fix(web): interleave tool calls with text during SSE streaming#1064
Conversation
During SSE streaming, tool calls always appeared below all text because onText appended to the existing message even when it already had tool calls. The server-side persistence already segments at this boundary. Mirror that rule in the client's onText handler: when the last streaming message has tool calls, seal it and start a new message for incoming text. Fixes #1054 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughExtracted SSE text event handling from ChatInterface into a pure, testable reducer function ( Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 Comprehensive PR ReviewPR: #1064 — fix(web): interleave tool calls with text during SSE streaming SummaryMinimal, correct fix that adds one boundary guard in the Verdict: ✅
🟡 Medium Issues (Needs Decision — recommend: defer as issues)1. Silent
|
| Issue | Location | Note |
|---|---|---|
| Guard doesn't mark in-flight tool calls complete | ChatInterface.tsx:345-357 |
Theoretical only — SSE event ordering prevents it; onToolResult backward search covers it anyway; YAGNI/KISS apply — leave as-is |
Workflow-status guard + empty last.content corner case |
ChatInterface.tsx:325 |
Pre-existing inconsistency vs server-side; out of scope |
Workflow hydration .catch has no user feedback |
ChatInterface.tsx:254 |
Pre-existing; background non-blocking call; logging present |
✅ What's Good
- Exact server parity: Guard condition
(last.toolCalls?.length ?? 0) > 0directly mirrorspersistence.ts:72. Comment even cites the line number — auditable without digging through history. - Correct placement: New guard sits AFTER the workflow-status check, preserving existing boundary priority ordering.
- Correct
isStreamingtransitions: Closing previous message withisStreaming: falseand opening new one withisStreaming: trueis consistent with all other boundary cases. - Consistent message shape: New segment object (
id,role,content,timestamp,isStreaming,toolCalls: []) matches every other message-creation site in the handler. - Minimal diff: +16 lines, 0 deletions — the smallest change that fixes fix(web): tool calls not interleaved with text during streaming — always appear at bottom #1054.
- CLAUDE.md compliance: YAGNI ✅, KISS ✅, no silent fallbacks ✅, TypeScript strict ✅
📋 Suggested Follow-up Issues
| Issue Title | Priority |
|---|---|
"Add logging to SSE reconnect re-fetch .catch" |
P3 |
"Extract onText reducer to chat-message-reducer.ts and add unit tests" |
P3 |
Reviewed by Archon comprehensive-pr-review workflow
Full artifacts: ~/.archon/workspaces/coleam00/Archon/artifacts/runs/86df3adf4a7a4b1da70719ded519aeb3/review/
- Add console.error logging to silent .catch on SSE reconnect re-fetch (ChatInterface.tsx:~544) so production failures are visible in logs - Extract onText setMessages reducer to chat-message-reducer.ts as a pure function (applyOnText) with 14 unit tests covering all 6 segmentation rules including the new tool-call boundary (issue #1054) - Refactor ChatInterface.onText to delegate to applyOnText Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix Report: PR #1064Date: 2026-04-10T00:00:00Z SummaryAddressed all 2 MEDIUM findings from the consolidated review. No CRITICAL or HIGH findings existed. The 3 LOW findings were correctly left as-is per reviewer recommendations (YAGNI / pre-existing / out-of-scope). Fixes Applied
Tests AddedFile:
All 14 tests pass. The Docs UpdatedNone required. Skipped Findings
Blocked (Could Not Fix)None. Validation
|
…flowResultCard Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…1054 fix(web): interleave tool calls with text during SSE streaming
Summary
onTextinChatInterface.tsxwas missing a boundary check — when text arrived after a tool call, it appended to the same streaming message rather than starting a new segmentonTextthat mirrors the existing server-side rule inpersistence.ts(line 72): if the last streaming message already has tool calls, seal it and open a new streaming message for the incoming textChanges
packages/web/src/components/chat/ChatInterface.tsx: added tool-call boundary check inside theonTextSSE handler (~16 lines added, 0 removed)Validation
bun run type-check)bun run lint --max-warnings 0)bun run format:check)bun run test)Manual verification steps:
Fixes #1054
Summary by CodeRabbit
Refactor
Tests