Skip to content

Fix cross-conversation message interference in streaming event routing#73

Merged
olsonjeffery merged 3 commits into
mainfrom
task/16-multiple-conversations-in-diff
Jul 25, 2026
Merged

Fix cross-conversation message interference in streaming event routing#73
olsonjeffery merged 3 commits into
mainfrom
task/16-multiple-conversations-in-diff

Conversation

@olsonjeffery

Copy link
Copy Markdown
Owner

Problem

Two concurrent conversations (tasks) sharing one opencode serve process per user experience message interference. The SSE /event stream multiplexes events from all sessions onto a single connection, and the only filtering was per-event session_id checks — but many event types lacked a session_id field entirely.

Root cause: MessagePartUpdatedData had no session_id field. The server sends "sessionID":"ses_..." inside every event's properties object, but serde silently dropped it during deserialization. As a result, every TextChunk, ToolUse, ToolResult, Thinking, etc. from session A was forwarded to session B's provider and vice versa.

Changes

Phase 1-3: Event data struct fixes

  • Added session_id field to MessagePartUpdatedData and MessageUpdatedData in src/opencode_sdk/types.rs
  • Fixed AssistantMessage.path type from Option<String> to Option<serde_json::Value> to match the server's object format

Phase 4: New ProviderEvent variant

  • Added ProviderEvent::MessageUpdated variant in src/providers/types.rs to carry serialized MessageUpdated data through to the broadcast task

Phase 5: Session-based event filtering

  • Filtered Event::MessagePartUpdated, Event::QuestionAsked, and Event::MessageUpdated by session_id in map_sdk_event_to_provider_event()

Phase 6: Reader task lifecycle fix

  • Cancelled old reader task before spawning a new one in subscribe_and_spawn() to prevent stale reader tasks from processing duplicate events

Testing

  • 5 new unit tests covering session_id filtering scenarios
  • All 433 tests pass (0 failed, 1 pre-existing ignore)

Closes #16

- Add session_id to MessagePartUpdatedData (captures server's sessionID)
- Add session_id to MessageUpdatedData and fix path type (String -> Value)
- Add ProviderEvent::MessageUpdated variant for broadcast
- Filter MessagePartUpdated and QuestionAsked by session_id in mapper
- Map MessageUpdated with session_id check to ProviderEvent
- Cancel stale reader task before spawning new one in subscribe_and_spawn
- Add 6 new unit tests for session_id filtering and deserialization
- Update existing test fixtures with required session_id field
- Convert inconsistent if/else session_id checks to early-return pattern
- Replace nested if-else with match in SessionStatus handler
- Deduplicate ProviderEvent::Done pattern matching
- Remove intermediate variables (local_completed, proj_str, active_sessions_inner clones)
- Move completed_normally store inside the is_done block
@olsonjeffery
olsonjeffery force-pushed the task/16-multiple-conversations-in-diff branch from 8d5f377 to b850022 Compare July 24, 2026 23:55
@olsonjeffery
olsonjeffery merged commit 90eff61 into main Jul 25, 2026
3 checks passed
@olsonjeffery
olsonjeffery deleted the task/16-multiple-conversations-in-diff branch July 25, 2026 02:23
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