Skip to content

fix(samples): make a2a human-in-the-loop sample resume after confirmation#6187

Open
vaibhav-patel wants to merge 1 commit into
google:mainfrom
vaibhav-patel:fix/5871-a2a-hitl-sample
Open

fix(samples): make a2a human-in-the-loop sample resume after confirmation#6187
vaibhav-patel wants to merge 1 commit into
google:mainfrom
vaibhav-patel:fix/5871-a2a-hitl-sample

Conversation

@vaibhav-patel

Copy link
Copy Markdown

Summary

Following the README for contributing/samples/a2a/a2a_human_in_loop, the task never completes after the manager approves a reimbursement — it only finishes if the user explicitly asks to "retry". Fixes #5871.

Root cause

The approval runs as a LongRunningFunctionTool (ask_for_approval) on the remote approval_agent, which is a sub-agent of the local root agent. When the user approves, the approval FunctionResponse must be routed back to the remote agent so it can resume the paused tool. Runner._find_agent_to_run only re-routes a function-response turn to the originating agent when the app is resumable, and ResumabilityConfig.is_resumable defaults to False. Under adk web the bare agent is wrapped in an App with no resumability config, so the approval was delivered to the root agent — which has no pending call — and nothing happened. "retry" only worked because it made the model transfer to the remote agent again, starting a brand-new task.

This is a sample-wiring issue; the framework resume path already works (see tests/unittests/a2a/integration/test_client_server.py).

Fix

  • Expose the sample as an App with ResumabilityConfig(is_resumable=True) (the same pattern as contributing/samples/hitl/human_tool_confirmation), so the approval is routed back to the remote approval_agent and the long-running tool resumes.
  • Fix stale paths in the README run commands (the sample lives under contributing/samples/a2a/) and document how to approve a pending request from the ADK Web UI (send a FunctionResponse via "Send another response", not a plain chat message).

Verification

Verified the routing mechanism deterministically with fake models (no live model needed):

  • Fix applied: the sample's app.resumability_config.is_resumable is True, app.root_agent intact.

  • Runner._find_agent_to_run routing — the exact decision the fix changes — driven with the session state the Web UI produces after approval (last event = the user's approval FunctionResponse for the long-running call previously emitted by approval_agent):

    App config approval routed to result
    is_resumable=True (this fix) approval_agent remote agent resumes its paused tool ✓
    is_resumable=False reimbursement_agent (root) root re-plans — the A2A human in the loop official sample not working #5871 bug
    bare agent, no App (upstream) reimbursement_agent (root) the A2A human in the loop official sample not working #5871 bug

    Confirmed identical in both a non-transferable LlmAgent sub-agent and a BaseAgent sub-agent (the sample's real shape — RemoteA2aAgent is a BaseAgent). 8/8 assertions passed.

  • Existing suites pass on the branch: a2a/integration/test_client_server.py (12), test_runners.py (69 — including test_find_agent_to_run_uses_function_response_when_resumable and ..._skips_function_response_when_not_resumable), plus the long-running-tool / resumability / apps suites — 122 passed, 1 skipped, 3 xfailed (the skip/xfail are pre-existing V2-resume markers, unrelated to this change).

Note: no Gemini key was available, so the full two-server live run wasn't exercised; the routing decision the fix relies on is verified at the Runner level and corroborated by the existing unit tests.

Fixes #5871.

…tion

The A2A human-in-the-loop sample never completed after the manager approved
a reimbursement: the approval ran as a long-running tool on the remote
approval_agent, but the root reimbursement_agent was exposed as a bare
agent. When the user sent the approval (a FunctionResponse for the pending
long-running call) the next turn was routed to the root agent instead of the
remote approval_agent, because Runner._find_agent_to_run only re-routes a
function-response turn back to the originating agent when the app is
resumable. Resumability is disabled by default, so the pending tool was never
resumed and the task only finished if the user explicitly asked to retry
(which made the model transfer to the remote agent again, starting a fresh
task).

Expose the sample as an App with ResumabilityConfig(is_resumable=True) so the
approval is delivered back to the remote approval_agent and the paused tool
resumes, matching the documented flow. Also fix the stale paths in the README
run commands (the sample lives under contributing/samples/a2a/) and document
how to approve a pending request from the ADK Web UI.

Fixes google#5871.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A2A human in the loop official sample not working

1 participant