@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.
@@ -1,90 +1,103 @@
1
- import { A2AAgentCard, A2AArtifact, A2ASendMessageConfiguration, A2ATask } from "./types.js";
2
- import { A2AClient } from "./A2AClient.js";
3
- import { AppendMessage, AssistantRuntime, ExportedMessageRepository, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
4
- //#region src/A2AThreadRuntimeCore.d.ts
5
- type A2AThreadRuntimeCoreOptions = {
6
- client: A2AClient;
7
- contextId?: string | undefined;
8
- configuration?: A2ASendMessageConfiguration | undefined;
9
- onError?: ((error: Error) => void) | undefined;
10
- onCancel?: (() => void) | undefined;
11
- onArtifactComplete?: ((artifact: A2AArtifact) => void) | undefined;
12
- history?: ThreadHistoryAdapter | undefined;
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
- private client;
17
- private contextId;
18
- private configuration;
19
- private onError;
20
- private onCancel;
21
- private onArtifactComplete;
22
- private history;
23
- private readonly notifyUpdate;
24
- private runtime;
25
- private readonly session;
26
- private isRunningFlag;
27
- private abortController;
28
- private pendingError;
29
- private currentTask;
30
- private currentArtifacts;
31
- private agentCardValue;
32
- private readonly assistantHistoryParents;
33
- private readonly recordedHistoryIds;
34
- private _isLoading;
35
- private _loadPromise;
36
- private _loadRequested;
37
- private _agentCardPromise;
38
- private _agentCardRetryAfter;
39
- private _agentCardRetryDelay;
40
- private _agentCardDiscoveryFailed;
41
- private lastOptionsContextId;
42
- constructor(options: A2AThreadRuntimeCoreOptions);
43
- updateOptions(options: Omit<A2AThreadRuntimeCoreOptions, "notifyUpdate">): void;
44
- /** Thread-boundary reset: applyExternalMessages alone also serves branch
45
- * switches, deletes, and cancel resyncs, which must keep the live context. */
46
- resetContext(): void;
47
- attachRuntime(runtime: AssistantRuntime): void;
48
- detachRuntime(): void;
49
- getRuntime(): AssistantRuntime | undefined;
50
- getMessages(): readonly ThreadMessage[];
51
- getMessageRepository(): ExportedMessageRepository;
52
- getTask(): A2ATask | undefined;
53
- getArtifacts(): readonly A2AArtifact[];
54
- getAgentCard(): A2AAgentCard | undefined;
55
- isRunning(): boolean;
56
- get isLoading(): boolean;
57
- private loadAgentCard;
58
- private waitForAgentCard;
59
- __internal_load(): Promise<void>;
60
- append(message: AppendMessage): Promise<void>;
61
- edit(message: AppendMessage): Promise<void>;
62
- reload(parentId: string | null, _config?: {
63
- runConfig?: Record<string, unknown>;
64
- }): Promise<void>;
65
- cancel(): Promise<void>;
66
- private appendLinearChain;
67
- private finalizeExternalApply;
68
- applyExternalMessages(messages: readonly ThreadMessage[]): void;
69
- private startRun;
70
- private runStreaming;
71
- private runSync;
72
- private handleStreamEvent;
73
- private handleStatusUpdate;
74
- private handleArtifactUpdate;
75
- private handleMessage;
76
- private handleTaskSnapshot;
77
- private insertAssistantPlaceholder;
78
- private updateAssistantContent;
79
- private updateAssistantStatus;
80
- private getAssistantStatus;
81
- private setRunning;
82
- private finishRun;
83
- private recordHistoryEntry;
84
- private markPendingAssistantHistory;
85
- private persistAssistantHistory;
86
- private appendHistoryItem;
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","names":[],"sources":["../src/A2AThreadRuntimeCore.ts"],"mappings":";;;;KAsCY;EACV,QAAQ;EACR;EACA,gBAAgB;EAChB,YAAY,OAAO;EACnB;EACA,uBAAuB,UAAU;EACjC,UAAU;EACV;;cAyBW;UACH;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;UAET;mBACS;UACT;UACA;UACA;UAGA;UACA;UACA;mBAGS;mBACA;UACT;UACA;UACA;UACA;UACA;UACA;UACA;UAEA;EAEI,YAAA,SAAS;EAYrB,cAAc,SAAS,KAAK;;;EA8B5B;EAcA,cAAc,SAAS;EAIvB;EASA,cAAc;EAId,wBAAwB;EAIxB,wBAAwB;EAIxB,WAAW;EAIX,yBAAyB;EAIzB,gBAAgB;EAIhB;MAII;UAII;UAwBM;EAoBd,mBAAmB;EAkCb,OAAO,SAAS,gBAAgB;EAuBhC,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAW,YAAY;MACtB;EAaG,UAAU;UAiBR;UAgBA;EAWR,sBAAsB,mBAAmB;UAmC3B;UA+EA;UA4CA;UA4BN;UAiBA;UA6BA;UA0CA;UAQA;UAuCA;UAsBA;UAUA;UAaA;UAQA;UAKA;UAQA;UAIA;UAQA;UAeA"}
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 = Promise.all([historyPromise, agentCardPromise]).then(([repo]) => {
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 (this.currentTask?.id) try {
196
- const updated = await this.client.cancelTask(this.currentTask.id);
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
- if (artifacts) this.currentArtifacts = artifacts;
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 (status.type === "complete" || status.type === "incomplete") this.persistAssistantHistory(messageId);
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 message = this.session.tryGetMessage(messageId)?.message;
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 (message.status?.type !== "complete" && message.status?.type !== "incomplete") return;
486
- this.assistantHistoryParents.delete(messageId);
487
- this.appendHistoryItem(parentId, message);
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
- }).catch(() => {
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