Skip to content

streaming: add MessageStreamReducer and MessageStore#32445

Merged
TirmanSidhu merged 1 commit into
TirmanSidhu/streaming-message-architecturefrom
run-plan/streaming-message-architecture/pr-3
May 28, 2026
Merged

streaming: add MessageStreamReducer and MessageStore#32445
TirmanSidhu merged 1 commit into
TirmanSidhu/streaming-message-architecturefrom
run-plan/streaming-message-architecture/pr-3

Conversation

@TirmanSidhu
Copy link
Copy Markdown
Contributor

Summary

  • Adds Swift types for new daemon events (message_open / block_open / block_close / message_close).
  • Extends existing event types with messageId / blockIndex / seq fields.
  • Adds MessageStore (keyed by messageId, blocks indexed by blockIndex).
  • Adds MessageStreamReducer with idempotent apply(event:).
  • Wires reducer to consume events from EventStreamClient — but UI does NOT render from MessageStore yet (PR 4 swaps the renderer).

Part of plan: streaming-message-architecture.md (PR 3 of 6)

@TirmanSidhu TirmanSidhu merged commit e6463a4 into TirmanSidhu/streaming-message-architecture May 28, 2026
@TirmanSidhu TirmanSidhu deleted the run-plan/streaming-message-architecture/pr-3 branch May 28, 2026 18:51
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88ea62e5f1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if snapshot.blocks[blockIndex] == nil {
snapshot.blocks[blockIndex] = BlockSnapshot(type: .toolUse, toolName: msg.toolName, toolUseId: msg.toolUseId)
}
snapshot.blocks[blockIndex]?.toolInputJson.append(msg.content)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace accumulated tool input instead of appending

When a tool streams multiple tool_input_delta events, this appends each event's content even though the daemon emits the full accumulated JSON (handleToolInputDelta sends event.accumulatedJson). For app/builder tools that produce several input updates, the new store will contain duplicated prefixes such as {"a"{"abc"..., so the PR 4 renderer would show/correlate a corrupted tool input preview. Store the latest msg.content (or append only a true delta) rather than appending the accumulated payload.

Useful? React with 👍 / 👎.

subscriptionTask?.cancel()
subscriptionTask = Task { [weak self] in
guard let self else { return }
let stream = self.eventStreamClient.subscribe()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Subscribe with the conversation filter

This new reducer subscribes to the global event stream without the broadcastFilter that the legacy chat loop uses, so every live ChatViewModel receives and stores all conversation-scoped message_open/delta events. In contexts with multiple chat view models (pop-outs/background conversations), messageStore will be contaminated with other conversations before the renderer flips to it; pass the same mutable conversation filter into the reducer subscription or otherwise check conversationId before applying.

Useful? React with 👍 / 👎.

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