Describe the Bug:
In ADK Java code execution flows, if the model response that contains executable code also has usageMetadata, ADK emits an extra contentless usage-only event after the codeExecutionResult event. That extra event is considered final=true, so BaseLlmFlow stops the loop and does not call the LLM again with the code execution result.
This breaks the intended CodeAct/code-execution loop:
model emits code
→ ADK executes code
→ ADK emits codeExecutionResult
→ ADK should call model again for final answer
The root cause appears to be that CodeExecution.runPostProcessor clears the consumed model response content: llmResponseBuilder.content((Content) null) but not usageMetadata.
Steps to Reproduce:
- Create an
LlmAgent with a non-built-in BaseCodeExecutor.
- Use streaming/SSE mode with a model/provider that includes
usageMetadata on the final response.
- Prompt the agent to generate and run Python code, for example: "Generate Python code to print the first 10 Fibonacci numbers."
Expected Behavior:
After code execution, ADK should continue the same invocation and call the LLM again with the codeExecutionResult, producing a final natural-language answer.
Expected event shape:
[event] executableCode ...
[event] codeExecutionResult ... final=false
# next LLM call happens
[event] final natural-language answer ... final=true
Observed Behavior:
ADK emits an extra contentless usage-only event after the code execution result:
[event] executableCode ... final=true
[event] codeExecutionResult ... final=false
[event] content= usage=GenerateContentResponseUsageMetadata{...} final=true
Because BaseLlmFlow checks only the last event in the step, the usage-only event stops the loop. The LLM is not called again with the codeExecutionResult.
Environment Details:
- ADK Library Version (1.3.0):
- OS: macOS:
Model Information:
gemini-2.5-pro
Describe the Bug:
In ADK Java code execution flows, if the model response that contains executable code also has
usageMetadata, ADK emits an extra contentless usage-only event after thecodeExecutionResultevent. That extra event is consideredfinal=true, soBaseLlmFlowstops the loop and does not call the LLM again with the code execution result.This breaks the intended CodeAct/code-execution loop:
The root cause appears to be that
CodeExecution.runPostProcessorclears the consumed model response content: llmResponseBuilder.content((Content) null) but not usageMetadata.Steps to Reproduce:
LlmAgentwith a non-built-inBaseCodeExecutor.usageMetadataon the final response.Expected Behavior:
After code execution, ADK should continue the same invocation and call the LLM again with the
codeExecutionResult, producing a final natural-language answer.Expected event shape:
Observed Behavior:
ADK emits an extra contentless usage-only event after the code execution result:
Because
BaseLlmFlowchecks only the last event in the step, the usage-only event stops the loop. The LLM is not called again with thecodeExecutionResult.Environment Details:
Model Information:
gemini-2.5-pro