Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Principle:Anthropics Anthropic sdk python Real time Content Processing

From Leeroopedia
Knowledge Sources
Domains Streaming, LLM
Last Updated 2026-02-15 00:00 GMT

Overview

The Real-time Content Processing principle describes the event-driven accumulation and dispatch pattern at the heart of the Anthropic Python SDK's streaming implementation. As each Server-Sent Event (SSE) arrives from the API, two distinct operations occur: (1) the event's payload is accumulated into a running message snapshot, and (2) the raw wire-protocol event is dispatched as one or more typed domain events. This dual-phase processing gives callers both a current-state view of the message (via the snapshot) and a stream of granular events suitable for real-time UI rendering or progressive processing.

Core Concepts

Event-Driven Accumulation

The Anthropic streaming API sends content as a series of deltas -- small incremental updates rather than complete objects. For example, a long text response arrives as dozens of text_delta events, each containing a few words or characters. The accumulation pattern reconstructs the complete object from these deltas:

Delta 1: "Once "         -> Snapshot: "Once "
Delta 2: "upon "         -> Snapshot: "Once upon "
Delta 3: "a time"        -> Snapshot: "Once upon a time"
Delta 4: ", there was"   -> Snapshot: "Once upon a time, there was"

The accumulator maintains a single ParsedMessage object (the snapshot) that represents the full message as constructed so far. Each new SSE event mutates this snapshot in place. This means the snapshot is always current and can be inspected at any time during iteration.

Content Type Multiplexing

The Anthropic API streams multiple types of content through the same SSE connection:

  • Text content: Regular response text, accumulated by appending string deltas.
  • Tool use input: JSON arguments for tool calls, accumulated as partial JSON strings and parsed incrementally using the jiter library's partial_mode.
  • Thinking content: Internal reasoning text (when thinking/extended thinking is enabled), accumulated similarly to regular text.
  • Signatures: Cryptographic signatures for thinking blocks, set as a complete value on the final delta.
  • Citations: Source references, accumulated as a growing list.

Each content type follows the same accumulation principle (delta + snapshot = updated snapshot) but applies type-specific merge logic.

Partial JSON Parsing

Tool use input presents a unique challenge: the JSON arguments arrive as string fragments that are not valid JSON individually. The SDK uses jiter (a fast JSON parser written in Rust) with partial_mode=True to parse incomplete JSON strings:

Fragment 1: '{"locati'           -> Parsed: {"locati": null}  (best-effort)
Fragment 2: '{"location": "San'  -> Parsed: {"location": "San"}
Fragment 3: '{"location": "San Francisco, CA"}' -> Parsed: {"location": "San Francisco, CA"}

This allows callers to inspect partially-constructed tool arguments in real time, which is useful for progressive UI rendering of tool calls.

Typed Event Dispatch

After accumulation, the raw wire event is transformed into one or more typed domain events. This transformation serves two purposes:

  1. Convenience: Domain events like TextEvent carry both the delta and the snapshot, so callers do not need to maintain their own accumulation state.
  2. Semantic clarity: Instead of checking event.type == "content_block_delta" and event.delta.type == "text_delta", callers can simply check event.type == "text".

The dispatch is implemented as a mapping from wire event types to domain event constructors:

Wire Event Delta Type Domain Event Key Fields
content_block_delta text_delta TextEvent .text (delta string), .snapshot (accumulated text)
content_block_delta input_json_delta InputJsonEvent .partial_json (delta string), .snapshot (parsed object)
content_block_delta thinking_delta ThinkingEvent .thinking (delta string), .snapshot (accumulated thinking)
content_block_delta signature_delta SignatureEvent .signature (full signature)
content_block_delta citations_delta CitationEvent .citation (new citation), .snapshot (all citations)
message_stop n/a ParsedMessageStopEvent .message (final ParsedMessage snapshot)
content_block_stop n/a ParsedContentBlockStopEvent .content_block (completed block)

Delta + Snapshot Duality

A key design choice is that most domain events carry both the delta and the snapshot:

  • The delta is the incremental change from this event (e.g., the new text fragment).
  • The snapshot is the full accumulated value up to and including this delta.

This duality means callers can choose their processing model:

# Delta-oriented: process each piece as it arrives
for event in stream:
    if event.type == "text":
        sys.stdout.write(event.text)  # Write just the new text

# Snapshot-oriented: use the accumulated state
for event in stream:
    if event.type == "text":
        display.update(event.snapshot)  # Replace entire display with accumulated text

Structured Output Parsing

When an output_format type is specified (e.g., a Pydantic model), the accumulator triggers structured parsing at the content_block_stop event. At that point, the complete text of the block is parsed into the specified type and stored as content_block.parsed_output. This parsing is deferred to block completion because partial text cannot be reliably parsed as structured output.

Design Rationale

The separation of accumulation from dispatch follows the single responsibility principle:

  • accumulate_event() is concerned only with maintaining the snapshot -- a purely stateful operation.
  • build_events() is concerned only with producing typed events from raw events and the current snapshot -- a mostly stateless transformation.

This separation means that the snapshot logic can be tested independently from the event dispatch logic. It also enables the snapshot to be accessed independently of the event stream (via current_message_snapshot), which is useful for status displays or progress indicators.

The choice to yield both raw events and domain events from the same iterator provides maximum flexibility without requiring callers to set up multiple listeners or callbacks.

Related Pages

Implemented By

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment