@assistant-ui/react-ag-ui 0.0.34 → 0.0.36
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/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts +8 -2
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js +158 -52
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts +12 -4
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +65 -30
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +1 -0
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +17 -0
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/adapter/subscriber.d.ts +3 -0
- package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
- package/dist/runtime/adapter/subscriber.js +1 -0
- package/dist/runtime/adapter/subscriber.js.map +1 -1
- package/dist/runtime/event-parser.js +9 -0
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/types.d.ts +4 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +9 -8
- package/src/index.ts +2 -0
- package/src/runtime/AgUiThreadRuntimeCore.ts +252 -87
- package/src/runtime/adapter/conversions.ts +87 -47
- package/src/runtime/adapter/run-aggregator.ts +30 -5
- package/src/runtime/adapter/subscriber.ts +3 -0
- package/src/runtime/event-parser.ts +9 -0
- package/src/runtime/types.ts +5 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { AgUiInterrupt, AgUiInterruptReason, AgUiResumeEntry, AgUiRunFinishedOutcome, UseAgUiRuntimeAdapters, UseAgUiRuntimeOptions, UseAgUiThreadListAdapter } from "./runtime/types.js";
|
|
2
2
|
import { AgUiAssistantRuntime, useAgUiRuntime } from "./useAgUiRuntime.js";
|
|
3
|
-
|
|
3
|
+
import { FromAgUiMessagesOptions, fromAgUiMessages } from "./runtime/adapter/conversions.js";
|
|
4
|
+
export { type AgUiAssistantRuntime, type AgUiInterrupt, type AgUiInterruptReason, type AgUiResumeEntry, type AgUiRunFinishedOutcome, type FromAgUiMessagesOptions, type UseAgUiRuntimeAdapters, type UseAgUiRuntimeOptions, type UseAgUiThreadListAdapter, fromAgUiMessages, useAgUiRuntime };
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { Logger } from "./logger.js";
|
|
2
2
|
import { AgUiInterrupt, AgUiResumeEntry } from "./types.js";
|
|
3
|
-
import { AddToolResultOptions, AppendMessage, AssistantRuntime, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
|
|
3
|
+
import { AddToolResultOptions, AppendMessage, AssistantRuntime, ChatModelRunOptions, ChatModelRunResult, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
|
|
4
4
|
import { HttpAgent } from "@ag-ui/client";
|
|
5
5
|
import { ReadonlyJSONValue } from "assistant-stream/utils";
|
|
6
6
|
|
|
7
7
|
//#region src/runtime/AgUiThreadRuntimeCore.d.ts
|
|
8
8
|
type RunConfig = NonNullable<AppendMessage["runConfig"]>;
|
|
9
|
+
type ResumeStream = (options: ChatModelRunOptions) => AsyncGenerator<ChatModelRunResult, void, unknown>;
|
|
9
10
|
type ResumeRunConfig = {
|
|
10
11
|
parentId: string | null;
|
|
11
12
|
sourceId: string | null;
|
|
12
13
|
runConfig: RunConfig;
|
|
13
|
-
stream?:
|
|
14
|
+
stream?: ResumeStream;
|
|
14
15
|
};
|
|
15
16
|
type CoreOptions = {
|
|
16
17
|
agent: HttpAgent;
|
|
@@ -40,6 +41,7 @@ declare class AgUiThreadRuntimeCore {
|
|
|
40
41
|
private readonly recordedHistoryIds;
|
|
41
42
|
private _isLoading;
|
|
42
43
|
private _loadPromise;
|
|
44
|
+
private pendingResumeMessageId;
|
|
43
45
|
constructor(options: CoreOptions);
|
|
44
46
|
updateOptions(options: Omit<CoreOptions, "notifyUpdate">): void;
|
|
45
47
|
attachRuntime(runtime: AssistantRuntime): void;
|
|
@@ -65,9 +67,12 @@ declare class AgUiThreadRuntimeCore {
|
|
|
65
67
|
private clearPendingInterrupts;
|
|
66
68
|
findMessageIdForToolCall(toolCallId: string): string | undefined;
|
|
67
69
|
addToolResult(options: AddToolResultOptions): void;
|
|
70
|
+
private maybeResumeAfterToolResults;
|
|
71
|
+
private startResumeRun;
|
|
68
72
|
applyExternalMessages(messages: readonly ThreadMessage[]): void;
|
|
69
73
|
loadExternalState(state: ReadonlyJSONValue): void;
|
|
70
74
|
private startRun;
|
|
75
|
+
private consumeResumeStream;
|
|
71
76
|
private buildRunInput;
|
|
72
77
|
private installResumeShim;
|
|
73
78
|
private setRunning;
|
|
@@ -75,6 +80,7 @@ declare class AgUiThreadRuntimeCore {
|
|
|
75
80
|
private insertAssistantPlaceholder;
|
|
76
81
|
private reassignAssistantId;
|
|
77
82
|
private updateAssistantMessage;
|
|
83
|
+
private preserveToolResults;
|
|
78
84
|
private mergeAssistantMetadata;
|
|
79
85
|
private handleEvent;
|
|
80
86
|
private importMessagesSnapshot;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;;KAsCK,SAAA,GAAY,WAAW,CAAC,aAAA;AAAA,KACxB,YAAA,IACH,OAAA,EAAS,mBAAA,KACN,cAAA,CAAe,kBAAA;AAAA,KACf,eAAA;EACH,QAAA;EACA,QAAA;EACA,SAAA,EAAW,SAAA;EACX,MAAA,GAAS,YAAY;AAAA;AAAA,KAGlB,WAAA;EACH,KAAA,EAAO,SAAA;EACP,MAAA,EAAQ,MAAA;EACR,YAAA;EACA,OAAA,IAAW,KAAA,EAAO,KAAA;EAClB,QAAA;EACA,OAAA,GAAU,oBAAA;EACV,YAAA;AAAA;AAAA,cAKW,qBAAA;EAAA,QACH,KAAA;EAAA,QACA,MAAA;EAAA,QACA,YAAA;EAAA,QACA,OAAA;EAAA,QACA,QAAA;EAAA,iBACS,YAAA;EAAA,QAET,OAAA;EAAA,QACA,QAAA;EAAA,QACA,aAAA;EAAA,QACA,eAAA;EAAA,QACA,aAAA;EAAA,QACA,YAAA;EAAA,QACA,OAAA;EAAA,QACA,aAAA;EAAA,iBACS,uBAAA;EAAA,iBACA,kBAAA;EAAA,QACT,UAAA;EAAA,QACA,YAAA;EAAA,QACA,sBAAA;cAEI,OAAA,EAAS,WAAA;EAWrB,aAAA,CAAc,OAAA,EAAS,IAAA,CAAK,WAAA;EAU5B,aAAA,CAAc,OAAA,EAAS,gBAAA;EAIvB,aAAA;EAIA,WAAA,aAAwB,aAAA;EAIxB,QAAA,IAAY,iBAAA;EAIZ,SAAA;EAAA,IAII,SAAA;EAIJ,eAAA,IAAmB,OAAA;EAwCb,MAAA,CAAO,OAAA,EAAS,aAAA,GAAgB,OAAA;EAmBhC,IAAA,CAAK,OAAA,EAAS,aAAA,GAAgB,OAAA;EAI9B,MAAA,CACJ,QAAA,iBACA,MAAA;IAAU,SAAA,GAAY,SAAA;EAAA,IACrB,OAAA;EAOG,MAAA,IAAU,OAAA;EAKV,MAAA,CAAO,MAAA,EAAQ,eAAA,GAAkB,OAAA;EAAA,QAU/B,yBAAA;EAOR,oBAAA;IACE,SAAA;IACA,UAAA,WAAqB,aAAA;EAAA;EAqBjB,wBAAA,CACJ,SAAA,WAAoB,eAAA,KACnB,OAAA;EAAA,QAyEK,sBAAA;EAgCR,wBAAA,CAAyB,UAAA;EAiBzB,aAAA,CAAc,OAAA,EAAS,oBAAA;EAAA,QAiCf,2BAAA;EAAA,QAqCA,cAAA;EAMR,qBAAA,CAAsB,QAAA,WAAmB,aAAA;EAUzC,iBAAA,CAAkB,KAAA,EAAO,iBAAA;EAAA,QAKX,QAAA;EAAA,QAqIA,mBAAA;EAAA,QAyDN,aAAA;EAAA,QA2BA,iBAAA;EAAA,QAqBA,UAAA;EAAA,QAKA,SAAA;EAAA,QAOA,0BAAA;EAAA,QAqBA,mBAAA;EAAA,QAiCA,sBAAA;EAAA,QAoDA,mBAAA;EAAA,QAiCA,sBAAA;EAAA,QA4BA,WAAA;EAAA,QAiCA,sBAAA;EAAA,QAwBA,eAAA;EAAA,QAQA,SAAA;EAAA,QAYA,gBAAA;EAAA,QAIA,mBAAA;EAAA,QAKA,kBAAA;EAAA,QAIA,2BAAA;EAAA,QAQA,uBAAA;EAAA,QAWA,iBAAA;AAAA"}
|
|
@@ -3,6 +3,7 @@ import { AG_UI_METADATA_NAMESPACE, RunAggregator } from "./adapter/run-aggregato
|
|
|
3
3
|
import { fromAgUiMessages, toAgUiMessages, toAgUiTools } from "./adapter/conversions.js";
|
|
4
4
|
import { createAgUiSubscriber } from "./adapter/subscriber.js";
|
|
5
5
|
import { fromThreadMessageLike, generateId } from "@assistant-ui/core/internal";
|
|
6
|
+
import jsonpatch from "fast-json-patch";
|
|
6
7
|
//#region src/runtime/AgUiThreadRuntimeCore.ts
|
|
7
8
|
const optimisticPrefix = "__optimistic__";
|
|
8
9
|
const generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
|
|
@@ -31,6 +32,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
31
32
|
recordedHistoryIds = /* @__PURE__ */ new Set();
|
|
32
33
|
_isLoading = false;
|
|
33
34
|
_loadPromise;
|
|
35
|
+
pendingResumeMessageId = null;
|
|
34
36
|
constructor(options) {
|
|
35
37
|
this.agent = options.agent;
|
|
36
38
|
this.logger = options.logger;
|
|
@@ -78,7 +80,8 @@ var AgUiThreadRuntimeCore = class {
|
|
|
78
80
|
this.applyExternalMessages(messages);
|
|
79
81
|
if (repo.unstable_resume) {
|
|
80
82
|
const parentId = repo.headId ?? messages.at(-1)?.id ?? null;
|
|
81
|
-
|
|
83
|
+
const resumeStream = this.history?.resume?.bind(this.history);
|
|
84
|
+
await this.startRun(parentId, this.lastRunConfig, void 0, resumeStream);
|
|
82
85
|
}
|
|
83
86
|
}).catch((error) => {
|
|
84
87
|
this.logger.error?.("[agui] failed to load history", error);
|
|
@@ -117,8 +120,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
117
120
|
}
|
|
118
121
|
async resume(config) {
|
|
119
122
|
this.assertNoPendingInterrupts();
|
|
120
|
-
|
|
121
|
-
await this.startRun(config.parentId, config.runConfig ?? this.lastRunConfig);
|
|
123
|
+
await this.startRun(config.parentId, config.runConfig ?? this.lastRunConfig, void 0, config.stream);
|
|
122
124
|
}
|
|
123
125
|
assertNoPendingInterrupts() {
|
|
124
126
|
if (!this.getPendingInterrupts()) return;
|
|
@@ -202,7 +204,6 @@ var AgUiThreadRuntimeCore = class {
|
|
|
202
204
|
}
|
|
203
205
|
addToolResult(options) {
|
|
204
206
|
let updated = false;
|
|
205
|
-
let shouldResume = false;
|
|
206
207
|
this.messages = this.messages.map((message) => {
|
|
207
208
|
if (message.id !== options.messageId || message.role !== "assistant") return message;
|
|
208
209
|
const assistant = message;
|
|
@@ -219,31 +220,40 @@ var AgUiThreadRuntimeCore = class {
|
|
|
219
220
|
});
|
|
220
221
|
if (!matchedToolCall) return message;
|
|
221
222
|
updated = true;
|
|
222
|
-
if (assistant.status?.type === "requires-action" && assistant.status.reason === "tool-calls" && content.every((part) => part.type !== "tool-call" || "result" in part && part.result !== void 0)) {
|
|
223
|
-
shouldResume = true;
|
|
224
|
-
return {
|
|
225
|
-
...assistant,
|
|
226
|
-
content,
|
|
227
|
-
status: {
|
|
228
|
-
type: "complete",
|
|
229
|
-
reason: "unknown"
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
223
|
return {
|
|
234
224
|
...assistant,
|
|
235
225
|
content
|
|
236
226
|
};
|
|
237
227
|
});
|
|
238
|
-
if (updated)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
228
|
+
if (!updated) return;
|
|
229
|
+
this.notifyUpdate();
|
|
230
|
+
this.maybeResumeAfterToolResults(options.messageId);
|
|
231
|
+
}
|
|
232
|
+
maybeResumeAfterToolResults(messageId) {
|
|
233
|
+
const message = this.messages.find((m) => m.id === messageId);
|
|
234
|
+
if (!message || message.role !== "assistant") return;
|
|
235
|
+
const assistant = message;
|
|
236
|
+
if (assistant.status?.type !== "requires-action" || assistant.status.reason !== "tool-calls") return;
|
|
237
|
+
if (!assistant.content.every((part) => part.type !== "tool-call" || "result" in part && part.result !== void 0)) return;
|
|
238
|
+
this.messages = this.messages.map((m) => m.id === messageId && m.role === "assistant" ? {
|
|
239
|
+
...m,
|
|
240
|
+
status: {
|
|
241
|
+
type: "complete",
|
|
242
|
+
reason: "unknown"
|
|
245
243
|
}
|
|
244
|
+
} : m);
|
|
245
|
+
this.notifyUpdate();
|
|
246
|
+
this.persistAssistantHistory(messageId);
|
|
247
|
+
if (this.isRunningFlag) {
|
|
248
|
+
this.pendingResumeMessageId = messageId;
|
|
249
|
+
return;
|
|
246
250
|
}
|
|
251
|
+
this.startResumeRun(messageId);
|
|
252
|
+
}
|
|
253
|
+
startResumeRun(messageId) {
|
|
254
|
+
this.startRun(messageId, this.lastRunConfig).catch((error) => {
|
|
255
|
+
this.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
256
|
+
});
|
|
247
257
|
}
|
|
248
258
|
applyExternalMessages(messages) {
|
|
249
259
|
this.assistantHistoryParents.clear();
|
|
@@ -256,14 +266,12 @@ var AgUiThreadRuntimeCore = class {
|
|
|
256
266
|
this.stateSnapshot = state;
|
|
257
267
|
this.notifyUpdate();
|
|
258
268
|
}
|
|
259
|
-
async startRun(parentId, runConfig, resume) {
|
|
269
|
+
async startRun(parentId, runConfig, resume, resumeStream) {
|
|
260
270
|
const normalizedRunConfig = runConfig ?? {};
|
|
261
271
|
this.lastRunConfig = normalizedRunConfig;
|
|
262
272
|
this.resetHead(parentId);
|
|
263
273
|
const historicalMessages = [...this.messages];
|
|
264
|
-
const runId = generateId();
|
|
265
274
|
this.pendingError = null;
|
|
266
|
-
const input = this.buildRunInput(runId, normalizedRunConfig, historicalMessages, resume);
|
|
267
275
|
const assistantParentId = parentId ?? this.messages.at(-1)?.id ?? null;
|
|
268
276
|
let assistantMessageId;
|
|
269
277
|
const ensureAssistant = () => {
|
|
@@ -273,13 +281,14 @@ var AgUiThreadRuntimeCore = class {
|
|
|
273
281
|
this.markPendingAssistantHistory(created, assistantParentId ?? null);
|
|
274
282
|
return created;
|
|
275
283
|
};
|
|
284
|
+
const applyUpdate = (update) => {
|
|
285
|
+
const resolved = this.updateAssistantMessage(ensureAssistant(), update);
|
|
286
|
+
if (resolved !== assistantMessageId) assistantMessageId = resolved;
|
|
287
|
+
};
|
|
276
288
|
const aggregator = new RunAggregator({
|
|
277
289
|
showThinking: this.showThinking,
|
|
278
290
|
logger: this.logger,
|
|
279
|
-
emit:
|
|
280
|
-
const resolved = this.updateAssistantMessage(ensureAssistant(), update);
|
|
281
|
-
if (resolved !== assistantMessageId) assistantMessageId = resolved;
|
|
282
|
-
},
|
|
291
|
+
emit: applyUpdate,
|
|
283
292
|
onServerMessageId: (serverId) => {
|
|
284
293
|
const placeholder = ensureAssistant();
|
|
285
294
|
if (placeholder === serverId) return;
|
|
@@ -291,32 +300,52 @@ var AgUiThreadRuntimeCore = class {
|
|
|
291
300
|
const abortController = new AbortController();
|
|
292
301
|
const abortSignal = abortController.signal;
|
|
293
302
|
this.abortController = abortController;
|
|
303
|
+
let cancelRun = () => dispatch({ type: "RUN_CANCELLED" });
|
|
294
304
|
abortSignal.addEventListener("abort", () => {
|
|
295
|
-
|
|
305
|
+
cancelRun();
|
|
296
306
|
this.finishRun(abortController);
|
|
297
307
|
this.onCancel?.();
|
|
298
308
|
}, { once: true });
|
|
299
|
-
const subscriber = createAgUiSubscriber({
|
|
300
|
-
dispatch,
|
|
301
|
-
runId,
|
|
302
|
-
logger: this.logger,
|
|
303
|
-
onRunFailed: (error) => {
|
|
304
|
-
this.pendingError = error;
|
|
305
|
-
this.onError?.(error);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
aggregator.handle({
|
|
309
|
-
type: "RUN_STARTED",
|
|
310
|
-
runId
|
|
311
|
-
});
|
|
312
309
|
this.setRunning(true);
|
|
313
310
|
try {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
311
|
+
if (resumeStream) {
|
|
312
|
+
cancelRun = () => applyUpdate({ status: {
|
|
313
|
+
type: "incomplete",
|
|
314
|
+
reason: "cancelled"
|
|
315
|
+
} });
|
|
316
|
+
await this.consumeResumeStream(resumeStream, {
|
|
317
|
+
runConfig: normalizedRunConfig,
|
|
318
|
+
threadId: this.agent.threadId || "main",
|
|
319
|
+
parentId: assistantParentId,
|
|
320
|
+
historicalMessages,
|
|
321
|
+
abortSignal,
|
|
322
|
+
ensureAssistant,
|
|
323
|
+
applyUpdate,
|
|
324
|
+
getAssistantMessageId: () => assistantMessageId
|
|
325
|
+
});
|
|
326
|
+
} else {
|
|
327
|
+
const runId = generateId();
|
|
328
|
+
aggregator.handle({
|
|
329
|
+
type: "RUN_STARTED",
|
|
330
|
+
runId
|
|
331
|
+
});
|
|
332
|
+
const input = this.buildRunInput(runId, normalizedRunConfig, historicalMessages, resume);
|
|
333
|
+
const subscriber = createAgUiSubscriber({
|
|
334
|
+
dispatch,
|
|
335
|
+
runId,
|
|
336
|
+
logger: this.logger,
|
|
337
|
+
onRunFailed: (error) => {
|
|
338
|
+
this.pendingError = error;
|
|
339
|
+
this.onError?.(error);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
try {
|
|
343
|
+
this.agent.messages = input.messages;
|
|
344
|
+
this.agent.threadId = input.threadId;
|
|
345
|
+
this.agent.state = input.state ?? null;
|
|
346
|
+
} catch {}
|
|
347
|
+
await this.agent.runAgent(input, subscriber, { signal: abortSignal });
|
|
348
|
+
}
|
|
320
349
|
} catch (error) {
|
|
321
350
|
if (!abortSignal.aborted) {
|
|
322
351
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
@@ -333,8 +362,55 @@ var AgUiThreadRuntimeCore = class {
|
|
|
333
362
|
if (this.pendingError) {
|
|
334
363
|
const err = this.pendingError;
|
|
335
364
|
this.pendingError = null;
|
|
365
|
+
this.pendingResumeMessageId = null;
|
|
336
366
|
throw err;
|
|
337
367
|
}
|
|
368
|
+
if (this.pendingResumeMessageId !== null) {
|
|
369
|
+
const resumeMessageId = this.pendingResumeMessageId;
|
|
370
|
+
this.pendingResumeMessageId = null;
|
|
371
|
+
if (!abortSignal.aborted) this.startResumeRun(resumeMessageId);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async consumeResumeStream(stream, ctx) {
|
|
375
|
+
const assistantId = ctx.ensureAssistant();
|
|
376
|
+
const currentId = () => ctx.getAssistantMessageId() ?? assistantId;
|
|
377
|
+
const options = {
|
|
378
|
+
messages: ctx.historicalMessages,
|
|
379
|
+
runConfig: ctx.runConfig,
|
|
380
|
+
abortSignal: ctx.abortSignal,
|
|
381
|
+
context: this.runtime?.thread.getModelContext() ?? {},
|
|
382
|
+
unstable_assistantMessageId: assistantId,
|
|
383
|
+
unstable_threadId: ctx.threadId,
|
|
384
|
+
unstable_parentId: ctx.parentId,
|
|
385
|
+
unstable_getMessage: () => {
|
|
386
|
+
const message = this.messages.find((m) => m.id === currentId());
|
|
387
|
+
if (!message) throw new Error("[agui] resume stream requested the assistant message before it existed");
|
|
388
|
+
return message;
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
try {
|
|
392
|
+
for await (const result of stream(options)) {
|
|
393
|
+
if (ctx.abortSignal.aborted) return;
|
|
394
|
+
ctx.applyUpdate(result);
|
|
395
|
+
}
|
|
396
|
+
} catch (error) {
|
|
397
|
+
if (ctx.abortSignal.aborted) return;
|
|
398
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
399
|
+
ctx.applyUpdate({ status: {
|
|
400
|
+
type: "incomplete",
|
|
401
|
+
reason: "error",
|
|
402
|
+
error: err.message
|
|
403
|
+
} });
|
|
404
|
+
this.onError?.(err);
|
|
405
|
+
this.pendingError = this.pendingError ?? err;
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (ctx.abortSignal.aborted) return;
|
|
409
|
+
const current = this.messages.find((m) => m.id === currentId());
|
|
410
|
+
if (!current || current.status?.type === "running") ctx.applyUpdate({ status: {
|
|
411
|
+
type: "complete",
|
|
412
|
+
reason: "unknown"
|
|
413
|
+
} });
|
|
338
414
|
}
|
|
339
415
|
buildRunInput(runId, runConfig, historyMessages, resume) {
|
|
340
416
|
const threadId = this.agent.threadId || "main";
|
|
@@ -433,9 +509,10 @@ var AgUiThreadRuntimeCore = class {
|
|
|
433
509
|
const assistant = message;
|
|
434
510
|
const metadata = update.metadata ? this.mergeAssistantMetadata(assistant.metadata, update.metadata) : assistant.metadata;
|
|
435
511
|
latestStatus = update.status ?? assistant.status;
|
|
512
|
+
const content = update.content !== void 0 ? this.preserveToolResults(assistant.content, update.content) : assistant.content;
|
|
436
513
|
return {
|
|
437
514
|
...assistant,
|
|
438
|
-
content
|
|
515
|
+
content,
|
|
439
516
|
status: latestStatus,
|
|
440
517
|
metadata
|
|
441
518
|
};
|
|
@@ -448,8 +525,29 @@ var AgUiThreadRuntimeCore = class {
|
|
|
448
525
|
resolvedMessageId = stableId;
|
|
449
526
|
} else this.notifyUpdate();
|
|
450
527
|
if (this.isPersistableStatus(latestStatus)) this.persistAssistantHistory(resolvedMessageId);
|
|
528
|
+
this.maybeResumeAfterToolResults(resolvedMessageId);
|
|
451
529
|
return resolvedMessageId;
|
|
452
530
|
}
|
|
531
|
+
preserveToolResults(previous, next) {
|
|
532
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
533
|
+
for (const part of previous) if (part.type === "tool-call" && "result" in part && part.result !== void 0) resolved.set(part.toolCallId, part);
|
|
534
|
+
if (resolved.size === 0) return next;
|
|
535
|
+
let changed = false;
|
|
536
|
+
const merged = next.map((part) => {
|
|
537
|
+
if (part.type !== "tool-call") return part;
|
|
538
|
+
if ("result" in part && part.result !== void 0) return part;
|
|
539
|
+
const prior = resolved.get(part.toolCallId);
|
|
540
|
+
if (!prior) return part;
|
|
541
|
+
changed = true;
|
|
542
|
+
return {
|
|
543
|
+
...part,
|
|
544
|
+
result: prior.result,
|
|
545
|
+
...prior.artifact !== void 0 ? { artifact: prior.artifact } : {},
|
|
546
|
+
...prior.isError !== void 0 ? { isError: prior.isError } : {}
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
return changed ? merged : next;
|
|
550
|
+
}
|
|
453
551
|
mergeAssistantMetadata(current, incoming) {
|
|
454
552
|
const annotations = incoming.unstable_annotations ? [...current.unstable_annotations, ...incoming.unstable_annotations] : current.unstable_annotations;
|
|
455
553
|
const data = incoming.unstable_data ? [...current.unstable_data, ...incoming.unstable_data] : current.unstable_data;
|
|
@@ -473,7 +571,15 @@ var AgUiThreadRuntimeCore = class {
|
|
|
473
571
|
this.notifyUpdate();
|
|
474
572
|
return;
|
|
475
573
|
case "STATE_DELTA":
|
|
476
|
-
|
|
574
|
+
if (event.delta.length === 0) return;
|
|
575
|
+
try {
|
|
576
|
+
const state = this.stateSnapshot ?? {};
|
|
577
|
+
const result = jsonpatch.applyPatch(state, event.delta, true, false);
|
|
578
|
+
this.stateSnapshot = result.newDocument;
|
|
579
|
+
this.notifyUpdate();
|
|
580
|
+
} catch (error) {
|
|
581
|
+
this.logger.error?.("[agui] failed to apply state delta", error);
|
|
582
|
+
}
|
|
477
583
|
return;
|
|
478
584
|
case "MESSAGES_SNAPSHOT":
|
|
479
585
|
this.importMessagesSnapshot(event.messages);
|
|
@@ -483,7 +589,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
483
589
|
}
|
|
484
590
|
importMessagesSnapshot(rawMessages) {
|
|
485
591
|
try {
|
|
486
|
-
const normalized = fromAgUiMessages(rawMessages);
|
|
592
|
+
const normalized = fromAgUiMessages(rawMessages, { showThinking: this.showThinking });
|
|
487
593
|
const converted = [];
|
|
488
594
|
for (const message of normalized) try {
|
|
489
595
|
converted.push(fromThreadMessageLike(message, generateId(), FALLBACK_USER_STATUS));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgUiThreadRuntimeCore.js","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"sourcesContent":["\"use client\";\n\nimport { generateId, fromThreadMessageLike } from \"@assistant-ui/core/internal\";\nimport type {\n AddToolResultOptions,\n AppendMessage,\n AssistantRuntime,\n ChatModelRunResult,\n MessageStatus,\n ThreadAssistantMessage,\n ThreadHistoryAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport type { HttpAgent } from \"@ag-ui/client\";\nimport type { Logger } from \"./logger\";\nimport type { AgUiEvent, AgUiInterrupt, AgUiResumeEntry } from \"./types\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport {\n AG_UI_METADATA_NAMESPACE,\n type AgUiCustomMetadata,\n RunAggregator,\n} from \"./adapter/run-aggregator\";\nimport {\n fromAgUiMessages,\n toAgUiMessages,\n toAgUiTools,\n} from \"./adapter/conversions\";\nimport { createAgUiSubscriber } from \"./adapter/subscriber\";\n\nconst optimisticPrefix = \"__optimistic__\";\nconst generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;\nconst isOptimisticId = (id: string) => id.startsWith(optimisticPrefix);\n\nconst symbolResumeShim = Symbol(\"agui-resume-shim\");\n\ntype RunConfig = NonNullable<AppendMessage[\"runConfig\"]>;\ntype ResumeRunConfig = {\n parentId: string | null;\n sourceId: string | null;\n runConfig: RunConfig;\n stream?: unknown;\n};\n\ntype CoreOptions = {\n agent: HttpAgent;\n logger: Logger;\n showThinking: boolean;\n onError?: (error: Error) => void;\n onCancel?: () => void;\n history?: ThreadHistoryAdapter;\n notifyUpdate: () => void;\n};\n\nconst FALLBACK_USER_STATUS = { type: \"complete\", reason: \"unknown\" } as const;\n\nexport class AgUiThreadRuntimeCore {\n private agent: HttpAgent;\n private logger: Logger;\n private showThinking: boolean;\n private onError: ((error: Error) => void) | undefined;\n private onCancel: (() => void) | undefined;\n private readonly notifyUpdate: () => void;\n\n private runtime: AssistantRuntime | undefined;\n private messages: ThreadMessage[] = [];\n private isRunningFlag = false;\n private abortController: AbortController | null = null;\n private stateSnapshot: ReadonlyJSONValue | undefined;\n private pendingError: Error | null = null;\n private history: ThreadHistoryAdapter | undefined;\n private lastRunConfig: RunConfig | undefined;\n private readonly assistantHistoryParents = new Map<string, string | null>();\n private readonly recordedHistoryIds = new Set<string>();\n private _isLoading = false;\n private _loadPromise: Promise<void> | undefined;\n\n constructor(options: CoreOptions) {\n this.agent = options.agent;\n this.logger = options.logger;\n this.showThinking = options.showThinking;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.history = options.history;\n this.notifyUpdate = options.notifyUpdate;\n this.installResumeShim();\n }\n\n updateOptions(options: Omit<CoreOptions, \"notifyUpdate\">) {\n this.agent = options.agent;\n this.logger = options.logger;\n this.showThinking = options.showThinking;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.history = options.history;\n this.installResumeShim();\n }\n\n attachRuntime(runtime: AssistantRuntime) {\n this.runtime = runtime;\n }\n\n detachRuntime() {\n this.runtime = undefined;\n }\n\n getMessages(): readonly ThreadMessage[] {\n return this.messages;\n }\n\n getState(): ReadonlyJSONValue | undefined {\n return this.stateSnapshot;\n }\n\n isRunning(): boolean {\n return this.isRunningFlag;\n }\n\n get isLoading(): boolean {\n return this._isLoading;\n }\n\n __internal_load(): Promise<void> {\n if (this._loadPromise) return this._loadPromise;\n\n const promise = this.history?.load() ?? Promise.resolve(null);\n\n this._isLoading = true;\n\n this._loadPromise = promise\n .then(async (repo) => {\n if (!repo) return;\n\n const messages = repo.messages.map((item) => item.message);\n this.applyExternalMessages(messages);\n\n if (repo.unstable_resume) {\n const parentId = repo.headId ?? messages.at(-1)?.id ?? null;\n await this.startRun(parentId, this.lastRunConfig);\n }\n })\n .catch((error) => {\n this.logger.error?.(\"[agui] failed to load history\", error);\n this.onError?.(\n error instanceof Error ? error : new Error(String(error)),\n );\n })\n .finally(() => {\n this._isLoading = false;\n this.notifyUpdate();\n });\n\n this.notifyUpdate();\n return this._loadPromise;\n }\n\n async append(message: AppendMessage): Promise<void> {\n const startRun = message.startRun ?? message.role === \"user\";\n if (startRun) this.assertNoPendingInterrupts();\n if (message.sourceId) {\n this.messages = this.messages.filter(\n (entry) => entry.id !== message.sourceId,\n );\n }\n this.resetHead(message.parentId);\n\n const threadMessage = this.toThreadMessage(message);\n this.messages = [...this.messages, threadMessage];\n this.notifyUpdate();\n this.recordHistoryEntry(message.parentId ?? null, threadMessage);\n\n if (!startRun) return;\n await this.startRun(threadMessage.id, message.runConfig);\n }\n\n async edit(message: AppendMessage): Promise<void> {\n await this.append(message);\n }\n\n async reload(\n parentId: string | null,\n config: { runConfig?: RunConfig } = {},\n ): Promise<void> {\n this.assertNoPendingInterrupts();\n this.resetHead(parentId);\n this.notifyUpdate();\n await this.startRun(parentId, config.runConfig);\n }\n\n async cancel(): Promise<void> {\n if (!this.abortController) return;\n this.abortController.abort();\n }\n\n async resume(config: ResumeRunConfig): Promise<void> {\n this.assertNoPendingInterrupts();\n if (config.stream) {\n this.logger.debug?.(\n \"[agui] resume stream is not supported, falling back to regular run\",\n );\n }\n await this.startRun(\n config.parentId,\n config.runConfig ?? this.lastRunConfig,\n );\n }\n\n private assertNoPendingInterrupts(): void {\n if (!this.getPendingInterrupts()) return;\n throw new Error(\n \"[agui] cannot start a new run while interrupts are pending; resolve them with submitInterruptResponses()\",\n );\n }\n\n getPendingInterrupts(): {\n messageId: string;\n interrupts: readonly AgUiInterrupt[];\n } | null {\n const assistant = this.messages.findLast((m) => m.role === \"assistant\") as\n | ThreadAssistantMessage\n | undefined;\n if (\n !assistant ||\n assistant.status?.type !== \"requires-action\" ||\n assistant.status.reason !== \"interrupt\"\n ) {\n return null;\n }\n const stored = (\n assistant.metadata.custom[AG_UI_METADATA_NAMESPACE] as\n | AgUiCustomMetadata\n | undefined\n )?.interrupts;\n if (!stored?.length) return null;\n return { messageId: assistant.id, interrupts: stored };\n }\n\n async submitInterruptResponses(\n responses: readonly AgUiResumeEntry[],\n ): Promise<void> {\n const pending = this.getPendingInterrupts();\n if (!pending) {\n throw new Error(\n \"[agui] submitInterruptResponses: no pending interrupts on this thread\",\n );\n }\n\n const responsesById = new Map<string, AgUiResumeEntry>();\n for (const entry of responses) {\n if (!entry || typeof entry.interruptId !== \"string\") {\n throw new Error(\n \"[agui] submitInterruptResponses: every entry must have an interruptId\",\n );\n }\n if (entry.status !== \"resolved\" && entry.status !== \"cancelled\") {\n throw new Error(\n `[agui] submitInterruptResponses: invalid status \"${entry.status}\" for interrupt ${entry.interruptId}`,\n );\n }\n if (responsesById.has(entry.interruptId)) {\n throw new Error(\n `[agui] submitInterruptResponses: duplicate response for interrupt ${entry.interruptId}`,\n );\n }\n responsesById.set(entry.interruptId, entry);\n }\n\n const openIds = pending.interrupts.map((i) => i.id);\n const missing = openIds.filter((id) => !responsesById.has(id));\n if (missing.length > 0) {\n throw new Error(\n `[agui] submitInterruptResponses: missing responses for open interrupts: ${missing.join(\", \")}`,\n );\n }\n const known = new Set(openIds);\n const unknownIds = [...responsesById.keys()].filter((id) => !known.has(id));\n if (unknownIds.length > 0) {\n throw new Error(\n `[agui] submitInterruptResponses: unknown interrupt ids: ${unknownIds.join(\", \")}`,\n );\n }\n\n const now = Date.now();\n for (const interrupt of pending.interrupts) {\n if (!interrupt.expiresAt) continue;\n const expiry = new Date(interrupt.expiresAt).getTime();\n if (Number.isNaN(expiry)) {\n throw new Error(\n `[agui] submitInterruptResponses: interrupt ${interrupt.id} has malformed expiresAt \"${interrupt.expiresAt}\"`,\n );\n }\n if (expiry <= now) {\n throw new Error(\n `[agui] submitInterruptResponses: interrupt ${interrupt.id} expired at ${interrupt.expiresAt}`,\n );\n }\n }\n\n const resume: AgUiResumeEntry[] = openIds.map(\n (id) => responsesById.get(id)!,\n );\n\n if (this.isRunningFlag) {\n throw new Error(\n \"[agui] submitInterruptResponses: a run is already in progress\",\n );\n }\n\n this.clearPendingInterrupts(pending.messageId);\n await this.startRun(pending.messageId, this.lastRunConfig, resume);\n }\n\n private clearPendingInterrupts(messageId: string): void {\n let touched = false;\n this.messages = this.messages.map((message) => {\n if (message.id !== messageId || message.role !== \"assistant\")\n return message;\n const assistant = message as ThreadAssistantMessage;\n if (\n assistant.status?.type !== \"requires-action\" ||\n assistant.status.reason !== \"interrupt\"\n ) {\n return assistant;\n }\n touched = true;\n const aguiMeta = assistant.metadata.custom[AG_UI_METADATA_NAMESPACE] as\n | AgUiCustomMetadata\n | undefined;\n const { interrupts: _drop, ...restAgui } = aguiMeta ?? {};\n const newCustom = { ...assistant.metadata.custom };\n if (Object.keys(restAgui).length > 0) {\n newCustom[AG_UI_METADATA_NAMESPACE] = restAgui;\n } else {\n delete newCustom[AG_UI_METADATA_NAMESPACE];\n }\n return {\n ...assistant,\n status: { type: \"complete\" as const, reason: \"unknown\" as const },\n metadata: { ...assistant.metadata, custom: newCustom },\n };\n });\n if (touched) this.notifyUpdate();\n }\n\n findMessageIdForToolCall(toolCallId: string): string | undefined {\n let fallbackMessageId: string | undefined;\n for (let index = this.messages.length - 1; index >= 0; index--) {\n const message = this.messages[index];\n if (!message || message.role !== \"assistant\") continue;\n for (const part of message.content) {\n if (part.type !== \"tool-call\" || part.toolCallId !== toolCallId)\n continue;\n if (!(\"result\" in part) || part.result === undefined) {\n return message.id;\n }\n fallbackMessageId ??= message.id;\n }\n }\n return fallbackMessageId;\n }\n\n addToolResult(options: AddToolResultOptions): void {\n let updated = false;\n let shouldResume = false;\n this.messages = this.messages.map((message) => {\n if (message.id !== options.messageId || message.role !== \"assistant\")\n return message;\n const assistant = message as ThreadAssistantMessage;\n let matchedToolCall = false;\n const content = assistant.content.map((part) => {\n if (part.type !== \"tool-call\" || part.toolCallId !== options.toolCallId)\n return part;\n matchedToolCall = true;\n return {\n ...part,\n result: options.result,\n artifact: options.artifact,\n isError: options.isError,\n };\n });\n if (!matchedToolCall) return message;\n updated = true;\n\n if (\n assistant.status?.type === \"requires-action\" &&\n assistant.status.reason === \"tool-calls\" &&\n content.every(\n (part) =>\n part.type !== \"tool-call\" ||\n (\"result\" in part && part.result !== undefined),\n )\n ) {\n shouldResume = true;\n return {\n ...assistant,\n content,\n status: { type: \"complete\" as const, reason: \"unknown\" as const },\n };\n }\n\n return {\n ...assistant,\n content,\n };\n });\n\n if (updated) {\n this.notifyUpdate();\n\n if (shouldResume) {\n this.persistAssistantHistory(options.messageId);\n\n if (!this.isRunningFlag) {\n void this.startRun(options.messageId, this.lastRunConfig).catch(\n (error) => {\n this.onError?.(\n error instanceof Error ? error : new Error(String(error)),\n );\n },\n );\n }\n }\n }\n }\n\n applyExternalMessages(messages: readonly ThreadMessage[]): void {\n this.assistantHistoryParents.clear();\n this.messages = [...messages];\n this.recordedHistoryIds.clear();\n for (const message of this.messages) {\n this.recordedHistoryIds.add(message.id);\n }\n this.notifyUpdate();\n }\n\n loadExternalState(state: ReadonlyJSONValue): void {\n this.stateSnapshot = state;\n this.notifyUpdate();\n }\n\n private async startRun(\n parentId: string | null,\n runConfig?: RunConfig,\n resume?: AgUiResumeEntry[],\n ): Promise<void> {\n const normalizedRunConfig = runConfig ?? {};\n this.lastRunConfig = normalizedRunConfig;\n this.resetHead(parentId);\n const historicalMessages = [...this.messages];\n\n const runId = generateId();\n this.pendingError = null;\n const input = this.buildRunInput(\n runId,\n normalizedRunConfig,\n historicalMessages,\n resume,\n );\n const assistantParentId = parentId ?? this.messages.at(-1)?.id ?? null;\n let assistantMessageId: string | undefined;\n const ensureAssistant = () => {\n if (assistantMessageId) return assistantMessageId;\n const created = this.insertAssistantPlaceholder();\n assistantMessageId = created;\n this.markPendingAssistantHistory(created, assistantParentId ?? null);\n return created;\n };\n\n const aggregator = new RunAggregator({\n showThinking: this.showThinking,\n logger: this.logger,\n emit: (update) => {\n const resolved = this.updateAssistantMessage(ensureAssistant(), update);\n if (resolved !== assistantMessageId) {\n assistantMessageId = resolved;\n }\n },\n onServerMessageId: (serverId) => {\n const placeholder = ensureAssistant();\n if (placeholder === serverId) return;\n this.reassignAssistantId(placeholder, serverId);\n assistantMessageId = serverId;\n },\n });\n const dispatch = (event: AgUiEvent) => this.handleEvent(aggregator, event);\n\n const abortController = new AbortController();\n const abortSignal = abortController.signal;\n this.abortController = abortController;\n\n abortSignal.addEventListener(\n \"abort\",\n () => {\n dispatch({ type: \"RUN_CANCELLED\" });\n this.finishRun(abortController);\n this.onCancel?.();\n },\n { once: true },\n );\n\n const subscriber = createAgUiSubscriber({\n dispatch,\n runId,\n logger: this.logger,\n onRunFailed: (error) => {\n this.pendingError = error;\n this.onError?.(error);\n },\n });\n\n aggregator.handle({ type: \"RUN_STARTED\", runId });\n this.setRunning(true);\n\n try {\n try {\n (this.agent as any).messages = input.messages;\n (this.agent as any).threadId = input.threadId;\n (this.agent as any).state = input.state ?? null;\n } catch {\n // ignore\n }\n await (this.agent as any).runAgent(input, subscriber, {\n signal: abortSignal,\n });\n } catch (error) {\n if (!abortSignal.aborted) {\n const err = error instanceof Error ? error : new Error(String(error));\n dispatch({ type: \"RUN_ERROR\", message: err.message });\n this.onError?.(err);\n this.pendingError = this.pendingError ?? err;\n }\n } finally {\n this.finishRun(abortController);\n }\n\n if (this.pendingError) {\n const err = this.pendingError;\n this.pendingError = null;\n throw err;\n }\n }\n\n private buildRunInput(\n runId: string,\n runConfig: RunConfig | undefined,\n historyMessages: readonly ThreadMessage[] | undefined,\n resume?: AgUiResumeEntry[],\n ) {\n const threadId = this.agent.threadId || \"main\";\n const messages = toAgUiMessages(historyMessages ?? this.messages);\n const context = this.runtime?.thread.getModelContext();\n return {\n threadId,\n runId,\n state: this.stateSnapshot ?? null,\n messages,\n tools: toAgUiTools(context?.tools),\n context: context?.system\n ? [{ description: \"system\", value: context.system }]\n : [],\n forwardedProps: {\n ...(context?.callSettings ?? {}),\n ...(context?.config ?? {}),\n ...(runConfig?.custom ? { runConfig: runConfig.custom } : {}),\n },\n ...(resume !== undefined ? { resume } : {}),\n };\n }\n\n private installResumeShim(): void {\n const agent = this.agent as any;\n if (agent[symbolResumeShim]) return;\n agent[symbolResumeShim] = true;\n const onInstance = Object.hasOwn(agent, \"prepareRunAgentInput\");\n const original = onInstance\n ? agent.prepareRunAgentInput\n : Object.getPrototypeOf(agent)?.prepareRunAgentInput;\n if (typeof original !== \"function\") return;\n agent.prepareRunAgentInput = function (\n this: unknown,\n params: { resume?: unknown } | undefined,\n ) {\n const input = original.call(this, params);\n if (params?.resume !== undefined && input && typeof input === \"object\") {\n return { ...(input as object), resume: params.resume };\n }\n return input;\n };\n }\n\n private setRunning(running: boolean) {\n this.isRunningFlag = running;\n this.notifyUpdate();\n }\n\n private finishRun(controller: AbortController | null) {\n if (this.abortController === controller) {\n this.abortController = null;\n }\n this.setRunning(false);\n }\n\n private insertAssistantPlaceholder(): string {\n const id = generateOptimisticId();\n const assistant: ThreadAssistantMessage = {\n id,\n role: \"assistant\",\n createdAt: new Date(),\n status: { type: \"running\" },\n content: [],\n metadata: {\n unstable_state: this.stateSnapshot ?? null,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n custom: {},\n },\n };\n this.messages = [...this.messages, assistant];\n this.notifyUpdate();\n return id;\n }\n\n private reassignAssistantId(oldId: string, newId: string): void {\n if (oldId === newId) return;\n\n const collidesWithExisting = this.messages.some((m) => m.id === newId);\n\n if (collidesWithExisting) {\n this.logger.debug?.(\n \"[agui] reassignAssistantId: server id already present in messages, dropping placeholder\",\n { oldId, newId },\n );\n this.messages = this.messages.filter((m) => m.id !== oldId);\n } else {\n this.messages = this.messages.map((m) =>\n m.id === oldId ? { ...m, id: newId } : m,\n );\n }\n\n const pendingParent = this.assistantHistoryParents.get(oldId);\n if (pendingParent !== undefined) {\n this.assistantHistoryParents.delete(oldId);\n if (!this.assistantHistoryParents.has(newId)) {\n this.assistantHistoryParents.set(newId, pendingParent);\n }\n }\n\n if (this.recordedHistoryIds.has(oldId)) {\n this.recordedHistoryIds.delete(oldId);\n this.recordedHistoryIds.add(newId);\n }\n\n this.notifyUpdate();\n }\n\n private updateAssistantMessage(\n messageId: string,\n update: ChatModelRunResult,\n ): string {\n let touched = false;\n let latestStatus: MessageStatus | undefined;\n this.messages = this.messages.map((message) => {\n if (message.id !== messageId || message.role !== \"assistant\")\n return message;\n touched = true;\n const assistant = message as ThreadAssistantMessage;\n const metadata = update.metadata\n ? this.mergeAssistantMetadata(assistant.metadata, update.metadata)\n : assistant.metadata;\n latestStatus = update.status ?? assistant.status;\n return {\n ...assistant,\n content: (update.content ??\n assistant.content) as ThreadAssistantMessage[\"content\"],\n status: latestStatus,\n metadata,\n };\n });\n if (!touched) return messageId;\n\n let resolvedMessageId = messageId;\n const isSettled =\n latestStatus !== undefined && latestStatus.type !== \"running\";\n if (isSettled && isOptimisticId(messageId)) {\n const stableId = generateId();\n this.reassignAssistantId(messageId, stableId);\n resolvedMessageId = stableId;\n } else {\n this.notifyUpdate();\n }\n if (this.isPersistableStatus(latestStatus)) {\n this.persistAssistantHistory(resolvedMessageId);\n }\n return resolvedMessageId;\n }\n\n private mergeAssistantMetadata(\n current: ThreadAssistantMessage[\"metadata\"],\n incoming: NonNullable<ChatModelRunResult[\"metadata\"]>,\n ): ThreadAssistantMessage[\"metadata\"] {\n const annotations = incoming.unstable_annotations\n ? [...current.unstable_annotations, ...incoming.unstable_annotations]\n : current.unstable_annotations;\n const data = incoming.unstable_data\n ? [...current.unstable_data, ...incoming.unstable_data]\n : current.unstable_data;\n const steps = incoming.steps\n ? [...current.steps, ...incoming.steps]\n : current.steps;\n return {\n unstable_state:\n incoming.unstable_state !== undefined\n ? incoming.unstable_state\n : current.unstable_state,\n unstable_annotations: annotations,\n unstable_data: data,\n steps,\n ...(incoming.timing ? { timing: incoming.timing } : {}),\n custom: incoming.custom\n ? { ...current.custom, ...incoming.custom }\n : current.custom,\n };\n }\n\n private handleEvent(aggregator: RunAggregator, event: AgUiEvent) {\n switch (event.type) {\n case \"STATE_SNAPSHOT\": {\n this.stateSnapshot = event.snapshot as ReadonlyJSONValue;\n this.notifyUpdate();\n return;\n }\n case \"STATE_DELTA\": {\n this.logger.debug?.(\"[agui] state delta event ignored\", event.delta);\n return;\n }\n case \"MESSAGES_SNAPSHOT\": {\n this.importMessagesSnapshot(event.messages);\n return;\n }\n default:\n aggregator.handle(event);\n }\n }\n\n private importMessagesSnapshot(rawMessages: readonly unknown[]) {\n try {\n const normalized = fromAgUiMessages(rawMessages);\n const converted: ThreadMessage[] = [];\n for (const message of normalized) {\n try {\n converted.push(\n fromThreadMessageLike(\n message as any,\n generateId(),\n FALLBACK_USER_STATUS,\n ),\n );\n } catch (error) {\n this.logger.error?.(\n \"[agui] failed to import message from snapshot\",\n error,\n );\n }\n }\n this.applyExternalMessages(converted);\n } catch (error) {\n this.logger.error?.(\"[agui] failed to import messages snapshot\", error);\n }\n }\n\n private toThreadMessage(message: AppendMessage): ThreadMessage {\n return fromThreadMessageLike(\n message as any,\n generateId(),\n FALLBACK_USER_STATUS,\n );\n }\n\n private resetHead(parentId: string | null | undefined) {\n if (!parentId) {\n if (this.messages.length) {\n this.messages = [];\n }\n return;\n }\n const idx = this.messages.findIndex((message) => message.id === parentId);\n if (idx === -1) return;\n this.messages = this.messages.slice(0, idx + 1);\n }\n\n private isTerminalStatus(status?: MessageStatus): boolean {\n return status?.type === \"complete\" || status?.type === \"incomplete\";\n }\n\n private isPersistableStatus(status?: MessageStatus): boolean {\n if (this.isTerminalStatus(status)) return true;\n return status?.type === \"requires-action\" && status.reason === \"interrupt\";\n }\n\n private recordHistoryEntry(parentId: string | null, message: ThreadMessage) {\n this.appendHistoryItem(parentId, message);\n }\n\n private markPendingAssistantHistory(\n messageId: string,\n parentId: string | null,\n ) {\n if (!this.history) return;\n this.assistantHistoryParents.set(messageId, parentId);\n }\n\n private persistAssistantHistory(messageId: string) {\n if (!this.history) return;\n const parentId = this.assistantHistoryParents.get(messageId);\n if (parentId === undefined) return;\n const message = this.messages.find((m) => m.id === messageId);\n if (!message || message.role !== \"assistant\") return;\n if (!this.isPersistableStatus(message.status)) return;\n this.assistantHistoryParents.delete(messageId);\n this.appendHistoryItem(parentId, message);\n }\n\n private appendHistoryItem(parentId: string | null, message: ThreadMessage) {\n if (!this.history || this.recordedHistoryIds.has(message.id)) return;\n this.recordedHistoryIds.add(message.id);\n void this.history.append({ parentId, message }).catch((error) => {\n this.recordedHistoryIds.delete(message.id);\n this.logger.error?.(\"[agui] failed to append history entry\", error);\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgUiThreadRuntimeCore.js","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"sourcesContent":["\"use client\";\n\nimport { generateId, fromThreadMessageLike } from \"@assistant-ui/core/internal\";\nimport type {\n AddToolResultOptions,\n AppendMessage,\n AssistantRuntime,\n ChatModelRunOptions,\n ChatModelRunResult,\n MessageStatus,\n ThreadAssistantMessage,\n ThreadHistoryAdapter,\n ThreadMessage,\n ToolCallMessagePart,\n} from \"@assistant-ui/core\";\nimport type { HttpAgent } from \"@ag-ui/client\";\nimport jsonpatch, { type Operation } from \"fast-json-patch\";\nimport type { Logger } from \"./logger\";\nimport type { AgUiEvent, AgUiInterrupt, AgUiResumeEntry } from \"./types\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport {\n AG_UI_METADATA_NAMESPACE,\n type AgUiCustomMetadata,\n RunAggregator,\n} from \"./adapter/run-aggregator\";\nimport {\n fromAgUiMessages,\n toAgUiMessages,\n toAgUiTools,\n} from \"./adapter/conversions\";\nimport { createAgUiSubscriber } from \"./adapter/subscriber\";\n\nconst optimisticPrefix = \"__optimistic__\";\nconst generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;\nconst isOptimisticId = (id: string) => id.startsWith(optimisticPrefix);\n\nconst symbolResumeShim = Symbol(\"agui-resume-shim\");\n\ntype RunConfig = NonNullable<AppendMessage[\"runConfig\"]>;\ntype ResumeStream = (\n options: ChatModelRunOptions,\n) => AsyncGenerator<ChatModelRunResult, void, unknown>;\ntype ResumeRunConfig = {\n parentId: string | null;\n sourceId: string | null;\n runConfig: RunConfig;\n stream?: ResumeStream;\n};\n\ntype CoreOptions = {\n agent: HttpAgent;\n logger: Logger;\n showThinking: boolean;\n onError?: (error: Error) => void;\n onCancel?: () => void;\n history?: ThreadHistoryAdapter;\n notifyUpdate: () => void;\n};\n\nconst FALLBACK_USER_STATUS = { type: \"complete\", reason: \"unknown\" } as const;\n\nexport class AgUiThreadRuntimeCore {\n private agent: HttpAgent;\n private logger: Logger;\n private showThinking: boolean;\n private onError: ((error: Error) => void) | undefined;\n private onCancel: (() => void) | undefined;\n private readonly notifyUpdate: () => void;\n\n private runtime: AssistantRuntime | undefined;\n private messages: ThreadMessage[] = [];\n private isRunningFlag = false;\n private abortController: AbortController | null = null;\n private stateSnapshot: ReadonlyJSONValue | undefined;\n private pendingError: Error | null = null;\n private history: ThreadHistoryAdapter | undefined;\n private lastRunConfig: RunConfig | undefined;\n private readonly assistantHistoryParents = new Map<string, string | null>();\n private readonly recordedHistoryIds = new Set<string>();\n private _isLoading = false;\n private _loadPromise: Promise<void> | undefined;\n private pendingResumeMessageId: string | null = null;\n\n constructor(options: CoreOptions) {\n this.agent = options.agent;\n this.logger = options.logger;\n this.showThinking = options.showThinking;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.history = options.history;\n this.notifyUpdate = options.notifyUpdate;\n this.installResumeShim();\n }\n\n updateOptions(options: Omit<CoreOptions, \"notifyUpdate\">) {\n this.agent = options.agent;\n this.logger = options.logger;\n this.showThinking = options.showThinking;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.history = options.history;\n this.installResumeShim();\n }\n\n attachRuntime(runtime: AssistantRuntime) {\n this.runtime = runtime;\n }\n\n detachRuntime() {\n this.runtime = undefined;\n }\n\n getMessages(): readonly ThreadMessage[] {\n return this.messages;\n }\n\n getState(): ReadonlyJSONValue | undefined {\n return this.stateSnapshot;\n }\n\n isRunning(): boolean {\n return this.isRunningFlag;\n }\n\n get isLoading(): boolean {\n return this._isLoading;\n }\n\n __internal_load(): Promise<void> {\n if (this._loadPromise) return this._loadPromise;\n\n const promise = this.history?.load() ?? Promise.resolve(null);\n\n this._isLoading = true;\n\n this._loadPromise = promise\n .then(async (repo) => {\n if (!repo) return;\n\n const messages = repo.messages.map((item) => item.message);\n this.applyExternalMessages(messages);\n\n if (repo.unstable_resume) {\n const parentId = repo.headId ?? messages.at(-1)?.id ?? null;\n const resumeStream = this.history?.resume?.bind(this.history);\n await this.startRun(\n parentId,\n this.lastRunConfig,\n undefined,\n resumeStream,\n );\n }\n })\n .catch((error) => {\n this.logger.error?.(\"[agui] failed to load history\", error);\n this.onError?.(\n error instanceof Error ? error : new Error(String(error)),\n );\n })\n .finally(() => {\n this._isLoading = false;\n this.notifyUpdate();\n });\n\n this.notifyUpdate();\n return this._loadPromise;\n }\n\n async append(message: AppendMessage): Promise<void> {\n const startRun = message.startRun ?? message.role === \"user\";\n if (startRun) this.assertNoPendingInterrupts();\n if (message.sourceId) {\n this.messages = this.messages.filter(\n (entry) => entry.id !== message.sourceId,\n );\n }\n this.resetHead(message.parentId);\n\n const threadMessage = this.toThreadMessage(message);\n this.messages = [...this.messages, threadMessage];\n this.notifyUpdate();\n this.recordHistoryEntry(message.parentId ?? null, threadMessage);\n\n if (!startRun) return;\n await this.startRun(threadMessage.id, message.runConfig);\n }\n\n async edit(message: AppendMessage): Promise<void> {\n await this.append(message);\n }\n\n async reload(\n parentId: string | null,\n config: { runConfig?: RunConfig } = {},\n ): Promise<void> {\n this.assertNoPendingInterrupts();\n this.resetHead(parentId);\n this.notifyUpdate();\n await this.startRun(parentId, config.runConfig);\n }\n\n async cancel(): Promise<void> {\n if (!this.abortController) return;\n this.abortController.abort();\n }\n\n async resume(config: ResumeRunConfig): Promise<void> {\n this.assertNoPendingInterrupts();\n await this.startRun(\n config.parentId,\n config.runConfig ?? this.lastRunConfig,\n undefined,\n config.stream,\n );\n }\n\n private assertNoPendingInterrupts(): void {\n if (!this.getPendingInterrupts()) return;\n throw new Error(\n \"[agui] cannot start a new run while interrupts are pending; resolve them with submitInterruptResponses()\",\n );\n }\n\n getPendingInterrupts(): {\n messageId: string;\n interrupts: readonly AgUiInterrupt[];\n } | null {\n const assistant = this.messages.findLast((m) => m.role === \"assistant\") as\n | ThreadAssistantMessage\n | undefined;\n if (\n !assistant ||\n assistant.status?.type !== \"requires-action\" ||\n assistant.status.reason !== \"interrupt\"\n ) {\n return null;\n }\n const stored = (\n assistant.metadata.custom[AG_UI_METADATA_NAMESPACE] as\n | AgUiCustomMetadata\n | undefined\n )?.interrupts;\n if (!stored?.length) return null;\n return { messageId: assistant.id, interrupts: stored };\n }\n\n async submitInterruptResponses(\n responses: readonly AgUiResumeEntry[],\n ): Promise<void> {\n const pending = this.getPendingInterrupts();\n if (!pending) {\n throw new Error(\n \"[agui] submitInterruptResponses: no pending interrupts on this thread\",\n );\n }\n\n const responsesById = new Map<string, AgUiResumeEntry>();\n for (const entry of responses) {\n if (!entry || typeof entry.interruptId !== \"string\") {\n throw new Error(\n \"[agui] submitInterruptResponses: every entry must have an interruptId\",\n );\n }\n if (entry.status !== \"resolved\" && entry.status !== \"cancelled\") {\n throw new Error(\n `[agui] submitInterruptResponses: invalid status \"${entry.status}\" for interrupt ${entry.interruptId}`,\n );\n }\n if (responsesById.has(entry.interruptId)) {\n throw new Error(\n `[agui] submitInterruptResponses: duplicate response for interrupt ${entry.interruptId}`,\n );\n }\n responsesById.set(entry.interruptId, entry);\n }\n\n const openIds = pending.interrupts.map((i) => i.id);\n const missing = openIds.filter((id) => !responsesById.has(id));\n if (missing.length > 0) {\n throw new Error(\n `[agui] submitInterruptResponses: missing responses for open interrupts: ${missing.join(\", \")}`,\n );\n }\n const known = new Set(openIds);\n const unknownIds = [...responsesById.keys()].filter((id) => !known.has(id));\n if (unknownIds.length > 0) {\n throw new Error(\n `[agui] submitInterruptResponses: unknown interrupt ids: ${unknownIds.join(\", \")}`,\n );\n }\n\n const now = Date.now();\n for (const interrupt of pending.interrupts) {\n if (!interrupt.expiresAt) continue;\n const expiry = new Date(interrupt.expiresAt).getTime();\n if (Number.isNaN(expiry)) {\n throw new Error(\n `[agui] submitInterruptResponses: interrupt ${interrupt.id} has malformed expiresAt \"${interrupt.expiresAt}\"`,\n );\n }\n if (expiry <= now) {\n throw new Error(\n `[agui] submitInterruptResponses: interrupt ${interrupt.id} expired at ${interrupt.expiresAt}`,\n );\n }\n }\n\n const resume: AgUiResumeEntry[] = openIds.map(\n (id) => responsesById.get(id)!,\n );\n\n if (this.isRunningFlag) {\n throw new Error(\n \"[agui] submitInterruptResponses: a run is already in progress\",\n );\n }\n\n this.clearPendingInterrupts(pending.messageId);\n await this.startRun(pending.messageId, this.lastRunConfig, resume);\n }\n\n private clearPendingInterrupts(messageId: string): void {\n let touched = false;\n this.messages = this.messages.map((message) => {\n if (message.id !== messageId || message.role !== \"assistant\")\n return message;\n const assistant = message as ThreadAssistantMessage;\n if (\n assistant.status?.type !== \"requires-action\" ||\n assistant.status.reason !== \"interrupt\"\n ) {\n return assistant;\n }\n touched = true;\n const aguiMeta = assistant.metadata.custom[AG_UI_METADATA_NAMESPACE] as\n | AgUiCustomMetadata\n | undefined;\n const { interrupts: _drop, ...restAgui } = aguiMeta ?? {};\n const newCustom = { ...assistant.metadata.custom };\n if (Object.keys(restAgui).length > 0) {\n newCustom[AG_UI_METADATA_NAMESPACE] = restAgui;\n } else {\n delete newCustom[AG_UI_METADATA_NAMESPACE];\n }\n return {\n ...assistant,\n status: { type: \"complete\" as const, reason: \"unknown\" as const },\n metadata: { ...assistant.metadata, custom: newCustom },\n };\n });\n if (touched) this.notifyUpdate();\n }\n\n findMessageIdForToolCall(toolCallId: string): string | undefined {\n let fallbackMessageId: string | undefined;\n for (let index = this.messages.length - 1; index >= 0; index--) {\n const message = this.messages[index];\n if (!message || message.role !== \"assistant\") continue;\n for (const part of message.content) {\n if (part.type !== \"tool-call\" || part.toolCallId !== toolCallId)\n continue;\n if (!(\"result\" in part) || part.result === undefined) {\n return message.id;\n }\n fallbackMessageId ??= message.id;\n }\n }\n return fallbackMessageId;\n }\n\n addToolResult(options: AddToolResultOptions): void {\n let updated = false;\n this.messages = this.messages.map((message) => {\n if (message.id !== options.messageId || message.role !== \"assistant\")\n return message;\n const assistant = message as ThreadAssistantMessage;\n let matchedToolCall = false;\n const content = assistant.content.map((part) => {\n if (part.type !== \"tool-call\" || part.toolCallId !== options.toolCallId)\n return part;\n matchedToolCall = true;\n return {\n ...part,\n result: options.result,\n artifact: options.artifact,\n isError: options.isError,\n };\n });\n if (!matchedToolCall) return message;\n updated = true;\n return { ...assistant, content };\n });\n\n if (!updated) return;\n this.notifyUpdate();\n this.maybeResumeAfterToolResults(options.messageId);\n }\n\n // Re-evaluate whether every tool call on the assistant message now has a\n // result and, if so, drive the follow-up run. Centralizing this lets the\n // continuation fire whether the frontend result lands before RUN_FINISHED\n // (status flips to requires-action only later, while a run is still draining)\n // or after it. Idempotent: once the message is marked complete it no-ops.\n private maybeResumeAfterToolResults(messageId: string): void {\n const message = this.messages.find((m) => m.id === messageId);\n if (!message || message.role !== \"assistant\") return;\n const assistant = message as ThreadAssistantMessage;\n if (\n assistant.status?.type !== \"requires-action\" ||\n assistant.status.reason !== \"tool-calls\"\n ) {\n return;\n }\n const allResolved = assistant.content.every(\n (part) =>\n part.type !== \"tool-call\" ||\n (\"result\" in part && part.result !== undefined),\n );\n if (!allResolved) return;\n\n this.messages = this.messages.map((m) =>\n m.id === messageId && m.role === \"assistant\"\n ? {\n ...(m as ThreadAssistantMessage),\n status: { type: \"complete\" as const, reason: \"unknown\" as const },\n }\n : m,\n );\n this.notifyUpdate();\n this.persistAssistantHistory(messageId);\n\n if (this.isRunningFlag) {\n // A run is still draining (RUN_FINISHED arrived but the stream has not\n // closed). Defer until startRun's tail so we never start two runs.\n this.pendingResumeMessageId = messageId;\n return;\n }\n this.startResumeRun(messageId);\n }\n\n private startResumeRun(messageId: string): void {\n void this.startRun(messageId, this.lastRunConfig).catch((error) => {\n this.onError?.(error instanceof Error ? error : new Error(String(error)));\n });\n }\n\n applyExternalMessages(messages: readonly ThreadMessage[]): void {\n this.assistantHistoryParents.clear();\n this.messages = [...messages];\n this.recordedHistoryIds.clear();\n for (const message of this.messages) {\n this.recordedHistoryIds.add(message.id);\n }\n this.notifyUpdate();\n }\n\n loadExternalState(state: ReadonlyJSONValue): void {\n this.stateSnapshot = state;\n this.notifyUpdate();\n }\n\n private async startRun(\n parentId: string | null,\n runConfig?: RunConfig,\n resume?: AgUiResumeEntry[],\n resumeStream?: ResumeStream,\n ): Promise<void> {\n const normalizedRunConfig = runConfig ?? {};\n this.lastRunConfig = normalizedRunConfig;\n this.resetHead(parentId);\n const historicalMessages = [...this.messages];\n\n this.pendingError = null;\n const assistantParentId = parentId ?? this.messages.at(-1)?.id ?? null;\n let assistantMessageId: string | undefined;\n const ensureAssistant = () => {\n if (assistantMessageId) return assistantMessageId;\n const created = this.insertAssistantPlaceholder();\n assistantMessageId = created;\n this.markPendingAssistantHistory(created, assistantParentId ?? null);\n return created;\n };\n\n const applyUpdate = (update: ChatModelRunResult) => {\n const resolved = this.updateAssistantMessage(ensureAssistant(), update);\n if (resolved !== assistantMessageId) {\n assistantMessageId = resolved;\n }\n };\n\n const aggregator = new RunAggregator({\n showThinking: this.showThinking,\n logger: this.logger,\n emit: applyUpdate,\n onServerMessageId: (serverId) => {\n const placeholder = ensureAssistant();\n if (placeholder === serverId) return;\n this.reassignAssistantId(placeholder, serverId);\n assistantMessageId = serverId;\n },\n });\n const dispatch = (event: AgUiEvent) => this.handleEvent(aggregator, event);\n\n const abortController = new AbortController();\n const abortSignal = abortController.signal;\n this.abortController = abortController;\n\n let cancelRun = () => dispatch({ type: \"RUN_CANCELLED\" });\n abortSignal.addEventListener(\n \"abort\",\n () => {\n cancelRun();\n this.finishRun(abortController);\n this.onCancel?.();\n },\n { once: true },\n );\n\n this.setRunning(true);\n\n try {\n if (resumeStream) {\n // Cancel flips only the status; an aggregator RUN_CANCELLED would emit an empty snapshot and wipe the replayed content.\n cancelRun = () =>\n applyUpdate({ status: { type: \"incomplete\", reason: \"cancelled\" } });\n await this.consumeResumeStream(resumeStream, {\n runConfig: normalizedRunConfig,\n threadId: this.agent.threadId || \"main\",\n parentId: assistantParentId,\n historicalMessages,\n abortSignal,\n ensureAssistant,\n applyUpdate,\n getAssistantMessageId: () => assistantMessageId,\n });\n } else {\n const runId = generateId();\n aggregator.handle({ type: \"RUN_STARTED\", runId });\n const input = this.buildRunInput(\n runId,\n normalizedRunConfig,\n historicalMessages,\n resume,\n );\n const subscriber = createAgUiSubscriber({\n dispatch,\n runId,\n logger: this.logger,\n onRunFailed: (error) => {\n this.pendingError = error;\n this.onError?.(error);\n },\n });\n try {\n (this.agent as any).messages = input.messages;\n (this.agent as any).threadId = input.threadId;\n (this.agent as any).state = input.state ?? null;\n } catch {\n // ignore\n }\n await (this.agent as any).runAgent(input, subscriber, {\n signal: abortSignal,\n });\n }\n } catch (error) {\n if (!abortSignal.aborted) {\n const err = error instanceof Error ? error : new Error(String(error));\n dispatch({ type: \"RUN_ERROR\", message: err.message });\n this.onError?.(err);\n this.pendingError = this.pendingError ?? err;\n }\n } finally {\n this.finishRun(abortController);\n }\n\n if (this.pendingError) {\n const err = this.pendingError;\n this.pendingError = null;\n this.pendingResumeMessageId = null;\n throw err;\n }\n\n // A tool result that landed before the run settled deferred its\n // continuation here so a second run never overlaps the first.\n if (this.pendingResumeMessageId !== null) {\n const resumeMessageId = this.pendingResumeMessageId;\n this.pendingResumeMessageId = null;\n if (!abortSignal.aborted) {\n this.startResumeRun(resumeMessageId);\n }\n }\n }\n\n // Replays a persisted run's snapshots into the existing assistant message, bypassing agent.runAgent so it is not re-invoked.\n private async consumeResumeStream(\n stream: ResumeStream,\n ctx: {\n runConfig: RunConfig;\n threadId: string;\n parentId: string | null;\n historicalMessages: readonly ThreadMessage[];\n abortSignal: AbortSignal;\n ensureAssistant: () => string;\n applyUpdate: (update: ChatModelRunResult) => void;\n getAssistantMessageId: () => string | undefined;\n },\n ): Promise<void> {\n const assistantId = ctx.ensureAssistant();\n const currentId = () => ctx.getAssistantMessageId() ?? assistantId;\n const options: ChatModelRunOptions = {\n messages: ctx.historicalMessages,\n runConfig: ctx.runConfig,\n abortSignal: ctx.abortSignal,\n context: this.runtime?.thread.getModelContext() ?? {},\n unstable_assistantMessageId: assistantId,\n unstable_threadId: ctx.threadId,\n unstable_parentId: ctx.parentId,\n unstable_getMessage: () => {\n const message = this.messages.find((m) => m.id === currentId());\n if (!message) {\n throw new Error(\n \"[agui] resume stream requested the assistant message before it existed\",\n );\n }\n return message;\n },\n };\n\n try {\n for await (const result of stream(options)) {\n if (ctx.abortSignal.aborted) return;\n ctx.applyUpdate(result);\n }\n } catch (error) {\n if (ctx.abortSignal.aborted) return;\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.applyUpdate({\n status: { type: \"incomplete\", reason: \"error\", error: err.message },\n });\n this.onError?.(err);\n this.pendingError = this.pendingError ?? err;\n return;\n }\n\n if (ctx.abortSignal.aborted) return;\n const current = this.messages.find((m) => m.id === currentId());\n if (!current || current.status?.type === \"running\") {\n ctx.applyUpdate({ status: { type: \"complete\", reason: \"unknown\" } });\n }\n }\n\n private buildRunInput(\n runId: string,\n runConfig: RunConfig | undefined,\n historyMessages: readonly ThreadMessage[] | undefined,\n resume?: AgUiResumeEntry[],\n ) {\n const threadId = this.agent.threadId || \"main\";\n const messages = toAgUiMessages(historyMessages ?? this.messages);\n const context = this.runtime?.thread.getModelContext();\n return {\n threadId,\n runId,\n state: this.stateSnapshot ?? null,\n messages,\n tools: toAgUiTools(context?.tools),\n context: context?.system\n ? [{ description: \"system\", value: context.system }]\n : [],\n forwardedProps: {\n ...(context?.callSettings ?? {}),\n ...(context?.config ?? {}),\n ...(runConfig?.custom ? { runConfig: runConfig.custom } : {}),\n },\n ...(resume !== undefined ? { resume } : {}),\n };\n }\n\n private installResumeShim(): void {\n const agent = this.agent as any;\n if (agent[symbolResumeShim]) return;\n agent[symbolResumeShim] = true;\n const onInstance = Object.hasOwn(agent, \"prepareRunAgentInput\");\n const original = onInstance\n ? agent.prepareRunAgentInput\n : Object.getPrototypeOf(agent)?.prepareRunAgentInput;\n if (typeof original !== \"function\") return;\n agent.prepareRunAgentInput = function (\n this: unknown,\n params: { resume?: unknown } | undefined,\n ) {\n const input = original.call(this, params);\n if (params?.resume !== undefined && input && typeof input === \"object\") {\n return { ...(input as object), resume: params.resume };\n }\n return input;\n };\n }\n\n private setRunning(running: boolean) {\n this.isRunningFlag = running;\n this.notifyUpdate();\n }\n\n private finishRun(controller: AbortController | null) {\n if (this.abortController === controller) {\n this.abortController = null;\n }\n this.setRunning(false);\n }\n\n private insertAssistantPlaceholder(): string {\n const id = generateOptimisticId();\n const assistant: ThreadAssistantMessage = {\n id,\n role: \"assistant\",\n createdAt: new Date(),\n status: { type: \"running\" },\n content: [],\n metadata: {\n unstable_state: this.stateSnapshot ?? null,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n custom: {},\n },\n };\n this.messages = [...this.messages, assistant];\n this.notifyUpdate();\n return id;\n }\n\n private reassignAssistantId(oldId: string, newId: string): void {\n if (oldId === newId) return;\n\n const collidesWithExisting = this.messages.some((m) => m.id === newId);\n\n if (collidesWithExisting) {\n this.logger.debug?.(\n \"[agui] reassignAssistantId: server id already present in messages, dropping placeholder\",\n { oldId, newId },\n );\n this.messages = this.messages.filter((m) => m.id !== oldId);\n } else {\n this.messages = this.messages.map((m) =>\n m.id === oldId ? { ...m, id: newId } : m,\n );\n }\n\n const pendingParent = this.assistantHistoryParents.get(oldId);\n if (pendingParent !== undefined) {\n this.assistantHistoryParents.delete(oldId);\n if (!this.assistantHistoryParents.has(newId)) {\n this.assistantHistoryParents.set(newId, pendingParent);\n }\n }\n\n if (this.recordedHistoryIds.has(oldId)) {\n this.recordedHistoryIds.delete(oldId);\n this.recordedHistoryIds.add(newId);\n }\n\n this.notifyUpdate();\n }\n\n private updateAssistantMessage(\n messageId: string,\n update: ChatModelRunResult,\n ): string {\n let touched = false;\n let latestStatus: MessageStatus | undefined;\n this.messages = this.messages.map((message) => {\n if (message.id !== messageId || message.role !== \"assistant\")\n return message;\n touched = true;\n const assistant = message as ThreadAssistantMessage;\n const metadata = update.metadata\n ? this.mergeAssistantMetadata(assistant.metadata, update.metadata)\n : assistant.metadata;\n latestStatus = update.status ?? assistant.status;\n const content =\n update.content !== undefined\n ? this.preserveToolResults(\n assistant.content,\n update.content as ThreadAssistantMessage[\"content\"],\n )\n : assistant.content;\n return {\n ...assistant,\n content,\n status: latestStatus,\n metadata,\n };\n });\n if (!touched) return messageId;\n\n let resolvedMessageId = messageId;\n const isSettled =\n latestStatus !== undefined && latestStatus.type !== \"running\";\n if (isSettled && isOptimisticId(messageId)) {\n const stableId = generateId();\n this.reassignAssistantId(messageId, stableId);\n resolvedMessageId = stableId;\n } else {\n this.notifyUpdate();\n }\n if (this.isPersistableStatus(latestStatus)) {\n this.persistAssistantHistory(resolvedMessageId);\n }\n this.maybeResumeAfterToolResults(resolvedMessageId);\n return resolvedMessageId;\n }\n\n // The RunAggregator rebuilds the assistant content from stream events only,\n // so a fresh snapshot omits results injected via addToolResult (frontend tool\n // execution). Carry those results forward so the aggregator never clobbers\n // them. Results are only ever added in this flow, so preserving is safe.\n private preserveToolResults(\n previous: ThreadAssistantMessage[\"content\"],\n next: ThreadAssistantMessage[\"content\"],\n ): ThreadAssistantMessage[\"content\"] {\n const resolved = new Map<string, ToolCallMessagePart>();\n for (const part of previous) {\n if (\n part.type === \"tool-call\" &&\n \"result\" in part &&\n part.result !== undefined\n ) {\n resolved.set(part.toolCallId, part);\n }\n }\n if (resolved.size === 0) return next;\n\n let changed = false;\n const merged = next.map((part) => {\n if (part.type !== \"tool-call\") return part;\n if (\"result\" in part && part.result !== undefined) return part;\n const prior = resolved.get(part.toolCallId);\n if (!prior) return part;\n changed = true;\n return {\n ...part,\n result: prior.result,\n ...(prior.artifact !== undefined ? { artifact: prior.artifact } : {}),\n ...(prior.isError !== undefined ? { isError: prior.isError } : {}),\n };\n });\n return changed ? (merged as ThreadAssistantMessage[\"content\"]) : next;\n }\n\n private mergeAssistantMetadata(\n current: ThreadAssistantMessage[\"metadata\"],\n incoming: NonNullable<ChatModelRunResult[\"metadata\"]>,\n ): ThreadAssistantMessage[\"metadata\"] {\n const annotations = incoming.unstable_annotations\n ? [...current.unstable_annotations, ...incoming.unstable_annotations]\n : current.unstable_annotations;\n const data = incoming.unstable_data\n ? [...current.unstable_data, ...incoming.unstable_data]\n : current.unstable_data;\n const steps = incoming.steps\n ? [...current.steps, ...incoming.steps]\n : current.steps;\n return {\n unstable_state:\n incoming.unstable_state !== undefined\n ? incoming.unstable_state\n : current.unstable_state,\n unstable_annotations: annotations,\n unstable_data: data,\n steps,\n ...(incoming.timing ? { timing: incoming.timing } : {}),\n custom: incoming.custom\n ? { ...current.custom, ...incoming.custom }\n : current.custom,\n };\n }\n\n private handleEvent(aggregator: RunAggregator, event: AgUiEvent) {\n switch (event.type) {\n case \"STATE_SNAPSHOT\": {\n this.stateSnapshot = event.snapshot as ReadonlyJSONValue;\n this.notifyUpdate();\n return;\n }\n case \"STATE_DELTA\": {\n if (event.delta.length === 0) return;\n try {\n const state = this.stateSnapshot ?? {};\n const result = jsonpatch.applyPatch(\n state,\n event.delta as Operation[],\n /* validateOperation */ true,\n /* mutateDocument */ false,\n );\n this.stateSnapshot = result.newDocument as ReadonlyJSONValue;\n this.notifyUpdate();\n } catch (error) {\n this.logger.error?.(\"[agui] failed to apply state delta\", error);\n }\n return;\n }\n case \"MESSAGES_SNAPSHOT\": {\n this.importMessagesSnapshot(event.messages);\n return;\n }\n default:\n aggregator.handle(event);\n }\n }\n\n private importMessagesSnapshot(rawMessages: readonly unknown[]) {\n try {\n const normalized = fromAgUiMessages(rawMessages, {\n showThinking: this.showThinking,\n });\n const converted: ThreadMessage[] = [];\n for (const message of normalized) {\n try {\n converted.push(\n fromThreadMessageLike(message, generateId(), FALLBACK_USER_STATUS),\n );\n } catch (error) {\n this.logger.error?.(\n \"[agui] failed to import message from snapshot\",\n error,\n );\n }\n }\n this.applyExternalMessages(converted);\n } catch (error) {\n this.logger.error?.(\"[agui] failed to import messages snapshot\", error);\n }\n }\n\n private toThreadMessage(message: AppendMessage): ThreadMessage {\n return fromThreadMessageLike(\n message as any,\n generateId(),\n FALLBACK_USER_STATUS,\n );\n }\n\n private resetHead(parentId: string | null | undefined) {\n if (!parentId) {\n if (this.messages.length) {\n this.messages = [];\n }\n return;\n }\n const idx = this.messages.findIndex((message) => message.id === parentId);\n if (idx === -1) return;\n this.messages = this.messages.slice(0, idx + 1);\n }\n\n private isTerminalStatus(status?: MessageStatus): boolean {\n return status?.type === \"complete\" || status?.type === \"incomplete\";\n }\n\n private isPersistableStatus(status?: MessageStatus): boolean {\n if (this.isTerminalStatus(status)) return true;\n return status?.type === \"requires-action\" && status.reason === \"interrupt\";\n }\n\n private recordHistoryEntry(parentId: string | null, message: ThreadMessage) {\n this.appendHistoryItem(parentId, message);\n }\n\n private markPendingAssistantHistory(\n messageId: string,\n parentId: string | null,\n ) {\n if (!this.history) return;\n this.assistantHistoryParents.set(messageId, parentId);\n }\n\n private persistAssistantHistory(messageId: string) {\n if (!this.history) return;\n const parentId = this.assistantHistoryParents.get(messageId);\n if (parentId === undefined) return;\n const message = this.messages.find((m) => m.id === messageId);\n if (!message || message.role !== \"assistant\") return;\n if (!this.isPersistableStatus(message.status)) return;\n this.assistantHistoryParents.delete(messageId);\n this.appendHistoryItem(parentId, message);\n }\n\n private appendHistoryItem(parentId: string | null, message: ThreadMessage) {\n if (!this.history || this.recordedHistoryIds.has(message.id)) return;\n this.recordedHistoryIds.add(message.id);\n void this.history.append({ parentId, message }).catch((error) => {\n this.recordedHistoryIds.delete(message.id);\n this.logger.error?.(\"[agui] failed to append history entry\", error);\n });\n }\n}\n"],"mappings":"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"}
|