Summary
client.messages.parse() makes a full model inference call to the Anthropic API but produces zero Braintrust spans. This structured-output helper was added to the anthropic Python SDK in v0.87.0 (2026-03-31). The current version pinned as latest in this repo is anthropic==0.116.0.
messages.parse() is the Anthropic equivalent of OpenAI's chat.completions.parse(), which is instrumented in this repo. The gap creates an asymmetry: users who migrate to parse() for structured outputs lose all tracing visibility.
Braintrust docs status: not_found — The Anthropic integration docs do not mention messages.parse() or structured output tracing.
Root cause
The Messages (and AsyncMessages) proxy class in py/src/braintrust/integrations/anthropic/tracing.py explicitly defines only create(), stream(), and a batches property. The Wrapper.__getattr__ delegates all other attribute access to the underlying unwrapped anthropic.resources.messages.Messages object.
When a caller invokes client.messages.parse(...), Python finds no parse method on the proxy and falls through to the real, uninstrumented SDK method. No span is created.
Unlike create() with stream=True (which the Messages proxy intercepts), parse() is an entirely separate code path in the Anthropic SDK that does not call through the proxy's create().
What needs to be instrumented
| Method |
SDK class |
Already traced? |
client.messages.parse(model, messages, output_format, ...) |
Messages |
No |
await client.messages.parse(model, messages, output_format, ...) |
AsyncMessages |
No |
parse() returns a ParsedMessage[T] wrapping the raw Message response. A useful span should record:
- input:
messages, system, tools
- output: the parsed structured content
- metadata:
model, output_format type, provider: "anthropic"
- metrics: token counts (from the embedded
Message.usage), wall-clock latency
Precedent
OpenAI's chat.completions.parse() is already instrumented via _chat_completion_parse_wrapper (see py/src/braintrust/integrations/openai/tracing.py), as is responses.parse() via _responses_parse_wrapper. The same pattern can be applied here.
Upstream sources
Local repo files inspected
py/src/braintrust/integrations/anthropic/tracing.py — Messages class defines create() and stream() only; no parse() method; __getattr__ from Wrapper delegates all other access to the unwrapped object
py/src/braintrust/integrations/anthropic/_utils.py — Wrapper.__getattr__ confirmed as the delegation mechanism
py/src/braintrust/integrations/openai/tracing.py — _chat_completion_parse_wrapper and _responses_parse_wrapper as precedent for parse instrumentation
py/src/braintrust/integrations/openai/patchers.py — _cc_parse_sync, _cc_parse_async as precedent patcher pattern
py/src/braintrust/integrations/anthropic/integration.py — min_version = "0.48.0", latest resolves to anthropic==0.116.0
- Full repo grep for
messages.parse and def parse across py/src/braintrust/integrations/anthropic/ — zero matches
Summary
client.messages.parse()makes a full model inference call to the Anthropic API but produces zero Braintrust spans. This structured-output helper was added to theanthropicPython SDK in v0.87.0 (2026-03-31). The current version pinned aslatestin this repo isanthropic==0.116.0.messages.parse()is the Anthropic equivalent of OpenAI'schat.completions.parse(), which is instrumented in this repo. The gap creates an asymmetry: users who migrate toparse()for structured outputs lose all tracing visibility.Braintrust docs status:
not_found— The Anthropic integration docs do not mentionmessages.parse()or structured output tracing.Root cause
The
Messages(andAsyncMessages) proxy class inpy/src/braintrust/integrations/anthropic/tracing.pyexplicitly defines onlycreate(),stream(), and abatchesproperty. TheWrapper.__getattr__delegates all other attribute access to the underlying unwrappedanthropic.resources.messages.Messagesobject.When a caller invokes
client.messages.parse(...), Python finds noparsemethod on the proxy and falls through to the real, uninstrumented SDK method. No span is created.Unlike
create()withstream=True(which theMessagesproxy intercepts),parse()is an entirely separate code path in the Anthropic SDK that does not call through the proxy'screate().What needs to be instrumented
client.messages.parse(model, messages, output_format, ...)Messagesawait client.messages.parse(model, messages, output_format, ...)AsyncMessagesparse()returns aParsedMessage[T]wrapping the rawMessageresponse. A useful span should record:messages,system,toolsmodel,output_formattype,provider: "anthropic"Message.usage), wall-clock latencyPrecedent
OpenAI's
chat.completions.parse()is already instrumented via_chat_completion_parse_wrapper(seepy/src/braintrust/integrations/openai/tracing.py), as isresponses.parse()via_responses_parse_wrapper. The same pattern can be applied here.Upstream sources
Messages.parse()source:https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/resources/messages/messages.py
messages.parse()https://github.com/anthropics/anthropic-sdk-python/blob/main/CHANGELOG.md
Local repo files inspected
py/src/braintrust/integrations/anthropic/tracing.py—Messagesclass definescreate()andstream()only; noparse()method;__getattr__fromWrapperdelegates all other access to the unwrapped objectpy/src/braintrust/integrations/anthropic/_utils.py—Wrapper.__getattr__confirmed as the delegation mechanismpy/src/braintrust/integrations/openai/tracing.py—_chat_completion_parse_wrapperand_responses_parse_wrapperas precedent for parse instrumentationpy/src/braintrust/integrations/openai/patchers.py—_cc_parse_sync,_cc_parse_asyncas precedent patcher patternpy/src/braintrust/integrations/anthropic/integration.py—min_version = "0.48.0",latestresolves toanthropic==0.116.0messages.parseanddef parseacrosspy/src/braintrust/integrations/anthropic/— zero matches