Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions packages/server/src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { SessionV2 } from "@opencode-ai/core/session"
import { LocationServiceMap } from "@opencode-ai/core/location-layer"
import { PermissionSaved } from "@opencode-ai/core/permission/saved"
import { PtyTicket } from "@opencode-ai/core/pty/ticket"
import { SessionStore } from "@opencode-ai/core/session/store"
import { SessionProjector } from "@opencode-ai/core/session/projector"
import { EventV2 } from "@opencode-ai/core/event"
import { Database } from "@opencode-ai/core/database/database"
import { ProjectV2 } from "@opencode-ai/core/project"
import { Layer } from "effect"
import { layer as locationLayer } from "./groups/location"
import { sessionLocationLayer } from "./middleware/session-location"
Expand Down Expand Up @@ -48,8 +53,32 @@ export const handlers = Layer.mergeAll(
).pipe(
Layer.provide(sessionLocationLayer),
Layer.provide(locationLayer),
Layer.provide(SessionV2.defaultLayer),
Layer.provide(SessionExecutionLocal.defaultLayer),
// NOTE: intentionally NOT `SessionV2.defaultLayer`. That export bakes
// `SessionExecution.noopLayer` into its own dependency graph (see
// packages/core/src/session.ts), which permanently resolves the
// session's SessionExecution.Service requirement to a no-op before this
// layer is ever built. Providing `SessionExecutionLocal.defaultLayer`
// from out here (as this file used to, right below) cannot reach past
// that already-closed-over dependency: Effect's Layer.provide binds a
// layer's requirement at the point the layer itself is constructed, not
// at the point it's later merged in. The practical symptom was that
// POST /session/{id}/prompt admitted durably (200, admittedSeq set) but
// session.wake()/resume() were silently no-ops, so the agent loop never
// ran (cost/tokens stayed 0, no assistant message was ever produced).
// Compose the session layer here instead, swapping in the real local
// executor, mirroring the (correct) pattern already used by
// packages/core/src/public/opencode.ts's `SessionsLayer`.
Layer.provide(
SessionV2.layer.pipe(
Layer.provide(SessionExecutionLocal.defaultLayer),
Layer.provide(SessionStore.defaultLayer),
Layer.provide(SessionProjector.defaultLayer),
Layer.provide(EventV2.defaultLayer),
Layer.provide(Database.defaultLayer),
Layer.provide(ProjectV2.defaultLayer),
Layer.orDie,
),
),
Layer.provide(PermissionSaved.defaultLayer),
Layer.provide(PtyTicket.defaultLayer),
Layer.provide(LocationServiceMap.layer),
Expand Down
Loading