Skip to content

Bug: prompt_async stops publishing message.part.delta events on second call (conversation continuation) #27663

Closed as not planned

Description

@webster-yuan

Bug Description

When prompt_async is called a second time on the same session (conversation continuation / resume), message.part.delta events stop being published entirely. Only initial state sync events (message.updated, message.part.updated, session.updated) arrive, followed by nothing but heartbeats.

Steps to Reproduce

  1. Create a session and send the first prompt_async — observe message.part.delta events flowing normally on both /event and /global/event
  2. After the first prompt completes (session idle), send a second prompt_async on the same session
  3. Observe the SSE stream: only message.updated / message.part.updated / session.updated arrive, then only server.heartbeat — no message.part.delta ever

Environment

  • opencode version: v1.14.50
  • SSE endpoint tested: both /event (instance-level) and /global/event
  • Same behavior on both endpoints

What We have Ruled Out

  1. Not an SSE subscription layer issue: We switched to /global/event (which uses GlobalBus — simple EventEmitter, no Effect fibers). Same problem persists. This means Bus.publish() is never called for deltas during the second prompt.
  2. Not a content complexity issue: A simple task that completes in one turn works fine. A complex task that triggers multi-turn interaction (planning → questions → file writes) triggers the bug.
  3. Root cause is in the prompt execution pipeline, not in SSE/bus subscription — Bus.publish() itself calls both PubSub.publish() and GlobalBus.emit() (confirmed in bus/index.ts:87-108), so the event is simply never created for the second prompt.

Suspected Root Cause

The second prompt_async call on an existing session seems to execute the prompt in a different code path or Effect scope where updatePartDelta() / Bus.publish() is either skipped or uses a different bus instance.

Relevant code paths:

  • handlers/session.ts:270-286 — promptAsync uses Effect.forkIn(scope)
  • session/message-v2.ts — updatePartDelta() publishes deltas via Bus.publish()
  • bus/index.ts:87-108 — publish() calls both PubSub and GlobalBus

Real-World Impact

This breaks any conversation-continuation flow — when a user answers a question or confirms a permission, the subsequent agent work becomes invisible to SSE clients. Frontends relying on SSE for real-time streaming see the agent "stuck" with no progress updates after the first interaction.

Note

PR #26678 (switching /event from Bus.Service to GlobalBus) addresses a related but different issue — it fixes the SSE subscription closing prematurely. Even with that fix applied (by using /global/event directly), this second-prompt delta bug remains.

Activity

  1. webster-yuan commented on May 21, 2026

    @webster-yuan
    Author

    The logs are crystal clear:

    16:46:37.534 > Prompt sent asynchronously (second prompt)
    16:46:37.542 > message.updated ← Received
    16:46:37.544 > message.part.updated ← Received
    16:46:37.545 > session.updated ← Received
    ...followed only by heartbeats, with no further events...
    16:46:45.548 > No message.part.delta received within 8 seconds of the prompt — SSE stream interrupted.
    Conclusion: This is indeed the issue described in #27663; it remains unfixed in version 1.15.6.

    message.updated / message.part.updated / session.updated (SyncEvent types) were received successfully ✅ — indicating that the fix for #27966 is effective.
    message.part.delta (BusEvent type) was not received at all ❌ — this is precisely the bug described in #27663.

  2. webster-yuan commented on May 26, 2026

    @webster-yuan
    Author

    Here's a minimal reproduction using curl + SSE client:

    # Terminal 1: Start opencode in API mode
    opencode serve
    
    # Terminal 2: Connect SSE
    curl -N "http://localhost:4096/global/event"
    
    # Terminal 3: First prompt - works fine
    curl -X POST "http://localhost:4096/session" \
      -H "Content-Type: application/json" \
      -d '{"prompt": "Say hello in 3 words", "async": true}'
    
    # Wait for first prompt to complete...
    # Then send second prompt on same session:
    curl -X POST "http://localhost:4096/session/<session_id>/prompt" \
      -H "Content-Type: application/json" \
      -d '{"prompt": "Now say goodbye in 3 words", "async": true}'
    
    # Observe SSE: no message.part.delta events on second prompt

    The issue is reproducible with the simplest possible prompts - doesn't require tool calls or multi-turn complexity. Just two consecutive prompts on the same session.

  3. github-actions commented on Jul 25, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions