Skip to content

fix(anthropic): preserve all streaming content block types#1695

Open
Stephen Belanger (Qard) wants to merge 2 commits intomainfrom
fix/anthropic-streaming-new-content-types
Open

fix(anthropic): preserve all streaming content block types#1695
Stephen Belanger (Qard) wants to merge 2 commits intomainfrom
fix/anthropic-streaming-new-content-types

Conversation

@Qard
Copy link
Copy Markdown
Contributor

Summary

Fixes three related issues where the Anthropic streaming aggregation silently dropped content block types it didn't recognize:

Root cause

finalizeContentBlock() had a catch-all that deleted any block type that wasn't text or tool_use. Additionally, the content_block_delta handler only recognized text_delta and input_json_delta, so thinking_delta and citations_delta events were ignored.

Changes

  • Vendor types (anthropic.ts): Add thinking block type, citations? on text blocks, AnthropicCitation interface, and new delta union members (thinking_delta, citations_delta, signature_delta)
  • Stream accumulator: Replace flat string[] with structured { textDeltas, citations } per block
  • Delta handling: thinking_delta → accumulate to textDeltas; citations_delta → accumulate to citations; signature_delta → ignore
  • finalizeContentBlock(): Handle thinking blocks (join textDeltas into thinking field); merge citations onto finalized text blocks; default case now preserves unknown blocks as-is instead of deleting them
  • Output composition: Use structured { role, content } form when any text block has citations
  • Unit tests: Full coverage for thinking blocks, citations, server_tool_use, web_search_tool_result, unknown future types, and mixed content

Test plan

  • cd js && pnpm test — all 845 unit tests pass
  • pnpm run lint — no new errors
  • pnpm run formatting — no formatting issues

🤖 Generated with Claude Code

Stephen Belanger (Qard) and others added 2 commits March 27, 2026 22:32
, #1621)

- Extend `AnthropicOutputContentBlock` with `thinking` and `citations` variants
- Add `AnthropicCitation` interface to vendor types
- Add `thinking_delta`, `citations_delta`, and `signature_delta` to stream event delta union
- Replace flat `string[]` accumulator with structured `{ textDeltas, citations }` per block
- Handle `thinking_delta` events (accumulated like text)
- Handle `citations_delta` events (accumulated separately and merged into finalized text block)
- Make `finalizeContentBlock()` forward-compatible: unknown block types are now preserved
  as-is instead of being silently deleted, fixing `server_tool_use`, `web_search_tool_result`
  and any future Anthropic content block types
- Keep structured output when any text block carries citations
- Add unit tests for all new block types and mixed content scenarios

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TypeScript cannot narrow a discriminated union member when a catch-all
{ type: string } overlaps with specific literal types. Use runtime
'in' checks + casts to safely extract fields from known delta types
while still allowing unknown future delta types to fall through.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@lforst Luca Forstner (lforst) left a comment

Choose a reason for hiding this comment

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

I would honestly love some more e2e test coverage for this because we gain version coverage!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants