Skip to content

fix(flows): terminate invocation at tool-level EUC#5638

Open
doughayden wants to merge 1 commit intogoogle:mainfrom
doughayden:fix/tool-level-auth-terminates-at-euc
Open

fix(flows): terminate invocation at tool-level EUC#5638
doughayden wants to merge 1 commit intogoogle:mainfrom
doughayden:fix/tool-level-auth-terminates-at-euc

Conversation

@doughayden
Copy link
Copy Markdown

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

This change adds invocation_context.end_invocation = True after the auth event yield in _postprocess_handle_function_calls_async, mirroring the existing termination signal in _resolve_toolset_auth. Tool-level auth now terminates symmetrically with toolset-level auth at the EUC, instead of continuing for one more LLM call.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Three existing tests in test_functions_request_euc.py had assertions tied to the trailing post-EUC LLM call:

  • test_function_request_euc: adds assert len(mock_model.requests) == 1 to anchor the new termination behavior.
  • test_function_get_auth_response: events[-3]events[-2] for the auth event lookup, since the auth event is now second-to-last.
  • test_function_get_auth_response_partial: same events[-3]events[-2] change, plus the two len(mock_model.requests) assertions drop by 1 (3 → 2 and 4 → 3).
$ pytest tests/unittests/flows/llm_flows/test_functions_request_euc.py
======================== 3 passed, 17 warnings in 1.31s ========================

$ pytest tests/unittests/
=============== 5695 passed, 2308 warnings in 122.89s (0:02:02) ================

Manual End-to-End (E2E) Tests:

A self-contained Runner-based reproduction is at https://github.com/doughayden/adk-issue-examples/tree/main/04-tool_level_auth_continuation. The agent definition (agent.py) wires up an OpenAPIToolset against a local OAuth2 test server. main.py constructs an InMemoryRunner, applies the workaround for #5327 (get_auth_config = lambda: None) at runtime to land on the tool-level auth path, and sends a tool-triggering prompt. The --apply-fix flag monkey-patches the proposed fix to demonstrate the resolution end-to-end.

Without the fix:

👤 User: What's the weather in San Francisco?
🌤️  Weather Assistant event stream:

    [function_call] get_weather by WeatherAssistant
    [auth_event] adk_request_credential by WeatherAssistant
    [function_response] get_weather by WeatherAssistant
    [post_euc_text] WeatherAssistant: "I'm sorry, I cannot retrieve the weather for San Francisco at the moment. It ..."

Event counts:
    function_calls: 1
    auth_events: 1
    function_responses: 1
    text_events: 1
    post_euc_text_events: 1

✅ Bug reproduced: 1 text event(s) after the EUC (agent loop continued past adk_request_credential).

With the fix:

👤 User: What's the weather in San Francisco?
🌤️  Weather Assistant event stream:

    [function_call] get_weather by WeatherAssistant
    [auth_event] adk_request_credential by WeatherAssistant
    [function_response] get_weather by WeatherAssistant

Event counts:
    function_calls: 1
    auth_events: 1
    function_responses: 1
    text_events: 0
    post_euc_text_events: 0

✅ Fix verified: no LLM events after the EUC.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

Alternative considered:

A reorder of the yields (yield auth_event last so last_event.is_final_response() returns True) would also fix the loop termination in a single iteration without needing the flag. I went with end_invocation = True to preserve the observable event order and to match the existing pattern in _resolve_toolset_auth. Happy to switch if maintainers prefer the reorder.

Related:

The same yield site at lines 1126-1130 also produces tool_confirmation_event for HITL with the same long_running_tool_ids shape and the same termination gap. This PR scopes to auth_event only. Happy to open a follow-up PR with the same fix for tool_confirmation_event if the team agrees with the approach here.

- Set end_invocation after auth event in postprocess
- Mirrors _resolve_toolset_auth's interrupt signal
- Tests assert single LLM call when auth requested
- events[-3] -> events[-2] in resume tests (tail trimmed)
@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tool-level auth continues invocation past the EUC event

2 participants