@assistant-ui/react-a2a 0.2.35 → 0.2.37
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/A2AClient.d.ts +45 -48
- package/dist/A2AClient.d.ts.map +1 -1
- package/dist/A2AClient.js +43 -7
- package/dist/A2AClient.js.map +1 -1
- package/dist/A2AThreadRuntimeCore.d.ts +100 -87
- package/dist/A2AThreadRuntimeCore.d.ts.map +1 -1
- package/dist/A2AThreadRuntimeCore.js +218 -20
- package/dist/A2AThreadRuntimeCore.js.map +1 -1
- package/dist/a2aExtras.d.ts +2 -5
- package/dist/a2aExtras.d.ts.map +1 -1
- package/dist/conversions.d.ts +26 -26
- package/dist/conversions.d.ts.map +1 -1
- package/dist/conversions.js +24 -2
- package/dist/conversions.js.map +1 -1
- package/dist/hooks.d.ts +3 -7
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/types.d.ts +276 -279
- package/dist/types.d.ts.map +1 -1
- package/dist/useA2ARuntime.d.ts +3 -6
- package/dist/useA2ARuntime.d.ts.map +1 -1
- package/dist/useA2ARuntime.js +8 -0
- package/dist/useA2ARuntime.js.map +1 -1
- package/package.json +12 -10
- package/src/A2AClient.test.ts +41 -0
- package/src/A2AClient.ts +50 -6
- package/src/A2AThreadRuntimeCore.test.ts +1134 -10
- package/src/A2AThreadRuntimeCore.ts +372 -21
- package/src/conversions.test.ts +116 -0
- package/src/conversions.ts +48 -1
- package/src/useA2ARuntime.test.tsx +336 -1
- package/src/useA2ARuntime.ts +14 -0
- package/src/useA2ARuntime.voice.test.tsx +370 -0
|
@@ -1,90 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A2AClient } from "./A2AClient.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
notifyUpdate: () => void;
|
|
1
|
+
import type { AppendMessage, AssistantRuntime, ExportedMessageRepository, ThreadHistoryAdapter, ThreadMessage, Unstable_RecordToolInteractionOptions } from "@assistant-ui/core";
|
|
2
|
+
import type { A2AClient } from "./A2AClient.js";
|
|
3
|
+
import type { A2AArtifact, A2AAgentCard, A2ASendMessageConfiguration, A2ATask } from "./types.js";
|
|
4
|
+
export type A2AThreadRuntimeCoreOptions = {
|
|
5
|
+
client: A2AClient;
|
|
6
|
+
contextId?: string | undefined;
|
|
7
|
+
configuration?: A2ASendMessageConfiguration | undefined;
|
|
8
|
+
onError?: ((error: Error) => void) | undefined;
|
|
9
|
+
onCancel?: (() => void) | undefined;
|
|
10
|
+
onArtifactComplete?: ((artifact: A2AArtifact) => void) | undefined;
|
|
11
|
+
history?: ThreadHistoryAdapter | undefined;
|
|
12
|
+
notifyUpdate: () => void;
|
|
14
13
|
};
|
|
15
|
-
declare class A2AThreadRuntimeCore {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
14
|
+
export declare class A2AThreadRuntimeCore {
|
|
15
|
+
private client;
|
|
16
|
+
private contextId;
|
|
17
|
+
private configuration;
|
|
18
|
+
private onError;
|
|
19
|
+
private onCancel;
|
|
20
|
+
private onArtifactComplete;
|
|
21
|
+
private history;
|
|
22
|
+
private readonly notifyUpdate;
|
|
23
|
+
private runtime;
|
|
24
|
+
private readonly session;
|
|
25
|
+
private isRunningFlag;
|
|
26
|
+
private abortController;
|
|
27
|
+
private runGeneration;
|
|
28
|
+
private pendingError;
|
|
29
|
+
private currentTask;
|
|
30
|
+
private currentArtifacts;
|
|
31
|
+
private a2uiState;
|
|
32
|
+
private readonly a2uiMessageIds;
|
|
33
|
+
private agentCardValue;
|
|
34
|
+
private readonly assistantHistoryParents;
|
|
35
|
+
private readonly recordedHistoryIds;
|
|
36
|
+
private readonly historyWrites;
|
|
37
|
+
private _isLoading;
|
|
38
|
+
private _loadPromise;
|
|
39
|
+
private _historyLoadGeneration;
|
|
40
|
+
private _loadRequested;
|
|
41
|
+
private _agentCardPromise;
|
|
42
|
+
private _agentCardRetryAfter;
|
|
43
|
+
private _agentCardRetryDelay;
|
|
44
|
+
private _agentCardDiscoveryFailed;
|
|
45
|
+
private lastOptionsContextId;
|
|
46
|
+
constructor(options: A2AThreadRuntimeCoreOptions);
|
|
47
|
+
updateOptions(options: Omit<A2AThreadRuntimeCoreOptions, "notifyUpdate">): void;
|
|
48
|
+
/** Thread-boundary reset: applyExternalMessages alone also serves branch
|
|
49
|
+
* switches, deletes, and cancel resyncs, which must keep the live context. */
|
|
50
|
+
resetContext(): void;
|
|
51
|
+
attachRuntime(runtime: AssistantRuntime): void;
|
|
52
|
+
detachRuntime(): void;
|
|
53
|
+
getRuntime(): AssistantRuntime | undefined;
|
|
54
|
+
getMessages(): readonly ThreadMessage[];
|
|
55
|
+
getMessageRepository(): ExportedMessageRepository;
|
|
56
|
+
recordToolInteraction({ messageId, toolCallId, interaction, }: Unstable_RecordToolInteractionOptions): Promise<void>;
|
|
57
|
+
getTask(): A2ATask | undefined;
|
|
58
|
+
getArtifacts(): readonly A2AArtifact[];
|
|
59
|
+
getAgentCard(): A2AAgentCard | undefined;
|
|
60
|
+
isRunning(): boolean;
|
|
61
|
+
get isLoading(): boolean;
|
|
62
|
+
private loadAgentCard;
|
|
63
|
+
private waitForAgentCard;
|
|
64
|
+
__internal_load(): Promise<void>;
|
|
65
|
+
append(message: AppendMessage): Promise<void>;
|
|
66
|
+
appendVoiceTranscript(message: ThreadMessage): void;
|
|
67
|
+
edit(message: AppendMessage): Promise<void>;
|
|
68
|
+
reload(parentId: string | null, _config?: {
|
|
69
|
+
runConfig?: Record<string, unknown>;
|
|
70
|
+
}): Promise<void>;
|
|
71
|
+
cancel(): Promise<void>;
|
|
72
|
+
private appendLinearChain;
|
|
73
|
+
private finalizeExternalApply;
|
|
74
|
+
applyExternalMessages(messages: readonly ThreadMessage[]): void;
|
|
75
|
+
private startRun;
|
|
76
|
+
private runStreaming;
|
|
77
|
+
private runSync;
|
|
78
|
+
private handleStreamEvent;
|
|
79
|
+
private handleStatusUpdate;
|
|
80
|
+
private handleArtifactUpdate;
|
|
81
|
+
private handleMessage;
|
|
82
|
+
private handleTaskSnapshot;
|
|
83
|
+
private insertAssistantPlaceholder;
|
|
84
|
+
private updateAssistantContent;
|
|
85
|
+
private applyA2uiMessage;
|
|
86
|
+
private applyA2uiParts;
|
|
87
|
+
private a2uiSurfaceParts;
|
|
88
|
+
private withA2uiSurfaces;
|
|
89
|
+
private withPreservedToolInteractions;
|
|
90
|
+
private rebuildAssistantA2uiSurfaces;
|
|
91
|
+
private updateAssistantArtifacts;
|
|
92
|
+
private updateAssistantStatus;
|
|
93
|
+
private getAssistantStatus;
|
|
94
|
+
private isPersistableAssistantStatus;
|
|
95
|
+
private setRunning;
|
|
96
|
+
private finishRun;
|
|
97
|
+
private recordHistoryEntry;
|
|
98
|
+
private markPendingAssistantHistory;
|
|
99
|
+
private persistAssistantHistory;
|
|
100
|
+
private appendHistoryItem;
|
|
101
|
+
private chainHistoryWrite;
|
|
87
102
|
}
|
|
88
|
-
//#endregion
|
|
89
|
-
export { A2AThreadRuntimeCore, A2AThreadRuntimeCoreOptions };
|
|
90
103
|
//# sourceMappingURL=A2AThreadRuntimeCore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"A2AThreadRuntimeCore.d.ts","
|
|
1
|
+
{"version":3,"file":"A2AThreadRuntimeCore.d.ts","sourceRoot":"","sources":["../src/A2AThreadRuntimeCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { a2aMessageToContent, isTerminalTaskState, taskStateToMessageStatus, threadMessageToA2AMessage } from "./conversions.js";
|
|
3
|
-
import { createMessageRepositorySession, invokeUserCallback } from "@assistant-ui/core/internal";
|
|
2
|
+
import { a2aMessageToContent, a2uiPartsToOperations, isTerminalTaskState, taskStateToMessageStatus, threadMessageToA2AMessage } from "./conversions.js";
|
|
3
|
+
import { appendToolInteraction, createMessageRepositorySession, invokeUserCallback } from "@assistant-ui/core/internal";
|
|
4
4
|
import { fromThreadMessageLike, generateId } from "@assistant-ui/core";
|
|
5
|
+
import { applyA2uiOperations, convertSurfaceToUISpec, surfaceToOperations } from "@assistant-ui/react-generative-ui/a2ui";
|
|
5
6
|
//#region src/A2AThreadRuntimeCore.ts
|
|
6
7
|
const INITIAL_AGENT_CARD_RETRY_DELAY_MS = 5e3;
|
|
7
8
|
const MAX_AGENT_CARD_RETRY_DELAY_MS = 3e5;
|
|
9
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
const storedArtifact = (artifact) => ({
|
|
11
|
+
...artifact,
|
|
12
|
+
parts: artifact.parts.map(({ raw: _raw, ...part }) => part)
|
|
13
|
+
});
|
|
8
14
|
const FALLBACK_USER_STATUS = {
|
|
9
15
|
type: "complete",
|
|
10
16
|
reason: "unknown"
|
|
@@ -31,14 +37,19 @@ var A2AThreadRuntimeCore = class {
|
|
|
31
37
|
session = createMessageRepositorySession();
|
|
32
38
|
isRunningFlag = false;
|
|
33
39
|
abortController = null;
|
|
40
|
+
runGeneration = 0;
|
|
34
41
|
pendingError = null;
|
|
35
42
|
currentTask;
|
|
36
43
|
currentArtifacts = [];
|
|
44
|
+
a2uiState = /* @__PURE__ */ new Map();
|
|
45
|
+
a2uiMessageIds = /* @__PURE__ */ new Set();
|
|
37
46
|
agentCardValue;
|
|
38
47
|
assistantHistoryParents = /* @__PURE__ */ new Map();
|
|
39
48
|
recordedHistoryIds = /* @__PURE__ */ new Set();
|
|
49
|
+
historyWrites = /* @__PURE__ */ new Map();
|
|
40
50
|
_isLoading = false;
|
|
41
51
|
_loadPromise;
|
|
52
|
+
_historyLoadGeneration = 0;
|
|
42
53
|
_loadRequested = false;
|
|
43
54
|
_agentCardPromise;
|
|
44
55
|
_agentCardRetryAfter = 0;
|
|
@@ -73,6 +84,8 @@ var A2AThreadRuntimeCore = class {
|
|
|
73
84
|
/** Thread-boundary reset: applyExternalMessages alone also serves branch
|
|
74
85
|
* switches, deletes, and cancel resyncs, which must keep the live context. */
|
|
75
86
|
resetContext() {
|
|
87
|
+
this._historyLoadGeneration++;
|
|
88
|
+
this._isLoading = false;
|
|
76
89
|
const controller = this.abortController;
|
|
77
90
|
this.contextId = this.lastOptionsContextId;
|
|
78
91
|
if (controller) {
|
|
@@ -99,6 +112,26 @@ var A2AThreadRuntimeCore = class {
|
|
|
99
112
|
getMessageRepository() {
|
|
100
113
|
return this.session.export();
|
|
101
114
|
}
|
|
115
|
+
async recordToolInteraction({ messageId, toolCallId, interaction }) {
|
|
116
|
+
const message = this.session.tryGetMessage(messageId)?.message;
|
|
117
|
+
if (!message) throw new Error("Tried to record a tool interaction on a non-existing message");
|
|
118
|
+
if (message.role !== "assistant") throw new Error("Tried to record a tool interaction on a non-assistant message");
|
|
119
|
+
const target = message.content.find((part) => part.type === "tool-call" && part.toolCallId === toolCallId);
|
|
120
|
+
if (!target || target.type !== "tool-call") throw new Error("Tried to record a tool interaction on a non-existing tool call");
|
|
121
|
+
if (this.session.updateMessage(messageId, (current) => {
|
|
122
|
+
if (current.role !== "assistant") return current;
|
|
123
|
+
return {
|
|
124
|
+
...current,
|
|
125
|
+
content: current.content.map((part) => part.type === "tool-call" && part.toolCallId === toolCallId ? {
|
|
126
|
+
...part,
|
|
127
|
+
unstable_interactions: appendToolInteraction(part.unstable_interactions, interaction)
|
|
128
|
+
} : part)
|
|
129
|
+
};
|
|
130
|
+
})) {
|
|
131
|
+
this.notifyUpdate();
|
|
132
|
+
this.persistAssistantHistory(messageId);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
102
135
|
getTask() {
|
|
103
136
|
return this.currentTask;
|
|
104
137
|
}
|
|
@@ -153,15 +186,19 @@ var A2AThreadRuntimeCore = class {
|
|
|
153
186
|
if (this._loadPromise) return this._loadPromise;
|
|
154
187
|
if (!this.history) return agentCardPromise;
|
|
155
188
|
this._isLoading = true;
|
|
189
|
+
const generation = this._historyLoadGeneration;
|
|
156
190
|
const historyPromise = this.history.load();
|
|
157
|
-
this._loadPromise =
|
|
191
|
+
this._loadPromise = historyPromise.then((repo) => {
|
|
192
|
+
if (generation !== this._historyLoadGeneration) return;
|
|
158
193
|
if (repo) {
|
|
159
194
|
this.session.applyExternalMessageRepository(repo);
|
|
160
195
|
this.finalizeExternalApply();
|
|
161
196
|
}
|
|
162
197
|
}).catch((error) => {
|
|
198
|
+
if (generation !== this._historyLoadGeneration) return;
|
|
163
199
|
invokeRuntimeCallback("onError", this.onError, error instanceof Error ? error : new Error(String(error)));
|
|
164
200
|
}).finally(() => {
|
|
201
|
+
if (generation !== this._historyLoadGeneration) return;
|
|
165
202
|
this._isLoading = false;
|
|
166
203
|
this.notifyUpdate();
|
|
167
204
|
});
|
|
@@ -179,6 +216,13 @@ var A2AThreadRuntimeCore = class {
|
|
|
179
216
|
if (!startRun) return;
|
|
180
217
|
await this.startRun(threadMessage);
|
|
181
218
|
}
|
|
219
|
+
appendVoiceTranscript(message) {
|
|
220
|
+
const parentId = this.session.headId;
|
|
221
|
+
this.session.addOrUpdateMessage(parentId, message);
|
|
222
|
+
this.session.switchToBranch(message.id);
|
|
223
|
+
this.notifyUpdate();
|
|
224
|
+
this.recordHistoryEntry(parentId, message);
|
|
225
|
+
}
|
|
182
226
|
async edit(message) {
|
|
183
227
|
await this.append(message);
|
|
184
228
|
}
|
|
@@ -191,10 +235,12 @@ var A2AThreadRuntimeCore = class {
|
|
|
191
235
|
}
|
|
192
236
|
async cancel() {
|
|
193
237
|
if (!this.abortController) return;
|
|
238
|
+
const task = this.currentTask;
|
|
239
|
+
const generation = this.runGeneration;
|
|
194
240
|
this.abortController.abort();
|
|
195
|
-
if (
|
|
196
|
-
const updated = await this.client.cancelTask(
|
|
197
|
-
this.currentTask = updated;
|
|
241
|
+
if (task?.id) try {
|
|
242
|
+
const updated = await this.client.cancelTask(task.id);
|
|
243
|
+
if (this.currentTask === task && this.runGeneration === generation) this.currentTask = updated;
|
|
198
244
|
} catch {}
|
|
199
245
|
}
|
|
200
246
|
appendLinearChain(messages) {
|
|
@@ -216,6 +262,8 @@ var A2AThreadRuntimeCore = class {
|
|
|
216
262
|
for (const { message } of this.getMessageRepository().messages) this.recordedHistoryIds.add(message.id);
|
|
217
263
|
this.currentTask = void 0;
|
|
218
264
|
this.currentArtifacts = [];
|
|
265
|
+
this.a2uiState = /* @__PURE__ */ new Map();
|
|
266
|
+
this.a2uiMessageIds.clear();
|
|
219
267
|
this.notifyUpdate();
|
|
220
268
|
}
|
|
221
269
|
applyExternalMessages(messages) {
|
|
@@ -246,6 +294,7 @@ var A2AThreadRuntimeCore = class {
|
|
|
246
294
|
this.finalizeExternalApply();
|
|
247
295
|
}
|
|
248
296
|
async startRun(userThreadMessage) {
|
|
297
|
+
this.runGeneration++;
|
|
249
298
|
if (this.abortController) {
|
|
250
299
|
this.abortController.abort();
|
|
251
300
|
this.abortController = null;
|
|
@@ -256,6 +305,8 @@ var A2AThreadRuntimeCore = class {
|
|
|
256
305
|
});
|
|
257
306
|
if (this.currentTask && isTerminalTaskState(this.currentTask.status.state)) this.currentTask = void 0;
|
|
258
307
|
this.currentArtifacts = [];
|
|
308
|
+
this.a2uiState = /* @__PURE__ */ new Map();
|
|
309
|
+
this.a2uiMessageIds.clear();
|
|
259
310
|
const assistantParentId = userThreadMessage.id;
|
|
260
311
|
const assistantId = this.insertAssistantPlaceholder(assistantParentId);
|
|
261
312
|
this.markPendingAssistantHistory(assistantId, assistantParentId);
|
|
@@ -332,7 +383,7 @@ var A2AThreadRuntimeCore = class {
|
|
|
332
383
|
this.handleStatusUpdate(assistantId, event.event);
|
|
333
384
|
break;
|
|
334
385
|
case "artifactUpdate":
|
|
335
|
-
this.handleArtifactUpdate(event.event);
|
|
386
|
+
this.handleArtifactUpdate(assistantId, event.event);
|
|
336
387
|
break;
|
|
337
388
|
case "message":
|
|
338
389
|
this.handleMessage(assistantId, event.message);
|
|
@@ -352,6 +403,7 @@ var A2AThreadRuntimeCore = class {
|
|
|
352
403
|
};
|
|
353
404
|
if (event.contextId) this.contextId = event.contextId;
|
|
354
405
|
if (event.status.message) {
|
|
406
|
+
this.applyA2uiMessage(event.status.message);
|
|
355
407
|
const content = a2aMessageToContent(event.status.message);
|
|
356
408
|
this.updateAssistantContent(assistantId, content);
|
|
357
409
|
}
|
|
@@ -359,7 +411,7 @@ var A2AThreadRuntimeCore = class {
|
|
|
359
411
|
this.updateAssistantStatus(assistantId, status);
|
|
360
412
|
this.notifyUpdate();
|
|
361
413
|
}
|
|
362
|
-
handleArtifactUpdate(event) {
|
|
414
|
+
handleArtifactUpdate(assistantId, event) {
|
|
363
415
|
const { append, lastChunk } = event;
|
|
364
416
|
const artifact = normalizeArtifact(event.artifact);
|
|
365
417
|
const existingIdx = this.currentArtifacts.findIndex((a) => a.artifactId === artifact.artifactId);
|
|
@@ -386,11 +438,15 @@ var A2AThreadRuntimeCore = class {
|
|
|
386
438
|
updated = artifact;
|
|
387
439
|
this.currentArtifacts = [...this.currentArtifacts, updated];
|
|
388
440
|
}
|
|
441
|
+
this.applyA2uiParts(artifact.parts);
|
|
442
|
+
this.updateAssistantArtifacts(assistantId);
|
|
443
|
+
this.rebuildAssistantA2uiSurfaces(assistantId);
|
|
389
444
|
if (lastChunk) invokeRuntimeCallback("onArtifactComplete", this.onArtifactComplete, updated);
|
|
390
445
|
this.notifyUpdate();
|
|
391
446
|
}
|
|
392
447
|
handleMessage(assistantId, message) {
|
|
393
448
|
if (message.role !== "agent") return;
|
|
449
|
+
this.applyA2uiMessage(message);
|
|
394
450
|
const content = a2aMessageToContent(message);
|
|
395
451
|
this.updateAssistantContent(assistantId, content);
|
|
396
452
|
this.notifyUpdate();
|
|
@@ -404,11 +460,21 @@ var A2AThreadRuntimeCore = class {
|
|
|
404
460
|
...history === void 0 ? {} : { history }
|
|
405
461
|
};
|
|
406
462
|
if (task.contextId) this.contextId = task.contextId;
|
|
407
|
-
|
|
463
|
+
const isCompleteSnapshot = history !== void 0 && artifacts !== void 0;
|
|
464
|
+
const artifactsToApply = isCompleteSnapshot ? artifacts : artifacts?.filter((artifact) => !this.currentArtifacts.some(({ artifactId }) => artifactId === artifact.artifactId));
|
|
465
|
+
if (isCompleteSnapshot) {
|
|
466
|
+
this.currentArtifacts = artifacts;
|
|
467
|
+
this.a2uiState = /* @__PURE__ */ new Map();
|
|
468
|
+
this.a2uiMessageIds.clear();
|
|
469
|
+
} else if (artifactsToApply) this.currentArtifacts = [...this.currentArtifacts, ...artifactsToApply];
|
|
470
|
+
for (const message of history ?? []) if (message.role === "agent") this.applyA2uiMessage(message, true);
|
|
471
|
+
for (const artifact of artifactsToApply ?? []) this.applyA2uiParts(artifact.parts);
|
|
472
|
+
if (task.status.message) this.applyA2uiMessage(task.status.message, true);
|
|
473
|
+
if (isCompleteSnapshot || artifactsToApply?.length) this.updateAssistantArtifacts(assistantId);
|
|
408
474
|
if (task.status.message) {
|
|
409
475
|
const content = a2aMessageToContent(task.status.message);
|
|
410
476
|
this.updateAssistantContent(assistantId, content);
|
|
411
|
-
}
|
|
477
|
+
} else this.rebuildAssistantA2uiSurfaces(assistantId);
|
|
412
478
|
const status = taskStateToMessageStatus(task.status.state);
|
|
413
479
|
this.updateAssistantStatus(assistantId, status);
|
|
414
480
|
this.notifyUpdate();
|
|
@@ -439,10 +505,86 @@ var A2AThreadRuntimeCore = class {
|
|
|
439
505
|
if (message.role !== "assistant") return message;
|
|
440
506
|
return {
|
|
441
507
|
...message,
|
|
442
|
-
content
|
|
508
|
+
content: this.withA2uiSurfaces(content, message.content)
|
|
443
509
|
};
|
|
444
510
|
});
|
|
445
511
|
}
|
|
512
|
+
applyA2uiMessage(message, replay = false) {
|
|
513
|
+
if (message.messageId) {
|
|
514
|
+
if (replay && this.a2uiMessageIds.has(message.messageId)) return;
|
|
515
|
+
this.a2uiMessageIds.add(message.messageId);
|
|
516
|
+
}
|
|
517
|
+
this.applyA2uiParts(message.parts);
|
|
518
|
+
}
|
|
519
|
+
applyA2uiParts(parts) {
|
|
520
|
+
const operations = a2uiPartsToOperations(parts);
|
|
521
|
+
if (operations.length === 0) return;
|
|
522
|
+
this.a2uiState = applyA2uiOperations(this.a2uiState, operations).state;
|
|
523
|
+
}
|
|
524
|
+
a2uiSurfaceParts() {
|
|
525
|
+
const parts = [];
|
|
526
|
+
for (const [surfaceId, surface] of this.a2uiState) {
|
|
527
|
+
const { spec } = convertSurfaceToUISpec(surface);
|
|
528
|
+
if (!spec) continue;
|
|
529
|
+
parts.push({
|
|
530
|
+
type: "tool-call",
|
|
531
|
+
toolCallId: `a2ui:${surfaceId}`,
|
|
532
|
+
toolName: "present",
|
|
533
|
+
args: spec,
|
|
534
|
+
argsText: JSON.stringify(spec),
|
|
535
|
+
result: {},
|
|
536
|
+
artifact: { a2ui: surfaceToOperations(surface) }
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
return parts;
|
|
540
|
+
}
|
|
541
|
+
withA2uiSurfaces(content, previousContent = content) {
|
|
542
|
+
const preserved = content.filter((part) => !(part.type === "tool-call" && part.toolCallId.startsWith("a2ui:")));
|
|
543
|
+
const interactionSource = [...previousContent, ...content];
|
|
544
|
+
return this.withPreservedToolInteractions(interactionSource, [...preserved, ...this.a2uiSurfaceParts()]);
|
|
545
|
+
}
|
|
546
|
+
withPreservedToolInteractions(previousContent, content) {
|
|
547
|
+
const interactions = /* @__PURE__ */ new Map();
|
|
548
|
+
for (const part of previousContent) if (part.type === "tool-call" && part.unstable_interactions !== void 0) interactions.set(part.toolCallId, part.unstable_interactions);
|
|
549
|
+
if (interactions.size === 0) return content;
|
|
550
|
+
return content.map((part) => {
|
|
551
|
+
if (part.type !== "tool-call" || part.unstable_interactions !== void 0) return part;
|
|
552
|
+
const unstable_interactions = interactions.get(part.toolCallId);
|
|
553
|
+
return unstable_interactions === void 0 ? part : {
|
|
554
|
+
...part,
|
|
555
|
+
unstable_interactions
|
|
556
|
+
};
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
rebuildAssistantA2uiSurfaces(messageId) {
|
|
560
|
+
if (this.session.updateMessage(messageId, (message) => {
|
|
561
|
+
if (message.role !== "assistant") return message;
|
|
562
|
+
return {
|
|
563
|
+
...message,
|
|
564
|
+
content: this.withA2uiSurfaces(message.content)
|
|
565
|
+
};
|
|
566
|
+
})) this.notifyUpdate();
|
|
567
|
+
}
|
|
568
|
+
updateAssistantArtifacts(messageId) {
|
|
569
|
+
if (this.session.updateMessage(messageId, (message) => {
|
|
570
|
+
if (message.role !== "assistant") return message;
|
|
571
|
+
const custom = message.metadata.custom;
|
|
572
|
+
const a2a = isRecord$1(custom.a2a) ? custom.a2a : {};
|
|
573
|
+
return {
|
|
574
|
+
...message,
|
|
575
|
+
metadata: {
|
|
576
|
+
...message.metadata,
|
|
577
|
+
custom: {
|
|
578
|
+
...custom,
|
|
579
|
+
a2a: {
|
|
580
|
+
...a2a,
|
|
581
|
+
artifacts: this.currentArtifacts.map(storedArtifact)
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
})) this.notifyUpdate();
|
|
587
|
+
}
|
|
446
588
|
updateAssistantStatus(messageId, status) {
|
|
447
589
|
if (this.session.updateMessage(messageId, (message) => {
|
|
448
590
|
if (message.role !== "assistant") return message;
|
|
@@ -452,7 +594,7 @@ var A2AThreadRuntimeCore = class {
|
|
|
452
594
|
};
|
|
453
595
|
})) {
|
|
454
596
|
this.notifyUpdate();
|
|
455
|
-
if (
|
|
597
|
+
if (this.isPersistableAssistantStatus(status)) this.persistAssistantHistory(messageId);
|
|
456
598
|
}
|
|
457
599
|
}
|
|
458
600
|
getAssistantStatus(messageId) {
|
|
@@ -460,6 +602,9 @@ var A2AThreadRuntimeCore = class {
|
|
|
460
602
|
if (msg?.role !== "assistant") return void 0;
|
|
461
603
|
return msg.status;
|
|
462
604
|
}
|
|
605
|
+
isPersistableAssistantStatus(status) {
|
|
606
|
+
return status.type === "complete" || status.type === "incomplete" || status.type === "requires-action" && status.reason === "interrupt";
|
|
607
|
+
}
|
|
463
608
|
setRunning(running) {
|
|
464
609
|
this.isRunningFlag = running;
|
|
465
610
|
this.notifyUpdate();
|
|
@@ -470,7 +615,9 @@ var A2AThreadRuntimeCore = class {
|
|
|
470
615
|
this.setRunning(false);
|
|
471
616
|
}
|
|
472
617
|
recordHistoryEntry(parentId, message) {
|
|
473
|
-
this.appendHistoryItem(parentId, message)
|
|
618
|
+
this.appendHistoryItem(parentId, message)?.catch((error) => {
|
|
619
|
+
console.error("[react-a2a] failed to append history entry", error);
|
|
620
|
+
});
|
|
474
621
|
}
|
|
475
622
|
markPendingAssistantHistory(messageId, parentId) {
|
|
476
623
|
if (!this.history) return;
|
|
@@ -478,23 +625,74 @@ var A2AThreadRuntimeCore = class {
|
|
|
478
625
|
}
|
|
479
626
|
persistAssistantHistory(messageId) {
|
|
480
627
|
if (!this.history) return;
|
|
628
|
+
const messageData = this.session.tryGetMessage(messageId);
|
|
481
629
|
const parentId = this.assistantHistoryParents.get(messageId);
|
|
482
|
-
if (parentId === void 0) return;
|
|
483
|
-
const
|
|
630
|
+
if (parentId === void 0 && !this.recordedHistoryIds.has(messageId)) return;
|
|
631
|
+
const resolvedParentId = parentId === void 0 ? messageData?.parentId : parentId;
|
|
632
|
+
if (resolvedParentId === void 0) return;
|
|
633
|
+
const message = messageData?.message;
|
|
484
634
|
if (!message || message.role !== "assistant") return;
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
this.
|
|
635
|
+
if (!this.isPersistableAssistantStatus(message.status)) return;
|
|
636
|
+
const isPausing = message.status.type === "requires-action";
|
|
637
|
+
if (isPausing && !this.history.update) return;
|
|
638
|
+
if (this.recordedHistoryIds.has(messageId)) {
|
|
639
|
+
if (this.history.update) {
|
|
640
|
+
const update = this.history.update.bind(this.history);
|
|
641
|
+
const write = this.chainHistoryWrite(messageId, () => update({
|
|
642
|
+
parentId: resolvedParentId,
|
|
643
|
+
message
|
|
644
|
+
}));
|
|
645
|
+
if (!isPausing) this.assistantHistoryParents.delete(messageId);
|
|
646
|
+
write.then(() => {
|
|
647
|
+
this.recordedHistoryIds.add(messageId);
|
|
648
|
+
}, (error) => {
|
|
649
|
+
const pending = this.historyWrites.get(messageId);
|
|
650
|
+
if (pending === void 0 || pending === write) this.assistantHistoryParents.set(messageId, resolvedParentId);
|
|
651
|
+
console.error("[react-a2a] failed to update history entry", error);
|
|
652
|
+
});
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
if (!isPausing) this.assistantHistoryParents.delete(messageId);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
const write = this.appendHistoryItem(resolvedParentId, message);
|
|
659
|
+
if (!write) return;
|
|
660
|
+
if (!isPausing) this.assistantHistoryParents.delete(messageId);
|
|
661
|
+
write.catch((error) => {
|
|
662
|
+
const pending = this.historyWrites.get(messageId);
|
|
663
|
+
if (pending === void 0 || pending === write) this.assistantHistoryParents.set(messageId, resolvedParentId);
|
|
664
|
+
console.error("[react-a2a] failed to append history entry", error);
|
|
665
|
+
});
|
|
488
666
|
}
|
|
489
667
|
appendHistoryItem(parentId, message) {
|
|
490
668
|
if (!this.history || this.recordedHistoryIds.has(message.id)) return;
|
|
491
669
|
this.recordedHistoryIds.add(message.id);
|
|
492
|
-
this.history.append(
|
|
670
|
+
const append = this.history.append.bind(this.history);
|
|
671
|
+
const write = this.chainHistoryWrite(message.id, () => append({
|
|
493
672
|
parentId,
|
|
494
673
|
message
|
|
495
|
-
})
|
|
674
|
+
}));
|
|
675
|
+
write.catch(() => {
|
|
496
676
|
this.recordedHistoryIds.delete(message.id);
|
|
497
677
|
});
|
|
678
|
+
return write;
|
|
679
|
+
}
|
|
680
|
+
chainHistoryWrite(id, write) {
|
|
681
|
+
const pending = this.historyWrites.get(id);
|
|
682
|
+
let next;
|
|
683
|
+
if (pending) next = pending.then(write, write);
|
|
684
|
+
else try {
|
|
685
|
+
next = Promise.resolve(write());
|
|
686
|
+
} catch (error) {
|
|
687
|
+
next = Promise.reject(error);
|
|
688
|
+
}
|
|
689
|
+
this.historyWrites.set(id, next);
|
|
690
|
+
next.then(() => {
|
|
691
|
+
if (this.historyWrites.get(id) === next) this.historyWrites.delete(id);
|
|
692
|
+
}, () => {
|
|
693
|
+
if (this.historyWrites.get(id) === next) this.historyWrites.delete(id);
|
|
694
|
+
});
|
|
695
|
+
return next;
|
|
498
696
|
}
|
|
499
697
|
};
|
|
500
698
|
//#endregion
|