Skip to content

contents_processor.go missing isConfirmationEvent filter breaks tool confirmation with persistent session stores #682

@odsod

Description

@odsod

🔴 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:

  1. Configure an agent with a tool that uses ctx.RequestConfirmation() (or RequireConfirmation: true)
  2. Use any persistent SessionService (database-backed, custom implementation, etc.)
  3. User sends a message that triggers the tool → confirmation event is stored in session
  4. User sends confirmation response (FunctionResponse with adk_request_confirmation)
  5. RequestConfirmationRequestProcessor re-executes the tool and yields the result
  6. ContentsRequestProcessor builds LLM history from session — includes adk_request_confirmation events
  7. 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:

How often has this issue occurred?:

Always (100%) — deterministic when using persistent sessions with tool confirmation.

Metadata

Metadata

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions