@assistant-ui/react-ag-ui 0.0.58 → 0.0.60

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.
Files changed (45) hide show
  1. package/dist/agUiExtras.d.ts +1 -2
  2. package/dist/agUiExtras.d.ts.map +1 -1
  3. package/dist/hooks.d.ts +6 -7
  4. package/dist/hooks.d.ts.map +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/runtime/AgUiThreadRuntimeCore.d.ts +17 -6
  7. package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
  8. package/dist/runtime/AgUiThreadRuntimeCore.js +95 -47
  9. package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
  10. package/dist/runtime/adapter/conversions.d.ts +11 -11
  11. package/dist/runtime/adapter/conversions.d.ts.map +1 -1
  12. package/dist/runtime/adapter/conversions.js +114 -17
  13. package/dist/runtime/adapter/conversions.js.map +1 -1
  14. package/dist/runtime/adapter/run-aggregator.d.ts +9 -10
  15. package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
  16. package/dist/runtime/adapter/run-aggregator.js +59 -0
  17. package/dist/runtime/adapter/run-aggregator.js.map +1 -1
  18. package/dist/runtime/adapter/subscriber.d.ts +2 -3
  19. package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
  20. package/dist/runtime/adapter/tool-approval.d.ts +4 -5
  21. package/dist/runtime/adapter/tool-approval.d.ts.map +1 -1
  22. package/dist/runtime/event-parser.d.ts +2 -3
  23. package/dist/runtime/event-parser.d.ts.map +1 -1
  24. package/dist/runtime/interrupt-internals.d.ts +3 -4
  25. package/dist/runtime/interrupt-internals.d.ts.map +1 -1
  26. package/dist/runtime/logger.d.ts +2 -3
  27. package/dist/runtime/logger.d.ts.map +1 -1
  28. package/dist/runtime/mcp-tool-result.d.ts +3 -4
  29. package/dist/runtime/mcp-tool-result.d.ts.map +1 -1
  30. package/dist/runtime/types.d.ts +35 -11
  31. package/dist/runtime/types.d.ts.map +1 -1
  32. package/dist/useAgUiRuntime.d.ts +2 -3
  33. package/dist/useAgUiRuntime.d.ts.map +1 -1
  34. package/dist/useAgUiRuntime.js +14 -5
  35. package/dist/useAgUiRuntime.js.map +1 -1
  36. package/package.json +12 -11
  37. package/src/index.ts +1 -0
  38. package/src/runtime/AgUiThreadRuntimeCore.test.ts +18 -0
  39. package/src/runtime/AgUiThreadRuntimeCore.ts +176 -63
  40. package/src/runtime/adapter/conversions.ts +200 -26
  41. package/src/runtime/adapter/run-aggregator.ts +85 -0
  42. package/src/runtime/types.ts +26 -0
  43. package/src/useAgUiRuntime.queue.test.tsx +54 -0
  44. package/src/useAgUiRuntime.thread-switch.test.tsx +199 -0
  45. package/src/useAgUiRuntime.ts +14 -3
@@ -1,6 +1,5 @@
1
1
  import { AgUiRuntimeExtras } from "./runtime/types.js";
2
2
  //#region src/agUiExtras.d.ts
3
- declare const agUiExtras: import("@assistant-ui/core/react").RuntimeExtras<AgUiRuntimeExtras>;
3
+ export declare const agUiExtras: import("@assistant-ui/core/react").RuntimeExtras<AgUiRuntimeExtras>;
4
4
  //#endregion
5
- export { agUiExtras };
6
5
  //# sourceMappingURL=agUiExtras.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agUiExtras.d.ts","names":[],"sources":["../src/agUiExtras.ts"],"mappings":";;cAGa,+CAAU,cAAA"}
1
+ {"version":3,"file":"agUiExtras.d.ts","names":[],"sources":["../src/agUiExtras.ts"],"mappings":";;qBAGa,+CAAU,cAAA"}
package/dist/hooks.d.ts CHANGED
@@ -6,17 +6,17 @@ import { ReadonlyJSONValue } from "assistant-stream/utils";
6
6
  * Read the pending AG-UI interrupts on the current thread. Returns an empty
7
7
  * array when no interrupts are pending, so consumers can `.map` without a guard.
8
8
  */
9
- declare const useAgUiInterrupts: () => readonly AgUiInterrupt[];
9
+ export declare const useAgUiInterrupts: () => readonly AgUiInterrupt[];
10
10
  /**
11
11
  * Returns a stable function that sends an A2UI action back to the agent and
12
12
  * resumes the run.
13
13
  */
14
- declare const useAgUiSendA2uiAction: () => (action: Record<string, unknown>) => void;
14
+ export declare const useAgUiSendA2uiAction: () => (action: Record<string, unknown>) => void;
15
15
  /**
16
16
  * Returns a function that submits responses (each `resolved` or `cancelled`)
17
17
  * for the pending AG-UI interrupts and resumes the run.
18
18
  */
19
- declare const useAgUiSubmitInterruptResponses: () => (responses: readonly AgUiResumeEntry[]) => Promise<void>;
19
+ export declare const useAgUiSubmitInterruptResponses: () => (responses: readonly AgUiResumeEntry[]) => Promise<void>;
20
20
  /**
21
21
  * Returns a function that discards the pending AG-UI interrupts or pending
22
22
  * client-side tool calls and appends the given user message, starting a fresh
@@ -30,9 +30,8 @@ declare const useAgUiSubmitInterruptResponses: () => (responses: readonly AgUiRe
30
30
  * `autoCancelPendingToolCalls` runtime option, this hook cancels regardless
31
31
  * of that option's value.
32
32
  */
33
- declare const useAgUiSteerAway: () => (message: CreateAppendMessage, responses?: readonly AgUiResumeEntry[]) => Promise<void>;
34
- declare const useAgUiState: <TState = ReadonlyJSONValue>() => TState | undefined;
35
- declare const useAgUiSetState: <TState = ReadonlyJSONValue>() => (next: TState | ((prev: TState | undefined) => TState)) => void;
33
+ export declare const useAgUiSteerAway: () => (message: CreateAppendMessage, responses?: readonly AgUiResumeEntry[]) => Promise<void>;
34
+ export declare const useAgUiState: <TState = ReadonlyJSONValue>() => TState | undefined;
35
+ export declare const useAgUiSetState: <TState = ReadonlyJSONValue>() => (next: TState | ((prev: TState | undefined) => TState)) => void;
36
36
  //#endregion
37
- export { useAgUiInterrupts, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
38
37
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;;;cAea,kCAAiC;;;;;cAOjC,8BAAqB,QAGrB;;;;;cAUA,wCAEH,oBAAoB,sBAAoB;;;;;;;;;;;;;;cAiBrC,yBAGT,SAAS,qBACT,qBAAqB,sBACpB;cAGQ,eAAgB,SAAS,wBAClC;cAIS,kBAAmB,SAAS,yBAE/B,MAAM,WAAW,MAAM,uBAAuB"}
1
+ {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;;;qBAea,kCAAiC;;;;;qBAOjC,8BAAqB,QAGrB;;;;;qBAUA,wCAEH,oBAAoB,sBAAoB;;;;;;;;;;;;;;qBAiBrC,yBAGT,SAAS,qBACT,qBAAqB,sBACpB;qBAGQ,eAAgB,SAAS,wBAClC;qBAIS,kBAAmB,SAAS,yBAE/B,MAAM,WAAW,MAAM,uBAAuB"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { AgUiInterrupt, AgUiInterruptReason, AgUiResumeEntry, AgUiRunFinishedOutcome, UseAgUiRuntimeAdapters, UseAgUiRuntimeOptions, UseAgUiThreadListAdapter } from "./runtime/types.js";
1
+ import { AgUiInterrupt, AgUiInterruptReason, AgUiResumeEntry, AgUiResumeTranscript, AgUiRunFinishedOutcome, UseAgUiRuntimeAdapters, UseAgUiRuntimeOptions, UseAgUiThreadListAdapter } from "./runtime/types.js";
2
2
  import { useAgUiInterrupts, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses } from "./hooks.js";
3
3
  import { AgUiAssistantRuntime, useAgUiRuntime } from "./useAgUiRuntime.js";
4
4
  import { AgUiMessage, FromAgUiMessagesOptions, fromAgUiMessages, toAgUiMessages } from "./runtime/adapter/conversions.js";
5
- export { type AgUiAssistantRuntime, type AgUiInterrupt, type AgUiInterruptReason, type AgUiMessage, type AgUiResumeEntry, type AgUiRunFinishedOutcome, type FromAgUiMessagesOptions, type UseAgUiRuntimeAdapters, type UseAgUiRuntimeOptions, type UseAgUiThreadListAdapter, fromAgUiMessages, toAgUiMessages, useAgUiInterrupts, useAgUiRuntime, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
5
+ export { type AgUiAssistantRuntime, type AgUiInterrupt, type AgUiInterruptReason, type AgUiMessage, type AgUiResumeEntry, type AgUiResumeTranscript, type AgUiRunFinishedOutcome, type FromAgUiMessagesOptions, type UseAgUiRuntimeAdapters, type UseAgUiRuntimeOptions, type UseAgUiThreadListAdapter, fromAgUiMessages, toAgUiMessages, useAgUiInterrupts, useAgUiRuntime, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
@@ -1,5 +1,5 @@
1
1
  import { Logger } from "./logger.js";
2
- import { AgUiInterrupt, AgUiResumeEntry } from "./types.js";
2
+ import { AgUiInterrupt, AgUiResumeEntry, AgUiResumeTranscript } from "./types.js";
3
3
  import { AddToolResultOptions, AppendMessage, AssistantRuntime, ChatModelRunOptions, ChatModelRunResult, CreateAppendMessage, ExportedMessageRepository, RespondToToolApprovalOptions, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
4
4
  import { AbstractAgent } from "@ag-ui/client";
5
5
  import { ReadonlyJSONValue } from "assistant-stream/utils";
@@ -16,16 +16,18 @@ type CoreOptions = {
16
16
  agent: AbstractAgent;
17
17
  logger: Logger;
18
18
  showThinking: boolean;
19
+ resumeTranscript?: AgUiResumeTranscript | undefined;
19
20
  autoCancelPendingToolCalls?: boolean | undefined;
20
21
  onError?: (error: Error) => void;
21
22
  onCancel?: () => void;
22
23
  history?: ThreadHistoryAdapter;
23
24
  notifyUpdate: () => void;
24
25
  };
25
- declare class AgUiThreadRuntimeCore {
26
+ export declare class AgUiThreadRuntimeCore {
26
27
  private agent;
27
28
  private logger;
28
29
  private showThinking;
30
+ private resumeTranscript;
29
31
  private autoCancelPendingToolCalls;
30
32
  private onError;
31
33
  private onCancel;
@@ -37,7 +39,6 @@ declare class AgUiThreadRuntimeCore {
37
39
  private abortController;
38
40
  private activeRunAgent;
39
41
  private stateSnapshot;
40
- private pendingError;
41
42
  private history;
42
43
  private lastRunConfig;
43
44
  private readonly assistantHistoryParents;
@@ -47,8 +48,8 @@ declare class AgUiThreadRuntimeCore {
47
48
  private _isLoading;
48
49
  private _loadPromise;
49
50
  private _loadRequested;
50
- private pendingResumeMessageId;
51
- private pendingA2uiResume;
51
+ private pendingResume;
52
+ private pendingA2uiResumeOwner;
52
53
  private pendingA2uiAction;
53
54
  constructor(options: CoreOptions);
54
55
  updateOptions(options: Omit<CoreOptions, "notifyUpdate">): void;
@@ -68,6 +69,8 @@ declare class AgUiThreadRuntimeCore {
68
69
  runConfig?: RunConfig;
69
70
  }): Promise<void>;
70
71
  cancel(): Promise<void>;
72
+ private abortActiveRun;
73
+ private supersedeActiveRun;
71
74
  resume(config: ResumeRunConfig): Promise<void>;
72
75
  resumeInFlightRun(messages: readonly ThreadMessage[]): Promise<void>;
73
76
  private assertNoPendingInterrupts;
@@ -117,6 +120,15 @@ declare class AgUiThreadRuntimeCore {
117
120
  private startRun;
118
121
  private consumeResumeStream;
119
122
  private buildRunInput;
123
+ /**
124
+ * An anchor the thread no longer carries falls back to the whole transcript.
125
+ * The anchor is missing exactly when a snapshot import replaced the messages
126
+ * this resume was raised against, and a host that expects a delta tolerates
127
+ * being told more than it knows, while one rebuilding the run from the
128
+ * transcript cannot recover from being told less.
129
+ */
130
+ private selectRunMessages;
131
+ private clearDeferredContinuations;
120
132
  private setRunning;
121
133
  private finishRun;
122
134
  private insertAssistantPlaceholder;
@@ -138,5 +150,4 @@ declare class AgUiThreadRuntimeCore {
138
150
  private chainHistoryWrite;
139
151
  }
140
152
  //#endregion
141
- export { AgUiThreadRuntimeCore };
142
153
  //# sourceMappingURL=AgUiThreadRuntimeCore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;KA8EK,YAAY,YAAY;KACxB,gBACH,SAAS,wBACN,eAAe;KACf;EACH;EACA;EACA,WAAW;EACX,SAAS;;KAGN;EACH,OAAO;EACP,QAAQ;EACR;EACA;EACA,WAAW,OAAO;EAClB;EACA,UAAU;EACV;;cAoCW;UACH;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UAET;mBACS;UAgBT;UACA;UAGA;UACA;UACA;UACA;UACA;mBACS;mBACA;mBACA;mBACA;UACT;UACA;UACA;UACA;UACA;UACA;EAEI,YAAA,SAAS;EAWrB,cAAc,SAAS,KAAK;EAoB5B,cAAc,SAAS;EAIvB;EAOA,wBAAwB;EAIxB,wBAAwB;EAIxB,YAAY;EAIZ;MAII;EAIJ,mBAAmB;EAsDb,OAAO,SAAS,gBAAgB;UAW9B;UAQA;EAiBF,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAU,YAAY;MACrB;EAMG,UAAU;EAcV,OAAO,QAAQ,kBAAkB;EAUjC,kBAAkB,mBAAmB,kBAAkB;UAwBrD;UAOA;EAgBR;IACE;IACA,qBAAqB;;EAavB;IACE;IACA;;EAaI,yBACJ,oBAAoB,oBACnB;;;;;;;UAuCW;;;;;;;;EAed,YAAY;UAYJ;EAwBF,sBACJ,SAAS,+BACR;EAsEG,UACJ,SAAS,qBACT,qBAAqB,oBACpB;UAyCK;UAkBA;UAiCA;UA0BA;EAmCR,yBAAyB;UAiBjB;EAiBR,cAAc,SAAS;EA+BvB,eAAe,QAAQ;UA4Bf;UAYA;UAiCA;EAUR,sBAAsB,mBAAmB;EAkDzC,kBAAkB,OAAO;EAKzB,SACE,MACI,sBACE,MAAM,kCAAkC;EAOhD;UAKc;UAyPA;UA2DN;UAkCA;UAKA;UAQA;UAyBA;UAkEA;UAiDA;UA0BA;UA6BA;UAgEA;UA0EA;UA6DA;UAuDA;UAQA;UAIA;UAKA;UAMA;UAQA;UAsDA;UAqBA"}
1
+ {"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;KAmFK,YAAY,YAAY;KACxB,gBACH,SAAS,wBACN,eAAe;KACf;EACH;EACA;EACA,WAAW;EACX,SAAS;;KAaN;EACH,OAAO;EACP,QAAQ;EACR;EACA,mBAAmB;EACnB;EACA,WAAW,OAAO;EAClB;EACA,UAAU;EACV;;qBAoCW;UACH;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UAET;mBACS;UAgBT;UACA;UAGA;UACA;UACA;UACA;mBACS;mBACA;mBACA;mBACA;UACT;UACA;UACA;UACA;UAEA;UACA;EAEI,YAAA,SAAS;EAYrB,cAAc,SAAS,KAAK;EAqB5B,cAAc,SAAS;EAIvB;EAOA,wBAAwB;EAIxB,wBAAwB;EAIxB,YAAY;EAIZ;MAII;EAIJ,mBAAmB;EAsDb,OAAO,SAAS,gBAAgB;UAgB9B;UAQA;EAiBF,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAU,YAAY;MACrB;EAMG,UAAU;UAWR;UAiBA;EAaF,OAAO,QAAQ,kBAAkB;EAUjC,kBAAkB,mBAAmB,kBAAkB;UAwBrD;UAOA;EAgBR;IACE;IACA,qBAAqB;;EAavB;IACE;IACA;;EAaI,yBACJ,oBAAoB,oBACnB;;;;;;;UAuCW;;;;;;;;EAkBd,YAAY;UAYJ;EAwBF,sBACJ,SAAS,+BACR;EAsEG,UACJ,SAAS,qBACT,qBAAqB,oBACpB;UA4CK;UAkBA;UAiCA;UA2BA;EAmCR,yBAAyB;UAiBjB;EAiBR,cAAc,SAAS;EAqCvB,eAAe,QAAQ;UA6Bf;UAaA;UAiCA;EAUR,sBAAsB,mBAAmB;EA6DzC,kBAAkB,OAAO;EAKzB,SACE,MACI,sBACE,MAAM,kCAAkC;EAOhD;UAKc;UA0PA;UA2DN;;;;;;;;UA4CA;UAaA;UAUA;UAKA;UAOA;UAyBA;UAkEA;UAiDA;UA6BA;UA6BA;UAgEA;UA0EA;UA6DA;UAuDA;UAQA;UAIA;UAKA;UAMA;UAQA;UAsDA;UAqBA"}
@@ -36,6 +36,7 @@ var AgUiThreadRuntimeCore = class {
36
36
  agent;
37
37
  logger;
38
38
  showThinking;
39
+ resumeTranscript;
39
40
  autoCancelPendingToolCalls;
40
41
  onError;
41
42
  onCancel;
@@ -60,7 +61,6 @@ var AgUiThreadRuntimeCore = class {
60
61
  abortController = null;
61
62
  activeRunAgent = null;
62
63
  stateSnapshot;
63
- pendingError = null;
64
64
  history;
65
65
  lastRunConfig;
66
66
  assistantHistoryParents = /* @__PURE__ */ new Map();
@@ -70,13 +70,14 @@ var AgUiThreadRuntimeCore = class {
70
70
  _isLoading = false;
71
71
  _loadPromise;
72
72
  _loadRequested = false;
73
- pendingResumeMessageId = null;
74
- pendingA2uiResume = false;
73
+ pendingResume = null;
74
+ pendingA2uiResumeOwner = null;
75
75
  pendingA2uiAction;
76
76
  constructor(options) {
77
77
  this.agent = options.agent;
78
78
  this.logger = options.logger;
79
79
  this.showThinking = options.showThinking;
80
+ this.resumeTranscript = options.resumeTranscript ?? "full";
80
81
  this.autoCancelPendingToolCalls = options.autoCancelPendingToolCalls;
81
82
  this.onError = options.onError;
82
83
  this.onCancel = options.onCancel;
@@ -87,6 +88,7 @@ var AgUiThreadRuntimeCore = class {
87
88
  this.agent = options.agent;
88
89
  this.logger = options.logger;
89
90
  this.showThinking = options.showThinking;
91
+ this.resumeTranscript = options.resumeTranscript ?? "full";
90
92
  this.autoCancelPendingToolCalls = options.autoCancelPendingToolCalls;
91
93
  this.onError = options.onError;
92
94
  this.onCancel = options.onCancel;
@@ -150,12 +152,14 @@ var AgUiThreadRuntimeCore = class {
150
152
  }
151
153
  async append(message) {
152
154
  const startRun = message.startRun ?? message.role === "user";
155
+ let ownsThread = true;
153
156
  if (startRun) {
154
157
  this.assertNoPendingInterrupts();
155
158
  this.maybeAutoCancelPendingToolCalls();
159
+ ownsThread = this.supersedeActiveRun();
156
160
  }
157
161
  const threadMessageId = this.appendEntry(message);
158
- if (!startRun) return;
162
+ if (!startRun || !ownsThread) return;
159
163
  await this.startRun(threadMessageId, message.runConfig);
160
164
  }
161
165
  maybeAutoCancelPendingToolCalls() {
@@ -184,12 +188,26 @@ var AgUiThreadRuntimeCore = class {
184
188
  await this.startRun(parentId, config.runConfig);
185
189
  }
186
190
  async cancel() {
187
- if (!this.abortController) return;
191
+ this.abortActiveRun();
192
+ }
193
+ abortActiveRun() {
194
+ const controller = this.abortController;
195
+ if (!controller) return;
188
196
  try {
189
197
  (this.activeRunAgent ?? this.agent).abortRun();
190
198
  } finally {
191
- this.abortController.abort();
199
+ controller.abort();
200
+ }
201
+ }
202
+ supersedeActiveRun() {
203
+ try {
204
+ this.abortActiveRun();
205
+ } catch (error) {
206
+ this.logger.error?.("[agui] agent abortRun failed", error);
192
207
  }
208
+ if (this.abortController === null) return true;
209
+ this.logger.debug?.("[agui] onCancel started a replacement run; dropping the superseding send");
210
+ return false;
193
211
  }
194
212
  async resume(config) {
195
213
  this.assertNoPendingInterrupts();
@@ -259,7 +277,10 @@ var AgUiThreadRuntimeCore = class {
259
277
  */
260
278
  async resumeWithResponses(messageId, resume) {
261
279
  this.clearPendingInterrupts(messageId, resume);
262
- await this.startRun(messageId, this.lastRunConfig, resume);
280
+ await this.startRun(messageId, this.lastRunConfig, {
281
+ entries: resume,
282
+ interruptedMessageId: messageId
283
+ });
263
284
  }
264
285
  /**
265
286
  * A rejected decision reaches the caller through the approval seam, and
@@ -331,7 +352,10 @@ var AgUiThreadRuntimeCore = class {
331
352
  const normalized = this.toAppendMessage(message);
332
353
  this.clearPendingInterrupts(pending.messageId, resume);
333
354
  const threadMessageId = this.appendEntry(normalized);
334
- await this.startRun(threadMessageId, normalized.runConfig, resume);
355
+ await this.startRun(threadMessageId, normalized.runConfig, {
356
+ entries: resume,
357
+ interruptedMessageId: pending.messageId
358
+ });
335
359
  }
336
360
  resolveSteerAwayResume(interrupts, responses) {
337
361
  const responsesById = this.collectInterruptResponses("steerAway", interrupts, responses ?? []);
@@ -368,7 +392,7 @@ var AgUiThreadRuntimeCore = class {
368
392
  };
369
393
  return {
370
394
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
371
- parentId: message.parentId ?? this.session.headId,
395
+ parentId: message.parentId === void 0 ? this.session.headId : message.parentId,
372
396
  sourceId: message.sourceId ?? null,
373
397
  role: message.role ?? "user",
374
398
  content: message.content,
@@ -446,8 +470,9 @@ var AgUiThreadRuntimeCore = class {
446
470
  return {
447
471
  ...part,
448
472
  result: options.result,
449
- artifact: options.artifact,
450
- isError: options.isError
473
+ isError: options.isError,
474
+ ...options.artifact !== void 0 && { artifact: options.artifact },
475
+ ...options.modelContent !== void 0 && { modelContent: options.modelContent }
451
476
  };
452
477
  });
453
478
  if (!matchedToolCall) return message;
@@ -471,16 +496,21 @@ var AgUiThreadRuntimeCore = class {
471
496
  delete userAction.type;
472
497
  if (!("timestamp" in userAction)) userAction.timestamp = (/* @__PURE__ */ new Date()).toISOString();
473
498
  this.pendingA2uiAction = userAction;
474
- if (this.isRunningFlag) {
475
- this.pendingA2uiResume = true;
499
+ const owner = this.abortController;
500
+ if (owner) {
501
+ this.pendingA2uiResumeOwner = owner;
476
502
  return;
477
503
  }
478
504
  this.startResumeRun(parentId);
479
505
  }
480
506
  maybeResumeAfterToolResults(messageId) {
481
507
  if (!this.maybeCompleteAfterToolResults(messageId)) return;
482
- if (this.isRunningFlag) {
483
- this.pendingResumeMessageId = messageId;
508
+ const owner = this.abortController;
509
+ if (owner) {
510
+ this.pendingResume = {
511
+ owner,
512
+ messageId
513
+ };
484
514
  return;
485
515
  }
486
516
  this.startResumeRun(messageId);
@@ -513,7 +543,7 @@ var AgUiThreadRuntimeCore = class {
513
543
  });
514
544
  }
515
545
  applyExternalMessages(messages) {
516
- this.pendingA2uiResume = false;
546
+ this.pendingA2uiResumeOwner = null;
517
547
  this.pendingA2uiAction = void 0;
518
548
  this.assistantHistoryParents.clear();
519
549
  if (messages.length === 0) this.session.clear();
@@ -551,6 +581,8 @@ var AgUiThreadRuntimeCore = class {
551
581
  }
552
582
  this.snapshotHistoryIds.clear();
553
583
  for (const { message } of this.getMessageRepository().messages) this.snapshotHistoryIds.add(message.id);
584
+ const resumeTarget = this.pendingResume?.messageId;
585
+ if (resumeTarget !== void 0 && !this.session.getMessages().some((message) => message.id === resumeTarget)) this.pendingResume = null;
554
586
  this.notifyUpdate();
555
587
  }
556
588
  loadExternalState(state) {
@@ -566,13 +598,14 @@ var AgUiThreadRuntimeCore = class {
566
598
  this.notifyUpdate();
567
599
  }
568
600
  async startRun(parentId, runConfig, resume, resumeStream) {
601
+ if (!this.supersedeActiveRun()) return;
569
602
  const normalizedRunConfig = runConfig ?? {};
570
603
  this.lastRunConfig = normalizedRunConfig;
571
604
  const parent = parentId === null ? void 0 : this.session.tryGetMessage(parentId);
572
605
  const shouldEagerlyInsertAssistant = parentId !== null && parent !== void 0 && parentId !== this.session.headId;
573
606
  const historicalMessages = [...shouldEagerlyInsertAssistant ? this.session.tryGetMessages(parentId) ?? this.session.getMessages() : this.session.getMessages()];
574
607
  const runStartMessageIds = new Set(this.getMessageRepository().messages.map(({ message }) => message.id));
575
- this.pendingError = null;
608
+ let pendingError = null;
576
609
  const assistantParentId = parent ? parentId : this.session.headId;
577
610
  let assistantMessageId;
578
611
  let assistantCollided = false;
@@ -647,7 +680,7 @@ var AgUiThreadRuntimeCore = class {
647
680
  type: "incomplete",
648
681
  reason: "cancelled"
649
682
  } });
650
- await this.consumeResumeStream(resumeStream, {
683
+ pendingError = await this.consumeResumeStream(resumeStream, {
651
684
  runConfig: normalizedRunConfig,
652
685
  threadId: this.agent.threadId || "main",
653
686
  parentId: assistantParentId,
@@ -656,7 +689,7 @@ var AgUiThreadRuntimeCore = class {
656
689
  ensureAssistant,
657
690
  applyUpdate,
658
691
  getAssistantMessageId: () => assistantMessageId
659
- });
692
+ }) ?? null;
660
693
  } else {
661
694
  const runId = generateId();
662
695
  aggregator.handle({
@@ -670,7 +703,7 @@ var AgUiThreadRuntimeCore = class {
670
703
  logger: this.logger,
671
704
  onRunFailed: (error) => {
672
705
  if (abortSignal.aborted) return;
673
- this.pendingError = error;
706
+ pendingError = error;
674
707
  invokeRuntimeCallback("onError", this.onError, error);
675
708
  }
676
709
  });
@@ -689,28 +722,24 @@ var AgUiThreadRuntimeCore = class {
689
722
  message: err.message
690
723
  });
691
724
  invokeRuntimeCallback("onError", this.onError, err);
692
- this.pendingError = this.pendingError ?? err;
725
+ pendingError ??= err;
693
726
  }
694
727
  } finally {
695
728
  this.finishRun(abortController);
696
729
  }
697
- if (this.pendingError) {
698
- const err = this.pendingError;
730
+ if (pendingError) {
731
+ const err = pendingError;
699
732
  this.reportedErrors.add(err);
700
- this.pendingError = null;
701
- this.pendingResumeMessageId = null;
702
- this.pendingA2uiResume = false;
703
- this.pendingA2uiAction = void 0;
733
+ this.clearDeferredContinuations(abortController);
704
734
  throw err;
705
735
  }
706
- if (this.pendingResumeMessageId !== null) {
707
- const resumeMessageId = this.pendingResumeMessageId;
708
- this.pendingResumeMessageId = null;
709
- if (!abortSignal.aborted) this.startResumeRun(resumeMessageId);
710
- else this.pendingA2uiAction = void 0;
736
+ if (this.pendingResume?.owner === abortController) {
737
+ const { messageId } = this.pendingResume;
738
+ this.pendingResume = null;
739
+ if (!abortSignal.aborted) this.startResumeRun(messageId);
711
740
  }
712
- if (this.pendingA2uiResume) {
713
- this.pendingA2uiResume = false;
741
+ if (this.pendingA2uiResumeOwner === abortController) {
742
+ this.pendingA2uiResumeOwner = null;
714
743
  if (!abortSignal.aborted && this.pendingA2uiAction !== void 0) {
715
744
  if (this.getPendingInterrupts()) {
716
745
  this.pendingA2uiAction = void 0;
@@ -729,7 +758,7 @@ var AgUiThreadRuntimeCore = class {
729
758
  }
730
759
  async consumeResumeStream(stream, ctx) {
731
760
  this.pendingA2uiAction = void 0;
732
- this.pendingA2uiResume = false;
761
+ this.pendingA2uiResumeOwner = null;
733
762
  const assistantId = ctx.ensureAssistant();
734
763
  const currentId = () => ctx.getAssistantMessageId() ?? assistantId;
735
764
  const options = {
@@ -748,11 +777,11 @@ var AgUiThreadRuntimeCore = class {
748
777
  };
749
778
  try {
750
779
  for await (const result of stream(options)) {
751
- if (ctx.abortSignal.aborted) return;
780
+ if (ctx.abortSignal.aborted) return void 0;
752
781
  ctx.applyUpdate(result);
753
782
  }
754
783
  } catch (error) {
755
- if (ctx.abortSignal.aborted) return;
784
+ if (ctx.abortSignal.aborted) return void 0;
756
785
  const err = error instanceof Error ? error : new Error(String(error));
757
786
  ctx.applyUpdate({ status: {
758
787
  type: "incomplete",
@@ -760,10 +789,9 @@ var AgUiThreadRuntimeCore = class {
760
789
  error: err.message
761
790
  } });
762
791
  invokeRuntimeCallback("onError", this.onError, err);
763
- this.pendingError = this.pendingError ?? err;
764
- return;
792
+ return err;
765
793
  }
766
- if (ctx.abortSignal.aborted) return;
794
+ if (ctx.abortSignal.aborted) return void 0;
767
795
  const current = this.session.tryGetMessage(currentId())?.message;
768
796
  if (!current || current.status?.type === "running") ctx.applyUpdate({ status: {
769
797
  type: "complete",
@@ -772,7 +800,7 @@ var AgUiThreadRuntimeCore = class {
772
800
  }
773
801
  buildRunInput(runId, runConfig, historyMessages, resume) {
774
802
  const threadId = this.agent.threadId || "main";
775
- const messages = toAgUiMessages(historyMessages ?? this.session.getMessages());
803
+ const messages = toAgUiMessages(this.selectRunMessages(historyMessages ?? this.session.getMessages(), resume));
776
804
  const context = this.runtime?.thread.getModelContext();
777
805
  const input = {
778
806
  threadId,
@@ -790,20 +818,39 @@ var AgUiThreadRuntimeCore = class {
790
818
  ...runConfig?.custom ? { runConfig: runConfig.custom } : {},
791
819
  ...this.pendingA2uiAction ? { a2uiAction: { userAction: this.pendingA2uiAction } } : {}
792
820
  },
793
- ...resume !== void 0 ? { resume } : {}
821
+ ...resume !== void 0 ? { resume: resume.entries } : {}
794
822
  };
795
823
  this.pendingA2uiAction = void 0;
796
824
  return input;
797
825
  }
826
+ /**
827
+ * An anchor the thread no longer carries falls back to the whole transcript.
828
+ * The anchor is missing exactly when a snapshot import replaced the messages
829
+ * this resume was raised against, and a host that expects a delta tolerates
830
+ * being told more than it knows, while one rebuilding the run from the
831
+ * transcript cannot recover from being told less.
832
+ */
833
+ selectRunMessages(messages, resume) {
834
+ if (resume === void 0 || this.resumeTranscript !== "appended") return messages;
835
+ const anchor = messages.findIndex((message) => message.id === resume.interruptedMessageId);
836
+ if (anchor === -1) return messages;
837
+ return messages.slice(anchor + 1);
838
+ }
839
+ clearDeferredContinuations(owner) {
840
+ if (this.pendingResume?.owner === owner) this.pendingResume = null;
841
+ if (this.pendingA2uiResumeOwner === owner) {
842
+ this.pendingA2uiResumeOwner = null;
843
+ this.pendingA2uiAction = void 0;
844
+ }
845
+ }
798
846
  setRunning(running) {
799
847
  this.isRunningFlag = running;
800
848
  this.notifyUpdate();
801
849
  }
802
850
  finishRun(controller) {
803
- if (this.abortController === controller) {
804
- this.abortController = null;
805
- this.activeRunAgent = null;
806
- }
851
+ if (this.abortController !== controller) return;
852
+ this.abortController = null;
853
+ this.activeRunAgent = null;
807
854
  this.setRunning(false);
808
855
  }
809
856
  insertAssistantPlaceholder(parentId, id = generateOptimisticId()) {
@@ -912,7 +959,8 @@ var AgUiThreadRuntimeCore = class {
912
959
  ...part,
913
960
  result: prior.result,
914
961
  ...prior.artifact !== void 0 ? { artifact: prior.artifact } : {},
915
- ...prior.isError !== void 0 ? { isError: prior.isError } : {}
962
+ ...prior.isError !== void 0 ? { isError: prior.isError } : {},
963
+ ...prior.modelContent !== void 0 ? { modelContent: prior.modelContent } : {}
916
964
  };
917
965
  });
918
966
  return changed ? merged : next;