Skip to content

fix(ai): keep OpenCode Ask AI subscribed before prompting - #1413

Open
danowicz wants to merge 3 commits into
backnotprop:mainfrom
danowicz:fix/opencode-ask-ai-sse
Open

fix(ai): keep OpenCode Ask AI subscribed before prompting#1413
danowicz wants to merge 3 commits into
backnotprop:mainfrom
danowicz:fix/opencode-ask-ai-sse

Conversation

@danowicz

@danowicz danowicz commented Aug 28, 2026

Copy link
Copy Markdown

Fixes the OpenCode half of #907 (source: #514). OpenCode Ask AI hung with Failed to fetch on 1.18.20: /api/ai/session succeeded, /api/ai/query returned SSE headers, then never emitted events.

Related: #513 (port conflict when attaching to an existing opencode serve).

The failure

OpenCodeSession.query subscribed to /event after promptAsync. A short turn can finish before that subscriber is live, so the query loop never sees idle and the browser times out.

Even when events arrive, 1.18 still streams message.part.delta for tokens but also lands a final message.part.updated text snapshot. The mapper treated snapshots as no-ops, so a late subscriber with no deltas rendered an empty bubble (#514).

The fix

Bun source of truth is packages/ai/providers/opencode-sdk.ts. Pi picks it up through vendor.sh (generated/ai/providers/opencode-sdk.ts); no hand-mirrored HTTP routes.

  • Subscribe first and wait for the first SSE frame before promptAsync. That frame is only a liveness check — leftover idle from a previous turn is not consumed as this query's result.
  • Drive the rest of the turn through consumeOpenCodeEvent (unit-tested). Idle after the prompt completes the query even if OpenCode never emitted busy.
  • If the turn never streamed text deltas, emit the last assistant text snapshot (parts with a time stamp) before the result. User-prompt snapshots have no time and are ignored, so the question is not echoed into the bubble.
  • Reasoning deltas stay ignored. Existing tool / permission mapping is unchanged.

Two-runtime note

Ask AI lives in @plannotator/ai. Both Bun (packages/server/ai-runtime.ts) and Pi (apps/pi-extension/server/ai-runtime.ts) load this provider. vendor.sh already copies opencode-sdk.ts; no Pi server edit.

Testing

  • bun test packages/ai/ai.test.ts: 121 pass. New cases cover snapshot-only idle (OpenCode AI tab: responses not rendering (empty bubbles) #514 empty bubble), no duplicate tokens when deltas already streamed, and ignoring the user-prompt snapshot.
  • bun run typecheck was not run in this checkout: tsc is not on PATH and the isolated install has no bun-types. CI test.yml should cover it.

Not done here: live Ask AI against a compiled plannotator binary. That still needs a release after merge. #907's anchored plan Q&A / thinking-vs-answer UI criteria are out of scope.

AI-assisted (Claude) under user direction.

Ask AI hung with Failed to fetch against OpenCode 1.18 because the
provider subscribed after promptAsync and ignored assistant text
snapshots when deltas were missed.
AGENTS.md requires each test to name the failure it guards.
Extract consumeOpenCodeEvent so the query loop can be unit-tested.
Ignore leftover idle from before promptAsync, skip user-prompt
snapshots that have no time stamp, and fall back to the assistant
text snapshot when deltas never arrive (backnotprop#514 / backnotprop#907).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant