ag-ui-protocol / ag-ui-protocol/ag-ui
bug(a2a): RunAgentInput.state is silently dropped — agent has no access to host context
- Linguagem predominante
- Python
- Estrelas
- 15.9k
- Forks
- 1.4k
- Merge médio
- 1d 17h
- PRs com merge (30d)
- 163
Descrição
# `RunAgentInput.state` is silently dropped by `@ag-ui/a2a`
**Package:** `@ag-ui/a2a@0.0.6`
**Fix available:** PR #1936
---
## Problem
`RunAgentInput` defines three fields that the AG-UI host uses to pass context into the agent run:
```typescript
interface RunAgentInput {
messages: Message[];
state?: Record; // ← host observational context
context?: ContextVariable[]; // ← semantic prompt items
tools?: Tool[]; // ← extra tools
forwardedProps?: unknown;
// ...
}
```
`A2AAgent.createSendParams()` currently constructs `MessageSendParams` with only `message` and `configuration`:
```typescript
// integrations/a2a/typescript/src/agent.ts — current
return {
message,
configuration,
// state, context, tools are never forwarded
} as MessageSendParams;
```
**`state`, `context`, and `tools` are silently dropped on every call.**
---
## Why `state` matters
`state` is the mechanism by which an AG-UI host tells the agent what is currently happening in the UI — which page the user is on, which item is selected, what filters are active. It is the input side of the `STATE_SNAPSHOT` / `STATE_DELTA` cycle that `useCoAgent` depends on.
Without it:
- The agent runs blind to the host application's context on every turn.
- `STATE_SNAPSHOT` / `STATE_DELTA` events emitted by the agent have no prior state to diff against on the first turn.
- Frameworks built on top of `@ag-ui/a2a` (CopilotKit, custom AG-UI servers) that use `useCoAgent` receive an agent that behaves as if the host UI doesn't exist.
A concrete example — a dashboard assistant whose `state` is:
```json
{
"host": { "route": "/analytics/funnel" },
"selectedMetric": { "id": "conversion_rate", "value": 0.032 }
}
```
…never receives this object. The agent cannot reference the metric, the route, or anything derived from them unless the user re-types it in the message.
---
## Root cause
`MessageSendParams` has an official extension point — `metadata?: { [k: string]: unknown }` — that is intentionally left open for use cases exactly like this. `createSendParams()` simply never uses it.
---
## Proposed fix (already implemented in PR #1936)
**Outbound (`agent.ts`):** forward `state` as `metadata["x-agui-state"]` when non-empty.
```typescript
return {
message,
configuration,
...(input.state &&
typeof input.state === "object" &&
Object.keys(input.state as Record).length > 0 && {
metadata: { "x-agui-state": input.state },
}),
} as MessageSendParams;
```
**Inbound (`utils.ts`):** recognise data parts of type `"agui-state-snapshot"` / `"agui-state-delta"` in `status-update.status.message.parts` and emit the corresponding `STATE_SNAPSHOT` / `STATE_DELTA` AG-UI events. Two exported constants avoid magic strings on both sides of the wire.
**Tests:** 5 new test cases covering outbound passthrough, empty-state omission, `STATE_SNAPSHOT` conversion, `STATE_DELTA` conversion, and malformed delta guard.
**Backward-compatible:** servers that ignore `metadata` see no change.
---
## Reproduction (minimal)
```typescript
import { A2AAgent } from "@ag-ui/a2a";
const agent = new A2AAgent({ a2aClient });
// Intercept to observe what actually reaches the A2A server
const orig = a2aClient.sendMessageStream.bind(a2aClient);
a2aClient.sendMessageStream = (params) => {
console.log("metadata:", params.metadata); // → undefined (should be { "x-agui-state": {...} })
return orig(params);
};
agent.run({
runId: "r1", threadId: "t1",
messages: [{ id: "m1", role: "user", content: "What is the current funnel performance?" }],
state: { selectedMetric: { id: "conversion_rate", value: 0.032 } },
tools: [], context: [], forwardedProps: {},
});
```
`params.metadata` is `undefined`. The `state` object never reaches the server.
---
## Related
- #1936 — fix PR (ready for review)
- `context` and `tools` fields from `RunAgentInput` are also dropped — not addressed in this issue/PR but worth tracking separately.
Guia de contribuição
Avaliação
Esta issue ainda não foi avaliada.