Description
When using an Anthropic/Claude model via ADK deployed on Vertex AI Agent Engine, resuming a session causes anthropic.BadRequestError. There are multiple related bugs in how session history is reconstructed for non-Gemini models.
Note: These bugs manifest specifically when accessed via Gemini Enterprise / AgentSpace console. The Vertex AI Agent Engine playground console and Python SDK work correctly.
Bug 1: preserve_function_call_ids strips tool IDs on session replay
Location: contents.py:47-53, functions.py:192-214
preserve_function_call_ids is hardcoded False for all non-Gemini models:
preserve_function_call_ids = (
isinstance(canonical_model, Gemini)
and canonical_model.use_interactions_api
)
This causes remove_client_function_call_id to run on every replayed content for Claude, stripping adk-* prefixed IDs to None. These adk-* IDs exist because:
- Vertex AI Claude streaming may return
ToolUseBlock with id = None
populate_client_function_call_id (functions.py:188) generates adk-<uuid> fallback
- On replay,
remove_client_function_call_id strips adk-* → None
part_to_message_block (anthropic_llm.py:117) converts None → "" → Anthropic rejects
Error: messages.1.content.1.tool_use.id: String should match pattern '^[a-zA-Z0-9_-]+$'
Fix: Extend preserve_function_call_ids to include AnthropicLlm:
preserve_function_call_ids = (
isinstance(canonical_model, AnthropicLlm)
or (isinstance(canonical_model, Gemini) and canonical_model.use_interactions_api)
)
Bug 2: Broken history reconstruction via Gemini Enterprise
Observed behavior: When Gemini Enterprise replays session history for a follow-up turn, the reconstructed llm_request.contents contains only assistant messages with tool_use blocks — the corresponding user messages with tool_result blocks are completely missing.
Correct structure (what Anthropic expects):
msg[0] user: "question"
msg[1] assistant: [text, tool_use, tool_use, tool_use]
msg[2] user: [tool_result, tool_result, tool_result]
msg[3] assistant: [text, tool_use, tool_use]
msg[4] user: [tool_result, tool_result]
msg[5] assistant: [text] ← final response
msg[6] user: "follow-up" ← new turn
Actual structure from Gemini Enterprise replay:
msg[0] user: "follow-up"
msg[1] assistant: [tool_use, tool_use, tool_use] ← IDs are None
msg[2] assistant: [tool_use, tool_use] ← IDs are None, no user msg between
The tool_result events and the original user/assistant text messages appear to be dropped or not included in the session replay via Gemini Enterprise. This may be a Gemini Enterprise-specific issue rather than an ADK issue.
Error: messages.1: tool_use ids were found without tool_result blocks immediately after
This bug is NOT fixable with a workaround — the tool_result data is simply not present in the replayed history.
Bug 3 (minor): part_to_message_block doesn't sanitize IDs
anthropic_llm.py:117 passes IDs raw without validating against Anthropic's ^[a-zA-Z0-9_-]+$ pattern. Should sanitize regardless of source.
Workaround
Using a before_model_callback that sanitizes invalid characters from tool_use IDs in llm_request.contents before the model call. This mitigates Bug 3 for the SDK and Agent Engine playground paths. Bugs 1 and 2 require framework-level fixes.
Current recommendation: Use the Vertex AI Agent Engine playground console (which works correctly) instead of Gemini Enterprise for session resumption with Claude models.
Environment
google-adk==1.27.2
- Model:
claude-opus-4-6 via Vertex AI
- Deployment: Vertex AI Agent Engine with
VertexAiSessionService
- Gemini Enterprise: broken on session resume
- Agent Engine playground: works correctly
- Python SDK: works correctly
Description
When using an Anthropic/Claude model via ADK deployed on Vertex AI Agent Engine, resuming a session causes
anthropic.BadRequestError. There are multiple related bugs in how session history is reconstructed for non-Gemini models.Note: These bugs manifest specifically when accessed via Gemini Enterprise / AgentSpace console. The Vertex AI Agent Engine playground console and Python SDK work correctly.
Bug 1:
preserve_function_call_idsstrips tool IDs on session replayLocation:
contents.py:47-53,functions.py:192-214preserve_function_call_idsis hardcodedFalsefor all non-Gemini models:This causes
remove_client_function_call_idto run on every replayed content for Claude, strippingadk-*prefixed IDs toNone. Theseadk-*IDs exist because:ToolUseBlockwithid = Nonepopulate_client_function_call_id(functions.py:188) generatesadk-<uuid>fallbackremove_client_function_call_idstripsadk-*→Nonepart_to_message_block(anthropic_llm.py:117) convertsNone→""→ Anthropic rejectsError:
messages.1.content.1.tool_use.id: String should match pattern '^[a-zA-Z0-9_-]+$'Fix: Extend
preserve_function_call_idsto includeAnthropicLlm:Bug 2: Broken history reconstruction via Gemini Enterprise
Observed behavior: When Gemini Enterprise replays session history for a follow-up turn, the reconstructed
llm_request.contentscontains only assistant messages withtool_useblocks — the correspondingusermessages withtool_resultblocks are completely missing.Correct structure (what Anthropic expects):
Actual structure from Gemini Enterprise replay:
The
tool_resultevents and the original user/assistant text messages appear to be dropped or not included in the session replay via Gemini Enterprise. This may be a Gemini Enterprise-specific issue rather than an ADK issue.Error:
messages.1: tool_use ids were found without tool_result blocks immediately afterThis bug is NOT fixable with a workaround — the tool_result data is simply not present in the replayed history.
Bug 3 (minor):
part_to_message_blockdoesn't sanitize IDsanthropic_llm.py:117passes IDs raw without validating against Anthropic's^[a-zA-Z0-9_-]+$pattern. Should sanitize regardless of source.Workaround
Using a
before_model_callbackthat sanitizes invalid characters from tool_use IDs inllm_request.contentsbefore the model call. This mitigates Bug 3 for the SDK and Agent Engine playground paths. Bugs 1 and 2 require framework-level fixes.Current recommendation: Use the Vertex AI Agent Engine playground console (which works correctly) instead of Gemini Enterprise for session resumption with Claude models.
Environment
google-adk==1.27.2claude-opus-4-6via Vertex AIVertexAiSessionService