Skip to content

Add progress updates for inbound A2A tasks - #47

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

Add progress updates for inbound A2A tasks#47
dimavrem22 merged 23 commits into
mainfrom
feat/a2a-worker-progress

Conversation

@dimavrem22

@dimavrem22 dimavrem22 commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Executive Summary

This PR makes long-running inbound A2A work visible without exposing worker internals or waking requester agents.

  • Adds immediate pickup acknowledgements plus periodic inbound A2A worker progress at a configurable 180-second default cadence.
  • Produces short nonterminal updates from bounded item identifiers in an isolated, tool-disabled Codex turn without retaining tool payloads.
  • Preserves authenticated caller input, delivery, cadence, and outcome ordering across retries, follow-ups, process restarts, cancellation, shutdown, and the separate tool process.

Description

Every created or message admission first verifies the exact authoritative task, context, active state, and latest caller-role message. The durable payload is rebuilt from the authoritative message parts and task caller metadata, so webhook-supplied caller IDs, organization IDs, handles, and text cannot reach the receipt, registry, or model turn. Inbound A2A dispatch then records acknowledgement and progress delivery in the durable task registry.

Progress runs as a child of the active worker turn, retries uncertain active delivery after five seconds, and stops when the task settles, requests input, or the gateway shuts down. Delivery is matched only against exact agent-role history; cadence and pending delivery remain anchored to the original durable start across process restarts and caller follow-ups. Restart catch-up validates every persisted nonfinal key against the authoritative exact task, context, active state, and latest caller-role message before acknowledgement, progress, or model work. It then enumerates both exact active states, deduplicates task IDs, and applies the same authoritative admission so work already advanced to working is not missed. A stale persisted generation is finalized without replay, while the current authoritative caller message is admitted once with canonical parts and caller metadata.

Codex item-start events expose only bounded normalized identifiers to a fresh read-only auxiliary turn. That turn disables tools and external capability sources; the normal worker turn keeps its existing tools. A task-scoped cross-process gate persists the current caller-message fence and ensures explicit and implicit outcomes drain in-flight progress before replying. Cancellation and shutdown close admission, signal progress runners, and drain active work before returning. Once closing starts, every A2A event—including cancellation and sent-task updates—receives a retryable 503 before it can mutate state or wake a session. Cancellation reconstructs missing message IDs, tombstones only that generation, and permits one distinct authoritative active caller follow-up.

Reason

Long-running delegated work otherwise appears idle after submission. A prompt receipt and occasional concise updates make worker activity visible without spending requester turns on informational events. Stale persisted work and spoofed webhook data must never select the caller identity, organization, text, or generation that Codex executes, and restart discovery must include work already in the working state.

Decisions

  • Default cadence: Use 180 seconds to reassure on long tasks without making ordinary tasks noisy.
  • Summary isolation: Use a fresh read-only, approval-free, tool-disabled Codex turn and one deterministic nonterminal fallback.
  • Admission authenticity: Durable writes, receipts, and model work require exact authoritative task, context, active state, and latest caller message; caller metadata and parts come only from the authoritative task.
  • Catch-up authenticity: Persisted active work resumes only when its key and context still equal the authoritative latest caller generation; stale entries finalize and the current generation is admitted once.
  • Recovery discovery: Query the exact submitted and working states, deduplicate by task ID, and pass every candidate through authoritative admission.
  • Delivery recovery: Persist pending progress before sending; only exact agent or ROLE_AGENT history confirms delivery, and uncertain active delivery retries after five seconds.
  • Cadence recovery: Keep the update phase anchored to the durable original start time and transfer pending state to caller follow-ups without regeneration.
  • Outcome ordering: Use a task-scoped process-safe gate and durable message owner so outcomes cannot race progress.
  • Cancellation recovery: Cancellation blocks only the canceled generation and drains admitted work; one distinct authoritative active caller message can resume.
  • Shutdown ordering: Shutdown closes all A2A event admission before awaiting admissions, delivery, progress runners, and worker jobs.
  • Requester behavior: Informational progress does not wake requester sessions; input-required and authentication-required states still do.

Testing

  • .venv/bin/python -m pytest -q — 527 passed, 23 skipped.
  • .venv/bin/python -m pytest -q tests/test_a2a_gateway.py — 45 passed.
  • python3.11 -m pytest -q tests/test_a2a_gateway.py — 45 passed.
  • ruff check inkbox_codex/gateway.py tests/test_a2a_gateway.py — passed.
  • .venv/bin/python -m compileall -q inkbox_codex — passed.
  • python3.11 -m pip wheel . --no-deps — passed.
  • git diff --check — passed.
  • Focused regressions verify working-state recovery after a stale persisted generation, task-ID deduplication across active-state discovery, and retryable post-close rejection of cancellation and sent-task updates without mutation or wake-up.
  • Live inbound progress expects prompt acknowledgement, ordered nonterminal updates at the CI 60-second cadence, and final worker output containing the unique token and 4 + 6 = 10.

@dimavrem22
dimavrem22 force-pushed the feat/a2a-worker-progress branch 3 times, most recently from b1dfa9b to a60ffae Compare August 15, 2026 04:12
@dimavrem22
dimavrem22 force-pushed the feat/a2a-worker-progress branch from a60ffae to ef062cd Compare August 15, 2026 04:45
@dimavrem22
dimavrem22 merged commit 6272085 into main Aug 16, 2026
16 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