ag-ui-protocol / ag-ui-protocol/ag-ui
[Feature]: Restore A2UI surfaces from a MESSAGES_SNAPSHOT of durable tool results
- 主要言語
- Python
- スター
- 15.9k
- フォーク
- 1.4k
- 平均マージ
- 1日 17時間
- マージ済み PR(30日)
- 163
説明
### Pre-flight Checklist
- [x] I have searched existing issues and this hasn't been requested yet.
### Problem or Motivation
`A2UIMiddleware` paints surfaces as `ACTIVITY_SNAPSHOT` events while a run streams. Nothing durable records them: the backend stores the assistant tool call and the tool result, and `prepareRunAgentInput` strips activity from what the client sends back. When a client reconnects to a stored thread and the backend answers with a `MESSAGES_SNAPSHOT`, every A2UI surface is gone. The tool calls and results are there, but the middleware only ever produces activity from a live stream.
The same applies to a read-only load of a thread: a client wants to show the stored conversation, including its surfaces, without injecting tools, executing user actions or running recovery.
### Proposed Solution
A pure projector in `@ag-ui/a2ui-middleware` that rebuilds the `a2ui-surface` activity from the durable messages in a snapshot:
- `projectA2UIHistory(snapshot, config)` walks assistant tool calls and their tool results, and emits one activity per painted surface right after the assistant message that called for it. Multi-surface results become one activity per surface. A call without a result becomes a `building` card, an errored result a `failed` card, and the toolkit's recovery-exhausted envelope keeps its attempts.
- The surface is assembled with the catalog it was originally painted with. The middleware records the resolved catalog for that purpose: it forwards `toolResultMetadata` in `forwardedProps` when it injects the tool, so a backend that stores tool results can attach it, and live activity snapshots carry `A2UI_HISTORY_METADATA` with the owning tool call id. A result with no recorded catalog and no explicit `catalogId` argument fails closed with a failed card instead of guessing today's default.
- `A2UIMiddleware` applies the projector to every snapshot it forwards, and a `readOnly: true` option runs only the projection with nothing from the caller's input admitted.
- The projected snapshot declares `a2ui-surface` as its authoritative activity type so it never deletes activity that other producers still own on the client. That needs the client change proposed in #2707.
- The activity constants and `getOperationSurfaceId` move to a dependency free `./activity` module published as `@ag-ui/a2ui-middleware/activity`, so a browser renderer can share the contract without loading the Node-only streaming parser from the root entry.
### Alternatives Considered
- Persisting activity messages on the backend and sending them in the snapshot. This works only for backends that store AG-UI activity, and it duplicates the tool result the backend already stores.
- Replaying the recorded event stream instead of a snapshot. This keeps order but forces every reconnect through the full history and the middleware's live state machine.
- Assembling with the currently configured catalog. A surface restored with a different catalog than the one it was painted with renders wrong or not at all.
### Additional Context
I have a PR ready for this, stacked on the client change for #2707, and will open it once the issue is triaged. @ag-ui-protocol/copilotkit could you assign it to me?
コントリビューションガイド
評価
この issue はまだ評価されていません。