@assistant-ui/react-ag-ui 0.0.48 → 0.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agUiExtras.d.ts +1 -1
- package/dist/agUiExtras.d.ts.map +1 -1
- package/dist/agUiExtras.js +1 -1
- package/dist/agUiExtras.js.map +1 -1
- package/dist/hooks.d.ts +6 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +10 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts +3 -0
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js +78 -16
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +63 -1
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +6 -1
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +57 -1
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/event-parser.js +5 -2
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/mcp-tool-result.d.ts.map +1 -1
- package/dist/runtime/mcp-tool-result.js +6 -3
- package/dist/runtime/mcp-tool-result.js.map +1 -1
- package/dist/runtime/types.d.ts +3 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js +2 -1
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +5 -4
- package/src/agUiExtras.ts +1 -1
- package/src/hooks.ts +14 -0
- package/src/index.ts +1 -0
- package/src/runtime/AgUiThreadRuntimeCore.ts +132 -16
- package/src/runtime/adapter/conversions.ts +107 -1
- package/src/runtime/adapter/run-aggregator.ts +82 -0
- package/src/runtime/event-parser.ts +12 -5
- package/src/runtime/mcp-tool-result.ts +8 -6
- package/src/runtime/types.ts +3 -0
- package/src/useAgUiRuntime.ts +1 -0
|
@@ -8,6 +8,12 @@ import {
|
|
|
8
8
|
type ToolCallMessagePart,
|
|
9
9
|
type ToolModelContentPart,
|
|
10
10
|
} from "@assistant-ui/core";
|
|
11
|
+
import {
|
|
12
|
+
applyA2uiOperations,
|
|
13
|
+
convertSurfaceToUISpec,
|
|
14
|
+
type A2uiState,
|
|
15
|
+
type A2uiSurfaceState,
|
|
16
|
+
} from "@assistant-ui/react-generative-ui/a2ui";
|
|
11
17
|
import { readMcpAppResourceUri } from "../mcp-tool-result";
|
|
12
18
|
import type { AgUiEvent, AgUiInterrupt } from "../types";
|
|
13
19
|
import type { Logger } from "../logger";
|
|
@@ -37,6 +43,8 @@ type ToolCallState = {
|
|
|
37
43
|
|
|
38
44
|
export const MCP_APPS_ACTIVITY_TYPE = "mcp-apps";
|
|
39
45
|
|
|
46
|
+
export const A2UI_SURFACE_ACTIVITY_TYPE = "a2ui-surface";
|
|
47
|
+
|
|
40
48
|
export const isPlainObject = (
|
|
41
49
|
value: unknown,
|
|
42
50
|
): value is Record<string, unknown> =>
|
|
@@ -72,6 +80,8 @@ export class RunAggregator {
|
|
|
72
80
|
private activeReasoningKey: string | undefined;
|
|
73
81
|
private reasoningPartCounter = 0;
|
|
74
82
|
private readonly toolCalls = new Map<string, ToolCallState>();
|
|
83
|
+
private readonly a2uiBuckets = new Map<string, A2uiState>();
|
|
84
|
+
private readonly a2uiToolCallIds = new Set<string>();
|
|
75
85
|
private lastResolvedToolCallId: string | undefined;
|
|
76
86
|
private readonly partOrder: (
|
|
77
87
|
| { kind: "text"; key: string }
|
|
@@ -104,6 +114,8 @@ export class RunAggregator {
|
|
|
104
114
|
this.activeReasoningKey = undefined;
|
|
105
115
|
this.reasoningPartCounter = 0;
|
|
106
116
|
this.toolCalls.clear();
|
|
117
|
+
this.a2uiBuckets.clear();
|
|
118
|
+
this.a2uiToolCallIds.clear();
|
|
107
119
|
this.lastResolvedToolCallId = undefined;
|
|
108
120
|
this.partOrder.length = 0;
|
|
109
121
|
this.textPartCounter = 0;
|
|
@@ -250,6 +262,10 @@ export class RunAggregator {
|
|
|
250
262
|
break;
|
|
251
263
|
}
|
|
252
264
|
case "ACTIVITY_SNAPSHOT": {
|
|
265
|
+
if (event.activityType === A2UI_SURFACE_ACTIVITY_TYPE) {
|
|
266
|
+
this.handleA2uiActivitySnapshot(event);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
253
269
|
if (event.activityType !== MCP_APPS_ACTIVITY_TYPE) break;
|
|
254
270
|
const toolCallId = event.content.toolCallId;
|
|
255
271
|
const entry =
|
|
@@ -305,6 +321,72 @@ export class RunAggregator {
|
|
|
305
321
|
}
|
|
306
322
|
}
|
|
307
323
|
|
|
324
|
+
private handleA2uiActivitySnapshot(
|
|
325
|
+
event: Extract<AgUiEvent, { type: "ACTIVITY_SNAPSHOT" }>,
|
|
326
|
+
): void {
|
|
327
|
+
const operations = event.content["a2ui_operations"];
|
|
328
|
+
if (!Array.isArray(operations)) return;
|
|
329
|
+
|
|
330
|
+
const messageId = event.messageId ?? "a2ui:anonymous";
|
|
331
|
+
if (event.replace === false && this.a2uiBuckets.has(messageId)) return;
|
|
332
|
+
|
|
333
|
+
const { state, warnings } = applyA2uiOperations(new Map(), operations);
|
|
334
|
+
for (const warning of warnings) {
|
|
335
|
+
this.logger.debug("[agui] a2ui operation warning", warning);
|
|
336
|
+
}
|
|
337
|
+
this.a2uiBuckets.delete(messageId);
|
|
338
|
+
this.a2uiBuckets.set(messageId, state);
|
|
339
|
+
this.synthesizeA2uiToolCalls();
|
|
340
|
+
this.emit();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private synthesizeA2uiToolCalls(): void {
|
|
344
|
+
const surfaces = new Map<string, A2uiSurfaceState>();
|
|
345
|
+
|
|
346
|
+
for (const bucket of this.a2uiBuckets.values()) {
|
|
347
|
+
for (const [surfaceId, surface] of bucket) {
|
|
348
|
+
surfaces.set(surfaceId, surface);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const activeToolCallIds = new Set<string>();
|
|
353
|
+
for (const [surfaceId, surface] of surfaces) {
|
|
354
|
+
const toolCallId = `a2ui:${surfaceId}`;
|
|
355
|
+
const { spec, warnings } = convertSurfaceToUISpec(surface);
|
|
356
|
+
for (const warning of warnings) {
|
|
357
|
+
this.logger.debug("[agui] a2ui surface conversion warning", warning);
|
|
358
|
+
}
|
|
359
|
+
if (!spec) continue;
|
|
360
|
+
|
|
361
|
+
activeToolCallIds.add(toolCallId);
|
|
362
|
+
|
|
363
|
+
const entry: ToolCallState = {
|
|
364
|
+
toolCallId,
|
|
365
|
+
toolCallName: "present",
|
|
366
|
+
argsText: JSON.stringify(spec),
|
|
367
|
+
parsedArgs: spec,
|
|
368
|
+
result: {},
|
|
369
|
+
isError: undefined,
|
|
370
|
+
snapshotResultApplied: false,
|
|
371
|
+
};
|
|
372
|
+
if (!this.toolCalls.has(toolCallId)) {
|
|
373
|
+
this.partOrder.push({ kind: "tool-call", toolCallId });
|
|
374
|
+
}
|
|
375
|
+
this.toolCalls.set(toolCallId, entry);
|
|
376
|
+
this.a2uiToolCallIds.add(toolCallId);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
for (const toolCallId of this.a2uiToolCallIds) {
|
|
380
|
+
if (activeToolCallIds.has(toolCallId)) continue;
|
|
381
|
+
this.toolCalls.delete(toolCallId);
|
|
382
|
+
const partIndex = this.partOrder.findIndex(
|
|
383
|
+
(part) => part.kind === "tool-call" && part.toolCallId === toolCallId,
|
|
384
|
+
);
|
|
385
|
+
if (partIndex !== -1) this.partOrder.splice(partIndex, 1);
|
|
386
|
+
this.a2uiToolCallIds.delete(toolCallId);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
308
390
|
private reportServerMessageId(messageId: string | undefined): void {
|
|
309
391
|
if (this.serverMessageIdReported || !messageId) return;
|
|
310
392
|
this.serverMessageIdReported = true;
|
|
@@ -241,11 +241,18 @@ export const parseAgUiEvent = (
|
|
|
241
241
|
case "ACTIVITY_SNAPSHOT": {
|
|
242
242
|
const activityType = getString("activityType");
|
|
243
243
|
if (!activityType || !isPlainObject(payload.content)) return null;
|
|
244
|
-
return
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
return withOptional(
|
|
245
|
+
{
|
|
246
|
+
type: "ACTIVITY_SNAPSHOT" as const,
|
|
247
|
+
activityType,
|
|
248
|
+
content: payload.content,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
messageId: getString("messageId"),
|
|
252
|
+
replace:
|
|
253
|
+
typeof payload.replace === "boolean" ? payload.replace : undefined,
|
|
254
|
+
},
|
|
255
|
+
);
|
|
249
256
|
}
|
|
250
257
|
case "RAW":
|
|
251
258
|
return withOptional(
|
|
@@ -26,12 +26,14 @@ export const parseMcpToolCallResult = (
|
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
// one (agno-agi/agno#9087).
|
|
29
|
+
// The MCP Apps pointer on CallToolResult._meta: canonical nested `ui.resourceUri`
|
|
30
|
+
// per the Apps spec (2026-01-26), with the deprecated flat `"ui/resourceUri"` kept
|
|
31
|
+
// for legacy producers. Only ui:// URIs identify a widget.
|
|
33
32
|
export const readMcpAppResourceUri = (meta: unknown): string | undefined => {
|
|
34
33
|
if (!isRecord(meta)) return undefined;
|
|
35
|
-
const
|
|
36
|
-
|
|
34
|
+
const ui = meta["ui"];
|
|
35
|
+
const nested = isRecord(ui) ? ui["resourceUri"] : undefined;
|
|
36
|
+
if (typeof nested === "string" && isMcpAppUri(nested)) return nested;
|
|
37
|
+
const flat = meta["ui/resourceUri"];
|
|
38
|
+
return typeof flat === "string" && isMcpAppUri(flat) ? flat : undefined;
|
|
37
39
|
};
|
package/src/runtime/types.ts
CHANGED
|
@@ -100,6 +100,7 @@ export type AgUiResumeEntry = {
|
|
|
100
100
|
|
|
101
101
|
export type AgUiRuntimeExtras = {
|
|
102
102
|
interrupts: readonly AgUiInterrupt[];
|
|
103
|
+
sendA2uiAction: (action: Record<string, unknown>) => void;
|
|
103
104
|
submitInterruptResponses: (
|
|
104
105
|
responses: readonly AgUiResumeEntry[],
|
|
105
106
|
) => Promise<void>;
|
|
@@ -169,6 +170,8 @@ export type AgUiEvent =
|
|
|
169
170
|
type: "ACTIVITY_SNAPSHOT";
|
|
170
171
|
activityType: string;
|
|
171
172
|
content: Record<string, unknown>;
|
|
173
|
+
messageId?: string;
|
|
174
|
+
replace?: boolean;
|
|
172
175
|
}
|
|
173
176
|
| { type: "RAW"; event: any; source?: string }
|
|
174
177
|
| { type: "CUSTOM"; name: string; value: any }
|
package/src/useAgUiRuntime.ts
CHANGED
|
@@ -147,6 +147,7 @@ export function useAgUiRuntime(
|
|
|
147
147
|
extras: agUiExtras.provide({
|
|
148
148
|
interrupts:
|
|
149
149
|
core.getPendingInterrupts()?.interrupts ?? EMPTY_INTERRUPTS,
|
|
150
|
+
sendA2uiAction: (action) => core.sendA2uiAction(action),
|
|
150
151
|
submitInterruptResponses: (responses) =>
|
|
151
152
|
core.submitInterruptResponses(responses),
|
|
152
153
|
steerAway: (message, responses) => core.steerAway(message, responses),
|