-
Notifications
You must be signed in to change notification settings - Fork 618
contents_processor.go missing isConfirmationEvent filter breaks tool confirmation with persistent session stores #682
Description
🔴 Required Information
Describe the Bug:
buildContentsDefault in internal/llminternal/contents_processor.go filters adk_request_credential events from LLM history via isAuthEvent(), but has no equivalent filter for adk_request_confirmation events. When using a persistent session store (anything other than InMemorySessionService), confirmation events are replayed into the Gemini context on the next turn, causing a 400 error because Gemini sees FunctionCall/FunctionResponse parts for adk_request_confirmation — a function it never declared.
This is documented as a known limitation in docs/tools-custom/confirmation.md:
Known limitations:
- DatabaseSessionService is not supported by this feature.
- VertexAiSessionService is not supported by this feature.
The fix below removes this limitation.
Steps to Reproduce:
- Configure an agent with a tool that uses
ctx.RequestConfirmation()(orRequireConfirmation: true) - Use any persistent
SessionService(database-backed, custom implementation, etc.) - User sends a message that triggers the tool → confirmation event is stored in session
- User sends confirmation response (
FunctionResponsewithadk_request_confirmation) RequestConfirmationRequestProcessorre-executes the tool and yields the resultContentsRequestProcessorbuilds LLM history from session — includesadk_request_confirmationevents- Gemini returns 400:
"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn"
Expected Behavior:
adk_request_confirmation events should be filtered from LLM history, matching the existing isAuthEvent() pattern for adk_request_credential.
Observed Behavior:
Gemini 400 error on the confirmation response turn. Tool confirmation only works with InMemorySessionService.
Proposed Fix:
Add isConfirmationEvent() filter in buildContentsDefault, mirroring isAuthEvent():
// In buildContentsDefault, after isAuthEvent check:
if isConfirmationEvent(ev) {
continue
}
// New function:
const requestConfirmationFunctionCallName = "adk_request_confirmation"
func isConfirmationEvent(ev *session.Event) bool {
c := utils.Content(ev)
if c == nil {
return false
}
for _, p := range c.Parts {
if p.FunctionCall != nil && p.FunctionCall.Name == requestConfirmationFunctionCallName {
return true
}
if p.FunctionResponse != nil && p.FunctionResponse.Name == requestConfirmationFunctionCallName {
return true
}
}
return false
}Environment Details:
- ADK Library Version: v1.0.0
- OS: Linux
- Go Version: 1.26
Model Information:
- Gemini 2.5 Flash / Pro (any model — the issue is in event history construction, not model-specific)
🟡 Optional Information
Related Issues:
- Missing ThoughtSignature on adk_request_confirmation parts breaks execution #656 (ThoughtSignature missing on confirmation events — different bug, same flow)
- generateRequestConfirmationEvent creates events with missing ID #590, generateRequestConfirmationEvent creates events with empty ID, causing DB primary key violations #558 (confirmation event missing ID — different bug, same flow)
How often has this issue occurred?:
Always (100%) — deterministic when using persistent sessions with tool confirmation.