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.

Implementation:Anthropics Anthropic sdk python ParsedMessage Output

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

Overview

The ParsedMessage Output implementation provides the generic typed container classes that hold validated structured output from the Anthropic API. It consists of ParsedTextBlock, ParsedContentBlock, and ParsedMessage, which extend the standard API response types to carry deserialized Pydantic model instances. The companion parse_text() and parse_response() functions handle the actual JSON validation and container construction.

API Surface

ParsedMessage

from anthropic.types import ParsedMessage

Source: src/anthropic/types/parsed_message.py:L45-56

class ParsedMessage(Message, Generic[ResponseFormatT]):
    content: List[ParsedContentBlock[ResponseFormatT]]

    @property
    def parsed_output(self) -> Optional[ResponseFormatT]:
        for content in self.content:
            if content.type == "text" and content.parsed_output:
                return content.parsed_output
        return None

ParsedTextBlock

Source: src/anthropic/types/parsed_message.py:L25-28

class ParsedTextBlock(TextBlock, Generic[ResponseFormatT]):
    parsed_output: Optional[ResponseFormatT] = None

    __api_exclude__ = {"parsed_output"}

ParsedContentBlock

Source: src/anthropic/types/parsed_message.py:L32-42

ParsedContentBlock: TypeAlias = Annotated[
    Union[
        ParsedTextBlock[ResponseFormatT],
        ThinkingBlock,
        RedactedThinkingBlock,
        ToolUseBlock,
        ServerToolUseBlock,
        WebSearchToolResultBlock,
    ],
    PropertyInfo(discriminator="type"),
]

A discriminated union of content block types. The type field is used as the discriminator so that Pydantic can dispatch to the correct block class. Only ParsedTextBlock carries the generic type parameter; other block types are passed through unchanged.

Parsing Functions

parse_text

Source: src/anthropic/lib/_parse/_response.py:L16-20

def parse_text(text: str, output_format: ResponseFormatT | NotGiven) -> ResponseFormatT | None:
    if is_given(output_format):
        adapted_type: TypeAdapter[ResponseFormatT] = TypeAdapter(output_format)
        return adapted_type.validate_json(text)
    return None

This function performs the core JSON-to-Pydantic deserialization:

  1. Checks if output_format is actually given (not the sentinel NOT_GIVEN).
  2. Creates a TypeAdapter for the target type.
  3. Calls validate_json(text), which parses the JSON string and validates it against the Pydantic model in a single step.
  4. Returns the validated model instance, or None if no output format was specified.

parse_response

Source: src/anthropic/lib/_parse/_response.py:L49-72

def parse_response(
    *,
    output_format: ResponseFormatT | NotGiven,
    response: Message,
) -> ParsedMessage[ResponseFormatT]:
    content_list: list[ParsedContentBlock[ResponseFormatT]] = []
    for content in response.content:
        if content.type == "text":
            content_list.append(
                construct_type_unchecked(
                    type_=ParsedTextBlock[ResponseFormatT],
                    value={
                        **content.to_dict(),
                        "parsed_output": parse_text(content.text, output_format),
                    },
                )
            )
        else:
            content_list.append(content)

    return construct_type_unchecked(
        type_=ParsedMessage[ResponseFormatT],
        value={
            **response.to_dict(),
            "content": content_list,
        },
    )

This function transforms a standard Message into a ParsedMessage:

  1. Iterates through the message's content blocks.
  2. For each TextBlock, constructs a ParsedTextBlock with the original data plus the validated parsed_output.
  3. Non-text blocks (ThinkingBlock, ToolUseBlock, etc.) are passed through unchanged.
  4. Constructs the final ParsedMessage with the rebuilt content list.

Uses construct_type_unchecked() to build instances without re-running validation on the already-validated data, for performance.

Detailed Behavior

parsed_output Property Lookup

The ParsedMessage.parsed_output property performs a linear scan through self.content:

@property
def parsed_output(self) -> Optional[ResponseFormatT]:
    for content in self.content:
        if content.type == "text" and content.parsed_output:
            return content.parsed_output
    return None

It returns the parsed_output from the first text block that has a truthy value. This handles the common case where there is a single text content block. If no text block has a parsed output (e.g., the model only produced tool use blocks, or the JSON was invalid), it returns None.

__api_exclude__ on ParsedTextBlock

The __api_exclude__ = {"parsed_output"} class variable ensures that the parsed_output field is excluded from serialization when the block is converted back to a dict for API communication. This prevents the SDK's internal augmentation from leaking into wire-format data.

TYPE_CHECKING Guard on Content

The content field on ParsedMessage uses a TYPE_CHECKING guard:

class ParsedMessage(Message, Generic[ResponseFormatT]):
    if TYPE_CHECKING:
        content: List[ParsedContentBlock[ResponseFormatT]]
    else:
        content: List[ParsedContentBlock]

At runtime, Pydantic sees the non-generic ParsedContentBlock (since generic unions are not fully supported by Pydantic at runtime). At type-check time, IDEs and type checkers see the fully parameterized ParsedContentBlock[ResponseFormatT], providing correct type inference for parsed_output.

Usage Example

import anthropic
from pydantic import BaseModel

class MovieReview(BaseModel):
    title: str
    rating: float
    summary: str
    pros: list[str]
    cons: list[str]

client = anthropic.Anthropic()

message = client.messages.parse(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Review the movie Inception"}],
    output_format=MovieReview,
)

# Type-safe access to the parsed output
review = message.parsed_output  # Optional[MovieReview]
if review is not None:
    print(f"{review.title}: {review.rating}/10")
    print(f"Summary: {review.summary}")
    for pro in review.pros:
        print(f"  + {pro}")
    for con in review.cons:
        print(f"  - {con}")

# Raw text is still accessible
for block in message.content:
    if block.type == "text":
        print(f"Raw JSON: {block.text}")

Dependencies

  • pydantic (BaseModel, TypeAdapter, validate_json): For JSON deserialization and validation.
  • typing_extensions (TypeVar, Generic, Annotated): For generic type parameterization.
  • anthropic._models (construct_type_unchecked): For constructing Pydantic models without re-validation.
  • anthropic._utils (PropertyInfo): For discriminated union support.

Key Source Files

  • src/anthropic/types/parsed_message.py -- ParsedTextBlock (L25-28), ParsedContentBlock (L32-42), ParsedMessage (L45-56).
  • src/anthropic/lib/_parse/_response.py -- parse_text() (L16-20), parse_response() (L49-72).

Related Pages

Implements Principle

Page Connections

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