ag-ui-protocol / ag-ui-protocol/ag-ui

Add missing AG-UI features to A2AAgent bridge (shared state, HITL, Task/Artifact updates)

Đang mở
#762 2 bình luận 2 reaction 0 người được giao Xem trên GitHub
enhancement Integration
Ngôn ngữ chính
Python
Star
15.9k
Fork
1.4k
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
163

Mô tả

# Summary
Build out the A2A bridge so AG-UI can project artifacts/status/activity into shared state and activity events from A2A tasks/status updates, handle the AG-UI config/control lane for shared-state updates, and support input-required/interrupt flows while preserving existing text-only agent behavior.

# Status
Work is already underway even though the guidelines ask contributors to reach out before starting; these features are required for my own usage whether or not they merge upstream.

# Missing AG-UI <> A2A bridge features
_`integrations/a2a/typescript/`_
- Config/control lane: support structured AG-UI shared-state/config updates via a dedicated extension, replace the unused extension header, and keep conversational messaging unchanged.
- Task-aware reconnect/resubscribe: use task snapshots/historyLength, subscribe-only mode, and resume payloads without reopening closed runs.
- Shared-state/activity projection: emit task/status/context snapshots and deltas; project artifacts with default `/view/artifacts/` paths, append/lastChunk handling, and metadata-driven paths; include activity for surfaces and input requests.
- Input-required interrupts/resume: emit RUN_FINISHED outcome `interrupt` with pending interrupt state/activity; surface A2A `input_required` task states through the AG-UI Human in the Loop (HITL) experience so reviewers see the request context; resume via `a2a.input.response`, update activity/state, and clear pending interrupts when resolved.
- Context/config forwarding (no full transcript): send the current message plus opt-in system/developer/config cues and AG-UI tool results when needed; rely on A2A task history for the full log; preserve existing text-only agents unchanged.
- Metadata hygiene: avoid leaking threadId/runId to A2A; prefer contextId/taskId in payloads and metadata.

# Fix A2A Compliance
Currently the AG-UI `threadId` is used as the A2A `contextId` which is non-compliant with the A2A Protocol. The A2A `contextId` is meant to be generated by the A2A server when not supplied by the A2A client. The A2A client should never send a `contextId` that wasn't obtained by the A2A server.
- AG-UI gives every agent a threadId up front: if the caller supplies one it’s used;
otherwise the AbstractAgent constructor auto-generates a UUID and stores it on the
instance (sdks/typescript/packages/client/src/agent/agent.ts:50-66).
- Each run reuses that agent threadId untouched; it’s copied straight into RunAgentInput
(sdks/typescript/packages/client/src/agent/agent.ts:287-299).
- In the A2A bridge, that same threadId is forwarded as the A2A contextId when converting
history and when sending the message (integrations/a2a/typescript/src/agent.ts:126-142 and
integrations/a2a/typescript/src/utils.ts:190-238). There is no additional ID generation or
remapping inside the bridge.
- The bridge never reads a server-generated contextId from A2A responses, so AG-UI’s
threadId remains the source of truth; A2A events are just streamed back as AG-UI events
and don’t mutate it (integrations/a2a/typescript/src/agent.ts:163-188).

## Proposed Solution

Keep `threadId` optional and late-bind `threadId` to the first server `contextId` for A2A agents; no bridge cache; non-A2A agents unchanged.

- Event semantics:
- For deferred A2A agents, RUN_STARTED is delayed until contextId is received; after that, event order remains RUN_STARTED → snapshot/deltas/messages.
- Non-A2A agents: no change.
- Caller contract:
- ThreadId and contextId are the same for A2A agents after the first binding; callers just keep using threadId. No extra contextId parameter is required in the public API.

# Scope / Acceptance
- Add run options (send/stream, taskId) plus:
- `subscribe-only` to reconnect without sending a new message (fetch snapshot, then resubscribe).
- `resume` to send input responses to the existing task without reopening the prior run.
- Use A2A server task snapshots (`getTask`) plus resubscribe for reconnects (no new message send).
- Send the current payload with opt-in system/developer/config cues (no full transcript); use a dedicated config/control extension for AG-UI shared-state updates and gate the legacy extension header; rely on A2A task storage for full history.
- Project A2A messages/status/artifacts into AG-UI text/tool/activity and shared-state events (snapshots + deltas), with default artifact base paths and append/lastChunk semantics.
- Handle `input_required` by emitting `RUN_FINISHED` with outcome `interrupt`, keeping pending interrupts in shared state/activity, surfacing them via the AG-UI Human in the Loop (HITL) flow for context, and resuming via `a2a.input.response` without reviving closed runs.
- Keep metadata layering so threadId/runId stay internal; prefer contextId/taskId externally.

# Testing plan
Add or update unit, integration, and e2e coverage as needed; run `pnpm --filter @ag-ui/a2a test` (A2A agent/util e2e + integration Jest suites), `pnpm --filter @ag-ui/client test` (client agent/subscriber Jest suites), plus `pnpm lint` and `pnpm build`; follow `docs/testing-strategy.md`.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.