Skip to content

feat(agent-runtime): add normalizeContentBlocks for Anthropic SDK stream events#429

Merged
jerryliang64 merged 1 commit intomasterfrom
worktree-normalize-content-blocks
Apr 1, 2026
Merged

feat(agent-runtime): add normalizeContentBlocks for Anthropic SDK stream events#429
jerryliang64 merged 1 commit intomasterfrom
worktree-normalize-content-blocks

Conversation

@jerryliang64
Copy link
Copy Markdown
Contributor

@jerryliang64 jerryliang64 commented Apr 1, 2026

Summary

  • mergeContentBlocks now auto-normalizes raw Anthropic streaming event blocks before merging
  • New normalizeContentBlocks method converts SDK events (content_block_start, content_block_delta, content_block_stop, etc.) into standard content blocks
  • Upstream code (e.g. QueryService) can transparently pass through SDK events without manual format conversion, while the framework produces clean final messages

Normalization rules

Input (Anthropic stream event) Output (standard block)
content_block_start[tool_use] ToolUseContentBlock
content_block_delta[input_json_delta] TextContentBlock (merged into tool_use.input)
content_block_delta[text_delta] TextContentBlock
content_block_delta[thinking_delta] discarded
content_block_stop / message_stop / message_delta discarded
Standard blocks (text, tool_use, tool_result) kept as-is

Test plan

  • 8 unit tests for normalizeContentBlocks covering each event type
  • 1 end-to-end test for mergeContentBlocks with raw Anthropic SDK stream events
  • All 139 existing tests pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Enhanced streaming message event processing to normalize raw stream events into consistent content blocks, including improved handling of tool use, text, and other content types
  • Tests

    • Added comprehensive test coverage for message block normalization, including validation of tool use conversion, text delta handling, event filtering, and end-to-end stream processing

…DK stream events

mergeContentBlocks now auto-normalizes raw Anthropic streaming event blocks
(content_block_start, content_block_delta, content_block_stop, etc.) into
standard content blocks before merging. This allows upstream code to
transparently pass through SDK events without manual format conversion.

Normalization rules:
- content_block_start[tool_use] → ToolUseContentBlock
- content_block_delta[input_json_delta] → TextContentBlock (merged into tool_use.input)
- content_block_delta[text_delta] → TextContentBlock
- content_block_delta[thinking_delta] → discarded
- content_block_stop / message_stop / message_delta → discarded
- Standard blocks (text, tool_use, tool_result) → kept as-is

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

coderabbitai bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

Added a new static method normalizeContentBlocks to the MessageConverter class that converts raw Anthropic SDK streaming event blocks into standard MessageContentBlock items, handling tool use and text deltas while filtering non-final events. The mergeContentBlocks method now calls this normalization upfront. Comprehensive test coverage validates the new functionality and end-to-end processing.

Changes

Cohort / File(s) Summary
Content Block Normalization
core/agent-runtime/src/MessageConverter.ts
Added normalizeContentBlocks static method that converts raw SDK streaming event blocks (content_block_start, content_block_delta) into standard MessageContentBlock items; filters non-final events (thinking_delta, content_block_stop, message_stop, message_delta). Integrated into mergeContentBlocks for upstream preprocessing of raw streams.
Normalization Test Suite
core/agent-runtime/test/MessageConverter.test.ts
Added comprehensive test suite validating normalizeContentBlocks behavior: event-to-block conversions, filtering logic, empty delta handling, and end-to-end mergeContentBlocks processing of raw Anthropic SDK event streams with merged text, discarded thinking events, parsed tool inputs, and preserved tool results.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #428: Directly modifies core/agent-runtime/src/MessageConverter.ts's mergeContentBlocks and stream-accumulation logic, creating a direct functional dependency with the new normalizeContentBlocks integration.
  • PR #426: Modifies MessageConverter.ts to improve handling of tool use and tool result content block types, overlapping with the normalization logic for these block types.
  • PR #427: Touches the streaming message-to-contentBlocks conversion path, consuming the normalized blocks output for runtime SSE event emission.

Poem

🐰 Raw SDK events hop and scatter,
Normalized blocks are all that matter!
Tool use and text in perfect bloom,
Stop events swept from the room,
Streams flow clean through the converter's loom! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a normalizeContentBlocks method for handling Anthropic SDK streaming event blocks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-normalize-content-blocks

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a normalizeContentBlocks method to the MessageConverter class to handle raw SDK streaming events, such as those from Anthropic. The method converts events like content_block_start and content_block_delta into standard MessageContentBlock types while discarding non-essential events like thinking_delta and message_stop. Comprehensive tests were added to verify the normalization logic and its integration into the existing mergeContentBlocks workflow. Review feedback suggests simplifying redundant string assignments and conditional checks within the new method.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/agent-runtime/src/MessageConverter.ts`:
- Around line 121-126: The normalizeContentBlocks method currently types its
input as MessageContentBlock[] but actually accepts raw SDK event shapes; define
a new union type RawSdkStreamingEvent that lists the supported raw packet shapes
(e.g., content_block_start, content_block_delta with subtypes
input_json_delta/text_delta/thinking_delta, message_delta, message_stop), then
update the signatures of normalizeContentBlocks and mergeContentBlocks to accept
(blocks: (MessageContentBlock | RawSdkStreamingEvent)[]): MessageContentBlock[]
so callers can pass raw events without casting; ensure all internal
pattern-matching within normalizeContentBlocks and mergeContentBlocks uses the
new union type guards to discriminate event kinds.
- Around line 129-161: In MessageConverter.normalizeContentBlocks, add a branch
to detect and skip blocks where b.type === 'content_block_start' and
b.content_block?.type === ContentBlockType.Text so these streaming
"content_block_start[text]" events are discarded before falling through to the
generic result.push; update mergeContentBlocks-related tests to include a
streaming event sequence with content_block_start[text] to assert it is ignored
in the final normalized/merged message (reference symbols: MessageConverter,
normalizeContentBlocks, mergeContentBlocks, ContentBlockType.Text).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: d2f976de-2041-4627-973b-2611455c4033

📥 Commits

Reviewing files that changed from the base of the PR and between 4bb30a1 and eb8304b.

📒 Files selected for processing (2)
  • core/agent-runtime/src/MessageConverter.ts
  • core/agent-runtime/test/MessageConverter.test.ts

@jerryliang64 jerryliang64 merged commit d780fdb into master Apr 1, 2026
12 checks passed
@jerryliang64 jerryliang64 deleted the worktree-normalize-content-blocks branch April 1, 2026 17:23
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