Repository navigation
Conversation
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
The approach makes sense, but I could only partly verify it: a real narration block needs a Claude 5.5 response, and there are no provider credentials here. The ai tests (17/17), the type checks in packages/ai and packages/tui, and the existing session-rows/verbosity tests (41/41) pass. A throwaway test against reduceSessionRows showed a reasoning part with a narration-marked signature becomes a text row, and an ordinary one stays a collapsed reasoning group. Screenshots of a real session before and after would help, since I couldn't produce them.
Public API: unchanged. The only request change is a default display: "summarized" on Anthropic adaptive thinking that doesn't set its own display, for Claude 5.5+, Fable 5+ and Mythos 5.1+.
Concerns:
progressUpdate()throws on any reasoning signature that isn't valid base64. That error escapes fromreduceSessionRows, the livesession.reasoning.endedhandler andSessionPartView, so it can break the whole transcript (see the inline comment).- Progress updates are detected by decoding the signature's undocumented byte layout, and only in the TUI. The desktop app, web app and
runoutput would still hide these notes. It would hold up better if the Anthropic protocol inpackages/aimarked these parts (for example in the reasoning part's provider state), and the TUI only read that flag.
| export function progressUpdate(state: SessionMessageAssistantReasoning["state"]) { | ||
| const signature = state?.signature | ||
| if (typeof signature !== "string") return false | ||
| return atob(signature.slice(0, 64)).includes("B\tnarration") |
There was a problem hiding this comment.
atob throws InvalidCharacterError when the input isn't valid base64. That includes base64url, other characters, or whatever an Anthropic-compatible gateway or third-party provider puts in signature. This runs on every reasoning part with a string signature, inside reduceSessionRows, the live session.reasoning.ended handler and the SessionPartView render. One odd signature can therefore break the whole session view. I checked: reduceSessionRows with state: { signature: "not base64 -_ signature!" } throws.
This needs at least a try/catch that returns false. The "B\tnarration" byte match also depends on an undocumented signature layout. Anthropic's docs describe a beta display: "updates" mode for this case, where any thinking block that arrives with text is a progress update. Doing the detection in the Anthropic protocol (packages/ai), where the provider is known, and storing a flag on the part would avoid decoding provider signatures in the UI. It would also let the desktop app, web app and run output show these notes.
|
Fixed the crash in c797ff2: On moving detection into Still no before/after screenshot of a live Claude 5.5 session; only the unit-level checks above. |
There was a problem hiding this comment.
The new commit fixes the crash I raised: progressUpdate() now uses Buffer.from(…, "base64"), which ignores characters it doesn't recognise instead of throwing. The added session-rows test covers that case and the narration case. It passes, and the TUI type check passes. I still couldn't check this end to end, because a real progress-update block needs Anthropic traffic.
Public API: unchanged.
Still open from before: narration blocks are detected by decoding the signature in the TUI, not in packages/ai, so other clients won't show these notes.
c797ff2 to
c78170b
Compare
|
@kitlangton could you take a look when you get a chance? It's still mergeable and checks are green. It covers the direct Anthropic route (narration blocks written between tool calls). @drsmile1001's claude-agent route is separate and would need the signature kept in the stream converter. |
Issue for this PR
Closes #55298
Type of change
What does this PR do?
Claude models that write progress updates (Claude 5.5+, Fable 5+, Mythos 5.1+) send the notes they write for the user between tool calls as thinking blocks marked
narration. opencode loses them in two places, and this PR fixes both.Request (
packages/ai). Anthropic's default adaptive-thinking display isomitted, which also empties progress updates. For models that write progress updates,anthropic-messages.tsnow defaults adaptive thinking todisplay: "summarized". This follows https://platform.claude.com/docs/en/build-with-claude/thinking#progress-updates. It runs before the existing block-binding default and doesn't change:displaydisabledorbetween_toolsthinkingModel detection reuses
claudeVersionaswritesProgressUpdatesinclaude-model.ts.TUI. A progress update arrives as a reasoning part. The only thing marking it is the block type inside the signature.
progressUpdate()checks for that marker, andSessionPartViewrenders those parts withTextPartinstead ofReasoningPart. Inrows.ts, history treats them as text for grouping. The signature only arrives withsession.reasoning.ended, after the deltas have already grouped the part as thinking, so the live path rebuilds rows at that point.Summarized display isn't guaranteed to be verbatim. It's still the only way to get the note's text to the user, and an empty block shows nothing.
How did you verify your code works?
packages/ai:bun test test/provider/anthropic-thinking-binding.test.tspasses (17 tests). New cases cover which models get the display default, explicit adaptive thinking without a display, and that explicit settings are kept.bun typecheckpasses inpackages/aiandpackages/tui.packages/tui:bun testpasses 1494 tests and fails 9. The same 9 fail on unmodifieddev: dialog-shell-output timeouts, plugin-keymap and plugin-source.narrationsignature.Screenshots / recordings
None.
Checklist