Skip to content

fix(server): wire the real SessionExecution local layer, not the noop stub - #244

Merged
dzianisv merged 1 commit into
devfrom
fix/server-session-execution-noop-layer
Aug 12, 2026
Merged

dzianisv merged 1 commit into
devfrom
fix/server-session-execution-noop-layer

Conversation

@dzianisv

Copy link
Copy Markdown
Owner

Summary

  • Fixes the headless opencode serve HTTP API silently never executing admitted prompts: POST /session/{id}/prompt returns 200 with an admittedSeq, but the agent loop never runs (cost/tokens stay 0, no assistant message is ever produced).
  • Root cause: packages/server/src/handlers.ts provided SessionV2.defaultLayer, which bakes SessionExecution.noopLayer into its own internal Layer.provide chain (packages/core/src/session.ts). That permanently closes the session's SessionExecution.Service dependency over the noop at the point defaultLayer is built. The sibling Layer.provide(SessionExecutionLocal.defaultLayer) right below it in handlers.ts can never reach past that already-resolved dependency — Effect's Layer.provide binds a requirement when the layer itself is constructed, not when it's later merged into a different layer graph.
  • Fix: build the session layer here from the raw SessionV2.layer plus its concrete sub-layers, substituting SessionExecutionLocal.defaultLayer for the noop — mirroring the already-correct pattern in packages/core/src/public/opencode.ts's SessionsLayer, which never had this bug for the same reason (it wires SessionV2.layer, not defaultLayer).
  • Confirmed present in every published version I checked (1.17.9 through the current latest, 1.17.17, and dev HEAD) — not something an npm i @vibetechnologies/opencode@latest + restart fixes.
  • POST /session/{id}/wait still 503s ("Session wait is not available yet") — that's a separate, genuinely-unimplemented V2 API stub (packages/core/src/session.ts's wait: handler unconditionally throws OperationUnavailableError), not the thing blocking execution. Clients should poll GET /session/{id}/message instead until that's implemented.

Test plan

  • CI typecheck/build (github-hosted runners — could not run bun install locally, both machines I tested from were disk-constrained under 2GB free)
  • After merge + release: npm i -g @vibetechnologies/opencode@latest && systemctl --user restart opencode-serve.service on a server host, then create a session, POST /session/{id}/prompt, and poll GET /session/{id}/message until a real assistant message appears (previously stuck at cost=0, empty messages, forever)

🤖 Generated with Claude Code

… stub

The HTTP server's handler layer graph provided SessionV2.defaultLayer,
which internally bakes in SessionExecution.noopLayer as part of its own
Layer.provide chain (packages/core/src/session.ts). That closes over the
session's SessionExecution.Service dependency permanently at the point
defaultLayer itself is constructed. The sibling
`Layer.provide(SessionExecutionLocal.defaultLayer)` in handlers.ts could
never reach past that already-resolved dependency, since Effect's
Layer.provide binds a layer's requirement when the layer is built, not
when it's later merged into an unrelated layer graph.

Practical symptom: POST /session/{id}/prompt admitted durably (200,
admittedSeq set, a durable row written), but session.wake()/resume()
silently no-op'd, so the agent loop never actually ran. Sessions stayed
at cost=0, tokens=0, with no assistant message ever produced, and
POST /session/{id}/wait 503'd with "Session wait is not available yet"
(a separate, still-unimplemented V2 API stub, not the primary blocker).

Fix: compose the session layer here from the raw SessionV2.layer plus
its concrete sub-layers, substituting SessionExecutionLocal.defaultLayer
for the noop. This mirrors the already-correct pattern used by
packages/core/src/public/opencode.ts's SessionsLayer, which never had
this bug because it wires SessionV2.layer (not defaultLayer) with the
local executor directly.

Not run through bun install/typecheck locally — both the dev host that
surfaced this bug and this workstation are disk-constrained (<2GB free).
Relying on CI (github-hosted runners) to validate the build.
@github-actions

Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

Copy link
Copy Markdown

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown

The following comment was made by an LLM, it may be inaccurate:

@dzianisv

Copy link
Copy Markdown
Owner Author

CI note: `unit (linux)` shows 5 failing tests (DatabaseMigration > declared schema has no ungenerated migrations; public native OpenCode API > rejects missing/Location-disabled models; LocationServiceMap > isolates location state / installs public plugins). Confirmed these are pre-existing and unrelated to this change — the same 5 tests, by exact name, fail on a dev baseline push run (30279773055, 2026-07-27) that predates this PR by two weeks. None of them touch packages/server/src/handlers.ts or the session/execution layers this PR changes. Not blocking.

@dzianisv
dzianisv merged commit aab0f9d into dev Aug 12, 2026
9 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant