Goal: A blocking wait should return control the moment a task needs authentication, instead of polling until it times out.
User story: As a developer (or CI job) waiting on a task, when the agent pauses the task for authentication I want the CLI to stop and tell me so immediately, so that I can act — instead of the command hanging until --timeout and then reporting a misleading "timeout" error.
Priority: P1 · Area: CLI code · Type: bug
What happens today
The polling loop treats a task as "still running" whenever its state is neither terminal nor INPUT_REQUIRED. It does not account for AUTH_REQUIRED. So a task that pauses at AUTH_REQUIRED keeps getting polled until the request context / --timeout expires, and the CLI then surfaces a timeout error — the user is told the call timed out, not that the agent is waiting for authentication.
This affects the blocking wait that falls back to polling (the send --stream path when the agent does not support streaming).
Root cause (confirmed by code review)
In internal/polling/polling.go:
- Line 62 — loop condition:
for !prevState.Status.State.Terminal() && prevState.Status.State != a2a.TaskStateInputRequired {
a2a.TaskStateAuthRequired is missing, so the loop keeps polling on an auth-paused task.
- Line 82 — the same omission when deciding whether to yield the task:
if task.Status.State.Terminal() || task.Status.State == a2a.TaskStateInputRequired {
AUTH_REQUIRED is a real, non-terminal "interrupted" state — the SDK defines it as a2a.TaskStateAuthRequired (= "auth-required") and TaskState.Terminal() correctly returns false for it. So this is purely the CLI's stop condition, not SDK behavior.
Expected behavior
A wait must return promptly on both interrupted states — INPUT_REQUIRED and AUTH_REQUIRED — yielding the task so the caller sees the state and identifiers and can act.
Suggested fix (small)
- Line 62: add
&& prevState.Status.State != a2a.TaskStateAuthRequired.
- Line 82: add
|| task.Status.State == a2a.TaskStateAuthRequired.
- Add a table-driven test covering a task that transitions to
AUTH_REQUIRED (assert the wait returns the task, not a timeout).
Steps to reproduce
Requires an agent that moves a task to AUTH_REQUIRED and does not advertise streaming (so the poll fallback runs):
a2a send -a <agent-that-pauses-for-auth> --stream "<message>"
- Observe the command hang until
--timeout, then fail with a timeout error, instead of returning promptly with the AUTH_REQUIRED state.
Acceptance criteria
Environment
- CLI version:
a2a version v0.0.0-…1e29dfe94f95+dirty (main 1e29dfe)
- OS: Linux x86_64
Goal: A blocking wait should return control the moment a task needs authentication, instead of polling until it times out.
User story: As a developer (or CI job) waiting on a task, when the agent pauses the task for authentication I want the CLI to stop and tell me so immediately, so that I can act — instead of the command hanging until
--timeoutand then reporting a misleading "timeout" error.Priority: P1 · Area: CLI code · Type: bug
What happens today
The polling loop treats a task as "still running" whenever its state is neither terminal nor
INPUT_REQUIRED. It does not account forAUTH_REQUIRED. So a task that pauses atAUTH_REQUIREDkeeps getting polled until the request context /--timeoutexpires, and the CLI then surfaces a timeout error — the user is told the call timed out, not that the agent is waiting for authentication.This affects the blocking wait that falls back to polling (the
send --streampath when the agent does not support streaming).Root cause (confirmed by code review)
In
internal/polling/polling.go:a2a.TaskStateAuthRequiredis missing, so the loop keeps polling on an auth-paused task.AUTH_REQUIREDis a real, non-terminal "interrupted" state — the SDK defines it asa2a.TaskStateAuthRequired(= "auth-required") andTaskState.Terminal()correctly returnsfalsefor it. So this is purely the CLI's stop condition, not SDK behavior.Expected behavior
A wait must return promptly on both interrupted states —
INPUT_REQUIREDandAUTH_REQUIRED— yielding the task so the caller sees the state and identifiers and can act.Suggested fix (small)
&& prevState.Status.State != a2a.TaskStateAuthRequired.|| task.Status.State == a2a.TaskStateAuthRequired.AUTH_REQUIRED(assert the wait returns the task, not a timeout).Steps to reproduce
Requires an agent that moves a task to
AUTH_REQUIREDand does not advertise streaming (so the poll fallback runs):a2a send -a <agent-that-pauses-for-auth> --stream "<message>"--timeout, then fail with a timeout error, instead of returning promptly with theAUTH_REQUIREDstate.Acceptance criteria
AUTH_REQUIRED, reportingtaskId,contextId, and the state.INPUT_REQUIREDand on terminal states, unchanged.AUTH_REQUIREDcase returns the task rather than timing out.Environment
a2a version v0.0.0-…1e29dfe94f95+dirty(main1e29dfe)