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

bug(a2a): RunAgentInput.state is silently dropped — agent has no access to host context

Aberta
#1,938 0 comentários 2 reações 2 responsáveis Reivindicada por @contextablemark Ver no GitHub
bug Integration
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

Abrir o guia de contribuição

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.