🔴 Required Information
Describe the Bug:
AnthropicLlm (google/adk/models/anthropic_llm.py) never sets LlmResponse.model_version,
on either the streaming or non-streaming path. Every other first-party model wrapper populates
it from the underlying API response:
google_llm.py sets model_version=model from the Gemini response.
lite_llm.py sets model_version=response.model / model_version=part.model (this covers
Claude-via-LiteLLM too, so that path does not have this bug).
apigee_llm.py sets model_version=response.get('model').
AnthropicLlm has the same data available and does not read it:
- Non-streaming:
message_to_generate_content_response() (anthropic_llm.py:672) takes
message: anthropic_types.Message and builds the LlmResponse at line 686 without ever
touching message.model — the Anthropic SDK's Message object exposes the actual resolved
model id there.
- Streaming: the
message_start event handler (anthropic_llm.py:998) reads
event.message.usage for token accounting (lines 999-1002) but never reads
event.message.model, so the aggregated LlmResponse yielded at the end of the stream
(anthropic_llm.py:1112) also has no model_version.
This matters because Anthropic model aliases (e.g. claude-sonnet-5) resolve to a dated
snapshot server-side, and model_version is the mechanism ADK already uses elsewhere (event
telemetry, DatabaseSessionService-persisted Event rows, the gen_ai.response.model span
attribute in telemetry/tracing.py) to record which snapshot actually served a given response.
For the Anthropic direct-API path, all of that ends up null.
Steps to Reproduce:
- Install
google-adk (reproduced on 2.7.0, but present since the module's introduction).
- Configure an
LlmAgent with model=AnthropicLlm(model="claude-sonnet-5") (ANTHROPIC_API_KEY set).
- Run any turn, streaming or non-streaming, and inspect the yielded
LlmResponse(s) — or, if
using DatabaseSessionService/any other persisted SessionService, inspect the stored
Event row for that turn.
- Compare
LlmResponse.model_version against the same check with Gemini or LiteLlm(model="claude-...").
Expected Behavior:
LlmResponse.model_version is populated with the model id/snapshot Anthropic actually served
(message.model non-streaming, event.message.model streaming), matching the behavior of
google_llm.py, lite_llm.py, and apigee_llm.py.
Observed Behavior:
LlmResponse.model_version is always None for every response AnthropicLlm produces, on
both the streaming and non-streaming paths.
Environment Details:
- ADK Library Version (pip show google-adk): 2.7.0
- Desktop OS: macOS
- Python Version (python -V): 3.13.7
Model Information:
- Are you using LiteLLM: No — using
AnthropicLlm directly (AsyncAnthropic, keyed by ANTHROPIC_API_KEY), not the LiteLLM path.
- Which model is being used: claude-sonnet-5 (also reproduces on other Claude ids)
🟡 Optional Information
Regression:
Not a regression — model_version appears to have never been wired into AnthropicLlm since
the class was introduced.
Additional Context:
This looks like the same class of gap as #5394 ("AnthropicLlm never populates
LlmResponse.finish_reason"), which was part of a batch of AnthropicLlm parity issues
(#5392–#5397) filed against this file. That issue's linked PR (#5512) showed the finish_reason
line had originally been commented out with # TODO: Deal with these later, and although both
community PRs for it (#5441, #5512) were closed unmerged, the fix did land internally by 2.7.0
(anthropic_llm.py:1121 now sets finish_reason=to_google_genai_finish_reason(stop_reason)).
model_version doesn't appear to be tracked anywhere in that batch or elsewhere in the tracker —
filing this separately so it doesn't fall through the same gap.
Minimal Reproduction Code:
from google.adk.models.anthropic_llm import AnthropicLlm
from google.adk.models.llm_request import LlmRequest
from google.genai import types
llm = AnthropicLlm(model="claude-sonnet-5")
request = LlmRequest(
contents=[types.Content(role="user", parts=[types.Part.from_text(text="hi")])],
)
async def main():
async for response in llm.generate_content_async(request):
print("model_version:", response.model_version) # always None
import asyncio
asyncio.run(main())
How often has this issue occurred?:
🔴 Required Information
Describe the Bug:
AnthropicLlm(google/adk/models/anthropic_llm.py) never setsLlmResponse.model_version,on either the streaming or non-streaming path. Every other first-party model wrapper populates
it from the underlying API response:
google_llm.pysetsmodel_version=modelfrom the Gemini response.lite_llm.pysetsmodel_version=response.model/model_version=part.model(this coversClaude-via-LiteLLM too, so that path does not have this bug).
apigee_llm.pysetsmodel_version=response.get('model').AnthropicLlmhas the same data available and does not read it:message_to_generate_content_response()(anthropic_llm.py:672) takesmessage: anthropic_types.Messageand builds theLlmResponseat line 686 without evertouching
message.model— the Anthropic SDK'sMessageobject exposes the actual resolvedmodel id there.
message_startevent handler (anthropic_llm.py:998) readsevent.message.usagefor token accounting (lines 999-1002) but never readsevent.message.model, so the aggregatedLlmResponseyielded at the end of the stream(
anthropic_llm.py:1112) also has nomodel_version.This matters because Anthropic model aliases (e.g.
claude-sonnet-5) resolve to a datedsnapshot server-side, and
model_versionis the mechanism ADK already uses elsewhere (eventtelemetry,
DatabaseSessionService-persistedEventrows, thegen_ai.response.modelspanattribute in
telemetry/tracing.py) to record which snapshot actually served a given response.For the Anthropic direct-API path, all of that ends up null.
Steps to Reproduce:
google-adk(reproduced on 2.7.0, but present since the module's introduction).LlmAgentwithmodel=AnthropicLlm(model="claude-sonnet-5")(ANTHROPIC_API_KEYset).LlmResponse(s) — or, ifusing
DatabaseSessionService/any other persistedSessionService, inspect the storedEventrow for that turn.LlmResponse.model_versionagainst the same check withGeminiorLiteLlm(model="claude-...").Expected Behavior:
LlmResponse.model_versionis populated with the model id/snapshot Anthropic actually served(
message.modelnon-streaming,event.message.modelstreaming), matching the behavior ofgoogle_llm.py,lite_llm.py, andapigee_llm.py.Observed Behavior:
LlmResponse.model_versionis alwaysNonefor every responseAnthropicLlmproduces, onboth the streaming and non-streaming paths.
Environment Details:
Model Information:
AnthropicLlmdirectly (AsyncAnthropic, keyed byANTHROPIC_API_KEY), not the LiteLLM path.🟡 Optional Information
Regression:
Not a regression —
model_versionappears to have never been wired intoAnthropicLlmsincethe class was introduced.
Additional Context:
This looks like the same class of gap as #5394 ("AnthropicLlm never populates
LlmResponse.finish_reason"), which was part of a batch ofAnthropicLlmparity issues(#5392–#5397) filed against this file. That issue's linked PR (#5512) showed the
finish_reasonline had originally been commented out with
# TODO: Deal with these later, and although bothcommunity PRs for it (#5441, #5512) were closed unmerged, the fix did land internally by 2.7.0
(
anthropic_llm.py:1121now setsfinish_reason=to_google_genai_finish_reason(stop_reason)).model_versiondoesn't appear to be tracked anywhere in that batch or elsewhere in the tracker —filing this separately so it doesn't fall through the same gap.
Minimal Reproduction Code:
How often has this issue occurred?: