fix(claude): handle all SDK stream messages; stop spurious work-log warning rows#4244
Merged
Conversation
The SDK stream emits this roster snapshot but its subtype is absent from
the typed union, so it fell through to the unknown-subtype warning path
and rendered as a spurious error row ('no displayable text content') in
client work logs. The task_* lifecycle events carry the authoritative
per-agent data; the typed background_tasks control request remains the
reconciliation source.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s guards Log-driven audit of real captured traffic (verification runs + wire probes) found api_retry storms rendering as 10 warning rows per 502 and several union subtypes falling into the unknown-subtype warning path. - api_retry → session.state.changed heartbeat (terminal error path already reports the real failure) - session_state_changed → authoritative session.state.changed mapping - notification → warning row only for high/immediate priority - model_refusal_fallback, local_command_output, plugin_install, commands_changed, memory_recall, elicitation_complete, prompt_suggestion → deliberately consumed, no spurious rows - default branches now narrow to never: a new SDK message type or subtype fails typecheck instead of silently warning at runtime; the runtime fallback still catches undeclared wire-only subtypes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Contributor
ApprovabilityVerdict: Approved This is a straightforward bug fix that handles SDK stream messages that were previously falling through to an unknown-subtype warning path, causing spurious error rows in client work logs. The scope is limited to message handling in ClaudeAdapter with comprehensive test coverage. You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/server/src/provider/Layers/ClaudeAdapter.test.ts`:
- Around line 1729-1779: Extend the test around the existing runtime message
emissions to cover the missing dispatch branches: task_updated, all remaining
silent subtypes, prompt_suggestion, high and immediate notifications, and
session_state_changed. Add focused table-driven assertions that verify silent
messages produce no warnings and the other messages produce their expected
runtime events, while preserving the existing api_retry heartbeat assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 29456e95-069d-480c-ac7f-4b98becbea79
📒 Files selected for processing (2)
apps/server/src/provider/Layers/ClaudeAdapter.test.tsapps/server/src/provider/Layers/ClaudeAdapter.ts
Table-driven emission of every silent subtype, task_updated, prompt_suggestion, high-priority notification (asserts exactly one warning row), and all three session_state_changed mappings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
macroscopeapp
Bot
dismissed
their stale review
July 22, 2026 02:40
Dismissing prior approval to re-evaluate 057a5c8
Assert (message satisfies never) and cast as separate statements, mirroring orchestration/decider.ts:778 — same compile-time guarantee, house style. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
macroscopeapp
Bot
dismissed
their stale review
July 22, 2026 02:50
Dismissing prior approval to re-evaluate 6a5718d
t3dotgg
added a commit
that referenced
this pull request
Jul 22, 2026
…4244 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Every Claude SDK stream message type is now explicitly handled in the ClaudeAdapter, with type-level exhaustiveness guards so future SDK additions fail typecheck instead of silently degrading.
Why now (split out of #4220)
Users on main see spurious error-toned rows in the work log today:
api_retrystorms: a 502 burst renders as ten orange "Claude system message 'api_retry'" rows (one per attempt). Now maps to asession.state.changedheartbeat (reason: api_retry:3/10); the terminal error path already reports the real failure once.background_tasks_changed: an undeclared-but-real wire subtype (absent from the SDK's typed union) that rendered as "Claude system message 'background_tasks_changed' (no displayable text content)". Now consumed silently.Found via a log-driven audit: censused every native SDK message in captured provider NDJSON logs from real sessions, cross-referenced against the SDK 0.3.170 union (33 message types / 24 system subtypes).
Changes
api_retry→ session heartbeat, not N warning rowssession_state_changed→ authoritativesession.state.changedmapping (idle/running/requires_action)notification→ warning row only forhigh/immediateprioritybackground_tasks_changed(undeclared),task_updated,model_refusal_fallback,local_command_output,plugin_install,commands_changed,memory_recall,elicitation_complete,prompt_suggestion→ deliberately consumed, no spurious rowsdefaultbranches now narrow tonever(message satisfies never): a new SDK message type or subtype is a typecheck failure at upgrade time; the runtime fallback still catches undeclared wire-only subtypesVerification
api_retry, asserts zero warning rows and the heartbeat eventtsgo --noEmitclean for apps/serverNote for #4220: that branch carries a richer
task_updatedmapping (agent status patches); this PR only stops it warning. #4220 will absorb this cleanly on rebase.🤖 Generated with Claude Code
Note
Medium Risk
Changes runtime event mapping for live Claude sessions (session state, warnings, retries); behavior is well-covered by tests but affects user-visible work logs during provider outages.
Overview
Stops false error-toned work-log rows by explicitly handling Claude SDK system and top-level messages that previously fell through to unknown-subtype warnings.
api_retrynow emits asession.state.changedheartbeat (reason: api_retry:n/m) instead of one warning per retry during 502 storms.session_state_changedmaps tosession.state.changed(running/waiting/ready).notificationonly surfaces asruntime.warningwhen priority ishighorimmediate.Wire-only or UX-internal traffic (
background_tasks_changed,task_updated,commands_changed,memory_recall,prompt_suggestion, and similar) is consumed silently. Routerdefaultbranches usemessage satisfies neverso new SDK union members fail typecheck at upgrade; undeclared wire subtypes still hit the runtime fallback.Adds an integration test that asserts a single high-priority notification warning, correct session-state mapping, and an
api_retryheartbeat.Reviewed by Cursor Bugbot for commit 6a5718d. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix Claude SDK stream handling to suppress spurious work-log warning rows
handleSystemMessagefor several SDK system subtypes (background_tasks_changed,task_updated,commands_changed,model_refusal_fallback,local_command_output,plugin_install,memory_recall,elicitation_complete) that previously generated spurious warning rows.session_state_changedmessages tosession.state.changedevents with normalized states (running,waiting,ready) and emits a heartbeatsession.state.changedforapi_retrymessages.notification-driven warnings tohighorimmediatepriority only; lower-priority notifications are silently consumed.prompt_suggestioninhandleSdkMessageso it no longer surfaces as an unknown-type warning.Macroscope summarized 6a5718d.
Summary by CodeRabbit
Bug Fixes
Tests