Skip to content

Add A2A worker progress updates - #63

Merged
dimavrem22 merged 20 commits into
mainfrom
feat/a2a-worker-progress
Aug 16, 2026
Merged

Add A2A worker progress updates#63
dimavrem22 merged 20 commits into
mainfrom
feat/a2a-worker-progress

Conversation

@dimavrem22

@dimavrem22 dimavrem22 commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Executive Summary

Adds durable, human-readable progress reporting for long-running inbound A2A worker tasks.

  • Acknowledges inbound A2A work immediately and publishes short nonterminal updates every three minutes by default.
  • Uses an isolated, tool-disabled side model with bounded task context, prior public progress, normalized identifiers, and one safe fallback.
  • Persists delivery and reply-intent state across retries, restarts, follow-ups, duplicate delivery, stopped states, cancellation, and shutdown.

Description

When an inbound A2A task is durably registered, the worker immediately sends a cadence-aware nonterminal receipt, then emits concise progress on a referenced timer that defaults to 180 seconds. Setting the interval to zero disables periodic generation and timers while retaining the immediate receipt and its retry path. Each summary runs in a separate tool-disabled session with bounded task context, the previous delivered update, and up to eight normalized host-lifecycle identifiers; arguments and results are excluded, and unsafe output falls back to one generic nonterminal sentence.

The durable registry journals acknowledgement and periodic delivery candidates independently, so overlapping retries cannot overwrite or clear each other. Each sender clears only its own exact candidate, legacy single-slot state migrates on access, and worker-role history reconciles accepted responses without duplication. Catch-up revalidates persisted candidates against the same authoritative admission contract before acknowledgement, progress, or model dispatch. A stale persisted generation cannot suppress the server-current caller message; the admitted generation is rewritten with authoritative caller metadata and parts. Remote discovery enumerates both submitted and working tasks with task-ID deduplication, then selects the latest caller-role message.

Every inbound task-created or task-message webhook, including an existing-key acknowledgement retry, is checked against the authoritative A2A task before registry writes, acknowledgement, or model dispatch. Admission requires an exact task ID and context ID, an active submitted or working state, and a webhook message key matching the latest caller-role message. Caller metadata and message parts are rebuilt from that authoritative caller message rather than accepted from the webhook. The in-process cancellation tombstone remains a concurrency fence, while authoritative admission also rejects delayed canceled generations after restart.

Before explicit complete, ask-caller, or fail intents—and before a collected plain completion—the worker persists an entry-level reply fence, then drains progress and acknowledgement work. An ambiguous response followed by restart cannot resume the fenced turn; only a genuine new caller message key acquires new work. Input-required and auth-required are authoritative stopped states alongside terminal states, preventing acknowledgement, progress, or replay in the post-reply crash window.

A stopped supervisor is replaced with a fenced task owner that retains the original cadence phase. Per-message admission serialization prevents simultaneous duplicate webhooks from both reading an absent registry entry and starting duplicate work. Task/context admission is serialized with cancellation, so cancellation cannot miss a worker admitted just after its run snapshot. Shutdown closes admission before draining locks, deliveries, supervisors, retries, and active worker turns. Informational updates remain visible in protocol history without waking the requester.

Reason

Long-running A2A work should remain visibly active to people and passive clients without spending a full requester-agent turn on every informational update. Delivery failures, spoofed or stale webhook data, ambiguous replies, restarts, simultaneous webhook delivery, stopped states, cancellation, and shutdown must not silently disable, duplicate, overwrite, misroute, or outlive the worker lifecycle.

Decisions

  • Runtime default: Three minutes balances useful visibility with auxiliary-model cost; zero explicitly disables periodic updates.
  • Live override: One minute keeps CI bounded while proving actual timer and delivery behavior.
  • Host-native context: Tool lifecycle hooks retain only bounded normalized identifiers; arguments and results are excluded.
  • No keyword taxonomy: The isolated auxiliary model infers plain-language activity from identifiers and bounded task context.
  • Fallback: Generation failure, terminal claims, and exact or space-equivalent identifier echoes use one generic nonterminal sentence.
  • Recovery: Acknowledgement and periodic candidates use independent durable slots, exact-owner clears, bounded acknowledgement backoff, immediate periodic retry, and worker-role reconciliation.
  • Authoritative admission: Every created/message webhook must match the active authoritative task, context, and latest caller message; persisted caller metadata and parts come only from that task.
  • Reply fence: Every terminal or input reply path persists a per-entry fence before network delivery; restart honors it until a new caller message arrives.
  • Stopped states: Input-required and auth-required stop sends and catch-up just like completed, failed, canceled, and rejected states.
  • Catch-up input: Persisted unfinished work must still match the active authoritative task, context, and latest caller message; only that canonical generation resumes, while submitted and working discovery is deduplicated by task ID.
  • Lifecycle ownership: Stopped supervisors are replaced without resetting cadence; old owners cannot delete replacements; cancellation and shutdown abort and await the exact active worker promises.
  • Admission lifecycle: Duplicate admission and task cancellation are serialized; shutdown closes admission before awaiting captured work.
  • Requester behavior: Informational progress stays in protocol history but does not wake the requester agent.

Testing

  • npm test — 45 files passed, 587 tests passed.
  • npm run typecheck — passed.
  • npm run build — passed.
  • npm test -- tests/inbound/session.test.ts — 143 tests passed.
  • npm test -- tests/a2a-registry.test.ts — 4 tests passed.
  • python3 -m pytest -q tests/live/test_mock_openai.py — 3 passed.
  • python3.11 -m pytest -q tests/live/test_a2a_helpers.py with the local SDK on PYTHONPATH — 3 passed.
  • python3.11 -m py_compile tests/live/a2a_driver.py tests/live/mock_openai.py — passed.
  • git diff --check — passed.
  • Deterministic A2A coverage includes receipt failure/retry/restart/concurrent duplicates, independent acknowledgement/progress overlap behind delivery barriers, explicit and plain reply fencing with ambiguous responses and restart, stopped-state crash recovery and stale webhook suppression, zero-cadence no-timer behavior, supervisor replacement before old-turn unwind, exact pending-progress recovery, authoritative caller-only catch-up, stale-A/current-working-B restart reconciliation, submitted/working discovery deduplication, canonical existing-key acknowledgement retry, authoritative created/message admission, cancellation/restart generation rejection, spoofed-payload replacement, simultaneous duplicate admission, cancellation/admission barriers, blocked admission shutdown, blocked terminal cancellation, abort-insensitive shutdown, and no registry writes after lifecycle completion.
  • Live A2A worker progress expects the receipt within 30 seconds with the one-minute cadence, at least two ordered nonterminal updates 50–90 seconds apart, at least one descriptive side-model summary, and a completed worker answer containing the unique token and 4 + 6 = 10.

@dimavrem22
dimavrem22 force-pushed the feat/a2a-worker-progress branch 5 times, most recently from cbed5b9 to 403e657 Compare August 15, 2026 04:39
@dimavrem22
dimavrem22 force-pushed the feat/a2a-worker-progress branch from 403e657 to 6302e0a Compare August 15, 2026 04:53
@dimavrem22
dimavrem22 merged commit c1eb8b0 into main Aug 16, 2026
17 checks passed
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.

1 participant