@assistant-ui/react-ag-ui 0.0.44 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agUiExtras.d.ts +0 -1
- package/dist/agUiExtras.d.ts.map +1 -1
- package/dist/hooks.d.ts +15 -9
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +17 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts +28 -4
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js +379 -114
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts +0 -1
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +12 -12
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +3 -2
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +48 -11
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/adapter/subscriber.d.ts +0 -1
- package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
- package/dist/runtime/event-parser.d.ts +0 -1
- package/dist/runtime/event-parser.d.ts.map +1 -1
- package/dist/runtime/event-parser.js +23 -11
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/logger.d.ts.map +1 -1
- package/dist/runtime/mcp-tool-result.d.ts +11 -0
- package/dist/runtime/mcp-tool-result.d.ts.map +1 -0
- package/dist/runtime/mcp-tool-result.js +20 -0
- package/dist/runtime/mcp-tool-result.js.map +1 -0
- package/dist/runtime/types.d.ts +15 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/useAgUiRuntime.d.ts +0 -1
- package/dist/useAgUiRuntime.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js +8 -2
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +7 -7
- package/src/hooks.ts +29 -7
- package/src/index.ts +2 -0
- package/src/runtime/AgUiThreadRuntimeCore.ts +547 -147
- package/src/runtime/adapter/conversions.ts +26 -17
- package/src/runtime/adapter/run-aggregator.ts +84 -7
- package/src/runtime/event-parser.ts +4 -1
- package/src/runtime/mcp-tool-result.ts +26 -0
- package/src/runtime/types.ts +19 -0
- package/src/useAgUiRuntime.ts +8 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { AG_UI_METADATA_NAMESPACE, RunAggregator, tryParseJSON } from "./adapter/run-aggregator.js";
|
|
2
|
+
import { AG_UI_METADATA_NAMESPACE, RunAggregator, isPlainObject, tryParseJSON } from "./adapter/run-aggregator.js";
|
|
3
3
|
import { fromAgUiMessages, toAgUiMessages, toAgUiTools } from "./adapter/conversions.js";
|
|
4
4
|
import { createAgUiSubscriber } from "./adapter/subscriber.js";
|
|
5
|
-
import {
|
|
5
|
+
import { MessageRepository } from "@assistant-ui/core/internal";
|
|
6
|
+
import { fromThreadMessageLike, generateId, isMcpAppUri } from "@assistant-ui/core";
|
|
6
7
|
import jsonpatch from "fast-json-patch";
|
|
7
8
|
//#region src/runtime/AgUiThreadRuntimeCore.ts
|
|
8
9
|
const optimisticPrefix = "__optimistic__";
|
|
9
10
|
const generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
|
|
10
11
|
const isOptimisticId = (id) => id.startsWith(optimisticPrefix);
|
|
12
|
+
const isResolvedToolCall = (part) => part.type === "tool-call" && "result" in part && part.result !== void 0;
|
|
11
13
|
const symbolResumeShim = Symbol("agui-resume-shim");
|
|
12
14
|
const FALLBACK_USER_STATUS = {
|
|
13
15
|
type: "complete",
|
|
@@ -17,11 +19,13 @@ var AgUiThreadRuntimeCore = class {
|
|
|
17
19
|
agent;
|
|
18
20
|
logger;
|
|
19
21
|
showThinking;
|
|
22
|
+
autoCancelPendingToolCalls;
|
|
20
23
|
onError;
|
|
21
24
|
onCancel;
|
|
22
25
|
notifyUpdate;
|
|
23
26
|
runtime;
|
|
24
|
-
|
|
27
|
+
repository = new MessageRepository();
|
|
28
|
+
exportedRepository;
|
|
25
29
|
isRunningFlag = false;
|
|
26
30
|
abortController = null;
|
|
27
31
|
stateSnapshot;
|
|
@@ -37,6 +41,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
37
41
|
this.agent = options.agent;
|
|
38
42
|
this.logger = options.logger;
|
|
39
43
|
this.showThinking = options.showThinking;
|
|
44
|
+
this.autoCancelPendingToolCalls = options.autoCancelPendingToolCalls;
|
|
40
45
|
this.onError = options.onError;
|
|
41
46
|
this.onCancel = options.onCancel;
|
|
42
47
|
this.history = options.history;
|
|
@@ -47,6 +52,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
47
52
|
this.agent = options.agent;
|
|
48
53
|
this.logger = options.logger;
|
|
49
54
|
this.showThinking = options.showThinking;
|
|
55
|
+
this.autoCancelPendingToolCalls = options.autoCancelPendingToolCalls;
|
|
50
56
|
this.onError = options.onError;
|
|
51
57
|
this.onCancel = options.onCancel;
|
|
52
58
|
this.history = options.history;
|
|
@@ -59,7 +65,74 @@ var AgUiThreadRuntimeCore = class {
|
|
|
59
65
|
this.runtime = void 0;
|
|
60
66
|
}
|
|
61
67
|
getMessages() {
|
|
62
|
-
return this.
|
|
68
|
+
return this.repository.getMessages();
|
|
69
|
+
}
|
|
70
|
+
getMessageRepository() {
|
|
71
|
+
if (this.exportedRepository) return this.exportedRepository;
|
|
72
|
+
const exportedRepository = this.repository.export();
|
|
73
|
+
let parentId = null;
|
|
74
|
+
for (const message of this.repository.getMessages()) {
|
|
75
|
+
if (message.metadata.isOptimistic) exportedRepository.messages.push({
|
|
76
|
+
parentId,
|
|
77
|
+
message
|
|
78
|
+
});
|
|
79
|
+
parentId = message.id;
|
|
80
|
+
}
|
|
81
|
+
this.exportedRepository = {
|
|
82
|
+
...exportedRepository,
|
|
83
|
+
headId: this.repository.headId
|
|
84
|
+
};
|
|
85
|
+
return this.exportedRepository;
|
|
86
|
+
}
|
|
87
|
+
tryGetMessage(messageId) {
|
|
88
|
+
try {
|
|
89
|
+
return this.repository.getMessage(messageId);
|
|
90
|
+
} catch {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
tryGetMessages(messageId) {
|
|
95
|
+
try {
|
|
96
|
+
return this.repository.getMessages(messageId);
|
|
97
|
+
} catch {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
hasMessage(messageId) {
|
|
102
|
+
return this.tryGetMessage(messageId) !== void 0;
|
|
103
|
+
}
|
|
104
|
+
addOrUpdateMessage(parentId, message) {
|
|
105
|
+
this.repository.addOrUpdateMessage(parentId, message);
|
|
106
|
+
this.exportedRepository = void 0;
|
|
107
|
+
}
|
|
108
|
+
deleteMessage(messageId, replacementId) {
|
|
109
|
+
this.repository.deleteMessage(messageId, replacementId);
|
|
110
|
+
this.exportedRepository = void 0;
|
|
111
|
+
}
|
|
112
|
+
tryDeleteMessage(messageId) {
|
|
113
|
+
if (!this.hasMessage(messageId)) return false;
|
|
114
|
+
this.deleteMessage(messageId);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
switchToBranch(messageId) {
|
|
118
|
+
this.repository.switchToBranch(messageId);
|
|
119
|
+
this.exportedRepository = void 0;
|
|
120
|
+
}
|
|
121
|
+
resetRepositoryHead(messageId) {
|
|
122
|
+
this.repository.resetHead(messageId);
|
|
123
|
+
this.exportedRepository = void 0;
|
|
124
|
+
}
|
|
125
|
+
clearRepository() {
|
|
126
|
+
this.repository.clear();
|
|
127
|
+
this.exportedRepository = void 0;
|
|
128
|
+
}
|
|
129
|
+
updateMessage(messageId, updater) {
|
|
130
|
+
const item = this.tryGetMessage(messageId);
|
|
131
|
+
if (!item) return false;
|
|
132
|
+
const message = updater(item.message);
|
|
133
|
+
if (message === item.message) return false;
|
|
134
|
+
this.addOrUpdateMessage(item.parentId, message);
|
|
135
|
+
return true;
|
|
63
136
|
}
|
|
64
137
|
getState() {
|
|
65
138
|
return this.stateSnapshot;
|
|
@@ -76,11 +149,10 @@ var AgUiThreadRuntimeCore = class {
|
|
|
76
149
|
this._isLoading = true;
|
|
77
150
|
this._loadPromise = promise.then(async (repo) => {
|
|
78
151
|
if (!repo) return;
|
|
79
|
-
|
|
80
|
-
this.applyExternalMessages(messages);
|
|
152
|
+
this.applyExternalMessageRepository(repo);
|
|
81
153
|
if (repo.state !== void 0) this.loadExternalState(repo.state);
|
|
82
154
|
if (repo.unstable_resume) {
|
|
83
|
-
const parentId = repo.headId ??
|
|
155
|
+
const parentId = repo.headId ?? this.repository.headId;
|
|
84
156
|
const resumeStream = this.history?.resume?.bind(this.history);
|
|
85
157
|
await this.startRun(parentId, this.lastRunConfig, void 0, resumeStream);
|
|
86
158
|
}
|
|
@@ -96,18 +168,29 @@ var AgUiThreadRuntimeCore = class {
|
|
|
96
168
|
}
|
|
97
169
|
async append(message) {
|
|
98
170
|
const startRun = message.startRun ?? message.role === "user";
|
|
99
|
-
if (startRun)
|
|
171
|
+
if (startRun) {
|
|
172
|
+
this.assertNoPendingInterrupts();
|
|
173
|
+
this.maybeAutoCancelPendingToolCalls();
|
|
174
|
+
}
|
|
100
175
|
const threadMessageId = this.appendEntry(message);
|
|
101
176
|
if (!startRun) return;
|
|
102
177
|
await this.startRun(threadMessageId, message.runConfig);
|
|
103
178
|
}
|
|
179
|
+
maybeAutoCancelPendingToolCalls() {
|
|
180
|
+
if (this.autoCancelPendingToolCalls === false) return;
|
|
181
|
+
const pending = this.getPendingToolCalls();
|
|
182
|
+
if (!pending) return;
|
|
183
|
+
this.cancelUnresolvedToolCalls(pending.messageId);
|
|
184
|
+
this.maybeCompleteAfterToolResults(pending.messageId);
|
|
185
|
+
}
|
|
104
186
|
appendEntry(message) {
|
|
105
|
-
if (message.sourceId) this.
|
|
106
|
-
this.resetHead(message.parentId);
|
|
187
|
+
if (message.sourceId) this.tryDeleteMessage(message.sourceId);
|
|
107
188
|
const threadMessage = this.toThreadMessage(message);
|
|
108
|
-
this.
|
|
189
|
+
const parentId = message.parentId === null ? null : message.parentId && this.hasMessage(message.parentId) ? message.parentId : this.repository.headId;
|
|
190
|
+
this.addOrUpdateMessage(parentId, threadMessage);
|
|
191
|
+
this.switchToBranch(threadMessage.id);
|
|
109
192
|
this.notifyUpdate();
|
|
110
|
-
this.recordHistoryEntry(
|
|
193
|
+
this.recordHistoryEntry(parentId, threadMessage);
|
|
111
194
|
return threadMessage.id;
|
|
112
195
|
}
|
|
113
196
|
async edit(message) {
|
|
@@ -115,8 +198,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
115
198
|
}
|
|
116
199
|
async reload(parentId, config = {}) {
|
|
117
200
|
this.assertNoPendingInterrupts();
|
|
118
|
-
this.
|
|
119
|
-
this.notifyUpdate();
|
|
201
|
+
this.maybeAutoCancelPendingToolCalls();
|
|
120
202
|
await this.startRun(parentId, config.runConfig);
|
|
121
203
|
}
|
|
122
204
|
async cancel() {
|
|
@@ -144,9 +226,14 @@ var AgUiThreadRuntimeCore = class {
|
|
|
144
226
|
if (!this.getPendingInterrupts()) return;
|
|
145
227
|
throw new Error("[agui] cannot start a new run while interrupts are pending; resolve them with submitInterruptResponses()");
|
|
146
228
|
}
|
|
229
|
+
findRequiresActionAssistant(reason) {
|
|
230
|
+
const assistant = this.getMessages().findLast((message) => message.role === "assistant");
|
|
231
|
+
if (!assistant || assistant.status?.type !== "requires-action" || assistant.status.reason !== reason) return null;
|
|
232
|
+
return assistant;
|
|
233
|
+
}
|
|
147
234
|
getPendingInterrupts() {
|
|
148
|
-
const assistant = this.
|
|
149
|
-
if (!assistant
|
|
235
|
+
const assistant = this.findRequiresActionAssistant("interrupt");
|
|
236
|
+
if (!assistant) return null;
|
|
150
237
|
const stored = assistant.metadata.custom[AG_UI_METADATA_NAMESPACE]?.interrupts;
|
|
151
238
|
if (!stored?.length) return null;
|
|
152
239
|
return {
|
|
@@ -154,22 +241,28 @@ var AgUiThreadRuntimeCore = class {
|
|
|
154
241
|
interrupts: stored
|
|
155
242
|
};
|
|
156
243
|
}
|
|
244
|
+
getPendingToolCalls() {
|
|
245
|
+
const assistant = this.findRequiresActionAssistant("tool-calls");
|
|
246
|
+
if (!assistant) return null;
|
|
247
|
+
const toolCallIds = [];
|
|
248
|
+
for (const part of assistant.content) {
|
|
249
|
+
if (part.type !== "tool-call") continue;
|
|
250
|
+
if (isResolvedToolCall(part)) continue;
|
|
251
|
+
toolCallIds.push(part.toolCallId);
|
|
252
|
+
}
|
|
253
|
+
if (toolCallIds.length === 0) return null;
|
|
254
|
+
return {
|
|
255
|
+
messageId: assistant.id,
|
|
256
|
+
toolCallIds
|
|
257
|
+
};
|
|
258
|
+
}
|
|
157
259
|
async submitInterruptResponses(responses) {
|
|
158
260
|
const pending = this.getPendingInterrupts();
|
|
159
261
|
if (!pending) throw new Error("[agui] submitInterruptResponses: no pending interrupts on this thread");
|
|
160
|
-
const responsesById =
|
|
161
|
-
for (const entry of responses) {
|
|
162
|
-
if (!entry || typeof entry.interruptId !== "string") throw new Error("[agui] submitInterruptResponses: every entry must have an interruptId");
|
|
163
|
-
if (entry.status !== "resolved" && entry.status !== "cancelled") throw new Error(`[agui] submitInterruptResponses: invalid status "${entry.status}" for interrupt ${entry.interruptId}`);
|
|
164
|
-
if (responsesById.has(entry.interruptId)) throw new Error(`[agui] submitInterruptResponses: duplicate response for interrupt ${entry.interruptId}`);
|
|
165
|
-
responsesById.set(entry.interruptId, entry);
|
|
166
|
-
}
|
|
262
|
+
const responsesById = this.collectInterruptResponses("submitInterruptResponses", pending.interrupts, responses);
|
|
167
263
|
const openIds = pending.interrupts.map((i) => i.id);
|
|
168
264
|
const missing = openIds.filter((id) => !responsesById.has(id));
|
|
169
265
|
if (missing.length > 0) throw new Error(`[agui] submitInterruptResponses: missing responses for open interrupts: ${missing.join(", ")}`);
|
|
170
|
-
const known = new Set(openIds);
|
|
171
|
-
const unknownIds = [...responsesById.keys()].filter((id) => !known.has(id));
|
|
172
|
-
if (unknownIds.length > 0) throw new Error(`[agui] submitInterruptResponses: unknown interrupt ids: ${unknownIds.join(", ")}`);
|
|
173
266
|
const now = Date.now();
|
|
174
267
|
for (const interrupt of pending.interrupts) {
|
|
175
268
|
if (!interrupt.expiresAt) continue;
|
|
@@ -185,6 +278,17 @@ var AgUiThreadRuntimeCore = class {
|
|
|
185
278
|
async steerAway(message, responses) {
|
|
186
279
|
const pending = this.getPendingInterrupts();
|
|
187
280
|
if (!pending) {
|
|
281
|
+
const pendingTools = this.getPendingToolCalls();
|
|
282
|
+
if (pendingTools) {
|
|
283
|
+
if (responses?.length) throw new Error("[agui] steerAway: responses are only valid for pending interrupts");
|
|
284
|
+
if (this.isRunningFlag) throw new Error("[agui] steerAway: a run is already in progress");
|
|
285
|
+
this.cancelUnresolvedToolCalls(pendingTools.messageId);
|
|
286
|
+
this.maybeCompleteAfterToolResults(pendingTools.messageId);
|
|
287
|
+
const normalized = this.toAppendMessage(message);
|
|
288
|
+
const threadMessageId = this.appendEntry(normalized);
|
|
289
|
+
await this.startRun(threadMessageId, normalized.runConfig);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
188
292
|
if (responses?.length) throw new Error("[agui] steerAway: no pending interrupts on this thread");
|
|
189
293
|
await this.append(this.toAppendMessage(message));
|
|
190
294
|
return;
|
|
@@ -197,25 +301,28 @@ var AgUiThreadRuntimeCore = class {
|
|
|
197
301
|
await this.startRun(threadMessageId, normalized.runConfig, resume);
|
|
198
302
|
}
|
|
199
303
|
resolveSteerAwayResume(interrupts, responses) {
|
|
200
|
-
const
|
|
201
|
-
|
|
304
|
+
const responsesById = this.collectInterruptResponses("steerAway", interrupts, responses ?? []);
|
|
305
|
+
return interrupts.map((interrupt) => responsesById.get(interrupt.id) ?? {
|
|
306
|
+
interruptId: interrupt.id,
|
|
307
|
+
status: "cancelled"
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
collectInterruptResponses(method, interrupts, responses) {
|
|
311
|
+
const known = new Set(interrupts.map((interrupt) => interrupt.id));
|
|
202
312
|
const responsesById = /* @__PURE__ */ new Map();
|
|
203
|
-
for (const entry of responses
|
|
204
|
-
if (!entry || typeof entry.interruptId !== "string") throw new Error(
|
|
205
|
-
if (entry.status !== "resolved" && entry.status !== "cancelled") throw new Error(`[agui]
|
|
206
|
-
if (!known.has(entry.interruptId)) throw new Error(`[agui]
|
|
207
|
-
if (responsesById.has(entry.interruptId)) throw new Error(`[agui]
|
|
313
|
+
for (const entry of responses) {
|
|
314
|
+
if (!entry || typeof entry.interruptId !== "string") throw new Error(`[agui] ${method}: every entry must have an interruptId`);
|
|
315
|
+
if (entry.status !== "resolved" && entry.status !== "cancelled") throw new Error(`[agui] ${method}: invalid status "${entry.status}" for interrupt ${entry.interruptId}`);
|
|
316
|
+
if (!known.has(entry.interruptId)) throw new Error(`[agui] ${method}: unknown interrupt id ${entry.interruptId}`);
|
|
317
|
+
if (responsesById.has(entry.interruptId)) throw new Error(`[agui] ${method}: duplicate response for interrupt ${entry.interruptId}`);
|
|
208
318
|
responsesById.set(entry.interruptId, entry);
|
|
209
319
|
}
|
|
210
|
-
return
|
|
211
|
-
interruptId: id,
|
|
212
|
-
status: "cancelled"
|
|
213
|
-
});
|
|
320
|
+
return responsesById;
|
|
214
321
|
}
|
|
215
322
|
toAppendMessage(message) {
|
|
216
323
|
if (typeof message === "string") return {
|
|
217
324
|
createdAt: /* @__PURE__ */ new Date(),
|
|
218
|
-
parentId: this.
|
|
325
|
+
parentId: this.repository.headId,
|
|
219
326
|
sourceId: null,
|
|
220
327
|
runConfig: {},
|
|
221
328
|
role: "user",
|
|
@@ -228,7 +335,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
228
335
|
};
|
|
229
336
|
return {
|
|
230
337
|
createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
|
|
231
|
-
parentId: message.parentId ?? this.
|
|
338
|
+
parentId: message.parentId ?? this.repository.headId,
|
|
232
339
|
sourceId: message.sourceId ?? null,
|
|
233
340
|
role: message.role ?? "user",
|
|
234
341
|
content: message.content,
|
|
@@ -239,16 +346,14 @@ var AgUiThreadRuntimeCore = class {
|
|
|
239
346
|
};
|
|
240
347
|
}
|
|
241
348
|
clearPendingInterrupts(messageId) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (message.id !== messageId || message.role !== "assistant") return message;
|
|
349
|
+
if (this.updateMessage(messageId, (message) => {
|
|
350
|
+
if (message.role !== "assistant") return message;
|
|
245
351
|
const assistant = message;
|
|
246
352
|
if (assistant.status?.type !== "requires-action" || assistant.status.reason !== "interrupt") return assistant;
|
|
247
|
-
touched = true;
|
|
248
353
|
const { interrupts: _drop, ...restAgui } = assistant.metadata.custom["agui"] ?? {};
|
|
249
354
|
const newCustom = { ...assistant.metadata.custom };
|
|
250
|
-
if (Object.keys(restAgui).length > 0) newCustom[
|
|
251
|
-
else delete newCustom[
|
|
355
|
+
if (Object.keys(restAgui).length > 0) newCustom["agui"] = restAgui;
|
|
356
|
+
else delete newCustom["agui"];
|
|
252
357
|
return {
|
|
253
358
|
...assistant,
|
|
254
359
|
status: {
|
|
@@ -260,26 +365,43 @@ var AgUiThreadRuntimeCore = class {
|
|
|
260
365
|
custom: newCustom
|
|
261
366
|
}
|
|
262
367
|
};
|
|
263
|
-
});
|
|
264
|
-
if (touched) this.notifyUpdate();
|
|
368
|
+
})) this.notifyUpdate();
|
|
265
369
|
}
|
|
266
370
|
findMessageIdForToolCall(toolCallId) {
|
|
267
371
|
let fallbackMessageId;
|
|
268
|
-
|
|
269
|
-
|
|
372
|
+
const messages = this.getMessages();
|
|
373
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
374
|
+
const message = messages[index];
|
|
270
375
|
if (!message || message.role !== "assistant") continue;
|
|
271
376
|
for (const part of message.content) {
|
|
272
377
|
if (part.type !== "tool-call" || part.toolCallId !== toolCallId) continue;
|
|
273
|
-
if (!(
|
|
378
|
+
if (!isResolvedToolCall(part)) return message.id;
|
|
274
379
|
fallbackMessageId ??= message.id;
|
|
275
380
|
}
|
|
276
381
|
}
|
|
277
382
|
return fallbackMessageId;
|
|
278
383
|
}
|
|
384
|
+
cancelUnresolvedToolCalls(messageId) {
|
|
385
|
+
if (this.updateMessage(messageId, (message) => {
|
|
386
|
+
if (message.role !== "assistant") return message;
|
|
387
|
+
const assistant = message;
|
|
388
|
+
const content = assistant.content.map((part) => {
|
|
389
|
+
if (part.type !== "tool-call" || isResolvedToolCall(part)) return part;
|
|
390
|
+
return {
|
|
391
|
+
...part,
|
|
392
|
+
result: { error: "Tool call cancelled by user" },
|
|
393
|
+
isError: true
|
|
394
|
+
};
|
|
395
|
+
});
|
|
396
|
+
return {
|
|
397
|
+
...assistant,
|
|
398
|
+
content
|
|
399
|
+
};
|
|
400
|
+
})) this.notifyUpdate();
|
|
401
|
+
}
|
|
279
402
|
addToolResult(options) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (message.id !== options.messageId || message.role !== "assistant") return message;
|
|
403
|
+
if (!this.updateMessage(options.messageId, (message) => {
|
|
404
|
+
if (message.role !== "assistant") return message;
|
|
283
405
|
const assistant = message;
|
|
284
406
|
let matchedToolCall = false;
|
|
285
407
|
const content = assistant.content.map((part) => {
|
|
@@ -293,13 +415,11 @@ var AgUiThreadRuntimeCore = class {
|
|
|
293
415
|
};
|
|
294
416
|
});
|
|
295
417
|
if (!matchedToolCall) return message;
|
|
296
|
-
updated = true;
|
|
297
418
|
return {
|
|
298
419
|
...assistant,
|
|
299
420
|
content
|
|
300
421
|
};
|
|
301
|
-
});
|
|
302
|
-
if (!updated) return;
|
|
422
|
+
})) return;
|
|
303
423
|
this.notifyUpdate();
|
|
304
424
|
this.maybeResumeAfterToolResults(options.messageId);
|
|
305
425
|
}
|
|
@@ -312,18 +432,18 @@ var AgUiThreadRuntimeCore = class {
|
|
|
312
432
|
this.startResumeRun(messageId);
|
|
313
433
|
}
|
|
314
434
|
maybeCompleteAfterToolResults(messageId) {
|
|
315
|
-
const message = this.
|
|
435
|
+
const message = this.tryGetMessage(messageId)?.message;
|
|
316
436
|
if (!message || message.role !== "assistant") return false;
|
|
317
437
|
const assistant = message;
|
|
318
438
|
if (assistant.status?.type !== "requires-action" || assistant.status.reason !== "tool-calls") return false;
|
|
319
|
-
if (!assistant.content.every((part) => part.type !== "tool-call" ||
|
|
320
|
-
|
|
321
|
-
...
|
|
439
|
+
if (!assistant.content.every((part) => part.type !== "tool-call" || isResolvedToolCall(part))) return false;
|
|
440
|
+
if (!this.updateMessage(messageId, (current) => current.role === "assistant" ? {
|
|
441
|
+
...current,
|
|
322
442
|
status: {
|
|
323
443
|
type: "complete",
|
|
324
444
|
reason: "unknown"
|
|
325
445
|
}
|
|
326
|
-
} :
|
|
446
|
+
} : current)) return false;
|
|
327
447
|
this.notifyUpdate();
|
|
328
448
|
this.persistAssistantHistory(messageId);
|
|
329
449
|
return true;
|
|
@@ -335,30 +455,122 @@ var AgUiThreadRuntimeCore = class {
|
|
|
335
455
|
}
|
|
336
456
|
applyExternalMessages(messages) {
|
|
337
457
|
this.assistantHistoryParents.clear();
|
|
338
|
-
|
|
458
|
+
if (messages.length === 0) this.clearRepository();
|
|
459
|
+
else {
|
|
460
|
+
let expectedParentId = null;
|
|
461
|
+
let lastAppliedId = null;
|
|
462
|
+
let hardReplace = false;
|
|
463
|
+
const seen = /* @__PURE__ */ new Set();
|
|
464
|
+
for (const message of messages) {
|
|
465
|
+
if (seen.has(message.id)) continue;
|
|
466
|
+
seen.add(message.id);
|
|
467
|
+
const existing = this.tryGetMessage(message.id);
|
|
468
|
+
if (existing && existing.parentId !== expectedParentId) {
|
|
469
|
+
hardReplace = true;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
this.addOrUpdateMessage(expectedParentId, message);
|
|
473
|
+
expectedParentId = message.id;
|
|
474
|
+
lastAppliedId = message.id;
|
|
475
|
+
}
|
|
476
|
+
if (hardReplace) {
|
|
477
|
+
this.clearRepository();
|
|
478
|
+
expectedParentId = null;
|
|
479
|
+
lastAppliedId = null;
|
|
480
|
+
seen.clear();
|
|
481
|
+
for (const message of messages) {
|
|
482
|
+
if (seen.has(message.id)) continue;
|
|
483
|
+
seen.add(message.id);
|
|
484
|
+
this.addOrUpdateMessage(expectedParentId, message);
|
|
485
|
+
expectedParentId = message.id;
|
|
486
|
+
lastAppliedId = message.id;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
this.resetRepositoryHead(lastAppliedId);
|
|
490
|
+
}
|
|
491
|
+
this.recordedHistoryIds.clear();
|
|
492
|
+
for (const { message } of this.getMessageRepository().messages) this.recordedHistoryIds.add(message.id);
|
|
493
|
+
this.notifyUpdate();
|
|
494
|
+
}
|
|
495
|
+
applyExternalMessageRepository(loaded) {
|
|
496
|
+
const headId = loaded.headId ?? loaded.messages.at(-1)?.message.id ?? null;
|
|
497
|
+
const ids = /* @__PURE__ */ new Set();
|
|
498
|
+
let degenerate = false;
|
|
499
|
+
for (const { message } of loaded.messages) {
|
|
500
|
+
if (ids.has(message.id)) {
|
|
501
|
+
degenerate = true;
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
ids.add(message.id);
|
|
505
|
+
}
|
|
506
|
+
if (headId !== null && !ids.has(headId)) degenerate = true;
|
|
507
|
+
if (!degenerate) {
|
|
508
|
+
this.clearRepository();
|
|
509
|
+
let pending = [...loaded.messages];
|
|
510
|
+
const importedIds = /* @__PURE__ */ new Set();
|
|
511
|
+
while (pending.length > 0) {
|
|
512
|
+
const unresolved = [];
|
|
513
|
+
let progressed = false;
|
|
514
|
+
for (const item of pending) {
|
|
515
|
+
if (item.parentId !== null && !importedIds.has(item.parentId)) {
|
|
516
|
+
unresolved.push(item);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
this.addOrUpdateMessage(item.parentId, item.message);
|
|
520
|
+
importedIds.add(item.message.id);
|
|
521
|
+
progressed = true;
|
|
522
|
+
}
|
|
523
|
+
if (!progressed) {
|
|
524
|
+
degenerate = true;
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
pending = unresolved;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (degenerate) {
|
|
531
|
+
this.clearRepository();
|
|
532
|
+
let previousId = null;
|
|
533
|
+
for (const { message } of loaded.messages) {
|
|
534
|
+
const existing = this.tryGetMessage(message.id);
|
|
535
|
+
this.addOrUpdateMessage(existing ? existing.parentId : previousId, message);
|
|
536
|
+
previousId = message.id;
|
|
537
|
+
}
|
|
538
|
+
this.resetRepositoryHead(previousId);
|
|
539
|
+
} else this.resetRepositoryHead(headId);
|
|
540
|
+
this.assistantHistoryParents.clear();
|
|
339
541
|
this.recordedHistoryIds.clear();
|
|
340
|
-
for (const message of
|
|
542
|
+
for (const { message } of loaded.messages) this.recordedHistoryIds.add(message.id);
|
|
341
543
|
this.notifyUpdate();
|
|
342
544
|
}
|
|
343
545
|
loadExternalState(state) {
|
|
344
546
|
this.stateSnapshot = state;
|
|
345
547
|
this.notifyUpdate();
|
|
346
548
|
}
|
|
549
|
+
setState(next) {
|
|
550
|
+
this.stateSnapshot = typeof next === "function" ? next(this.stateSnapshot) : next;
|
|
551
|
+
this.notifyUpdate();
|
|
552
|
+
}
|
|
553
|
+
resetState() {
|
|
554
|
+
this.stateSnapshot = void 0;
|
|
555
|
+
this.notifyUpdate();
|
|
556
|
+
}
|
|
347
557
|
async startRun(parentId, runConfig, resume, resumeStream) {
|
|
348
558
|
const normalizedRunConfig = runConfig ?? {};
|
|
349
559
|
this.lastRunConfig = normalizedRunConfig;
|
|
350
|
-
this.
|
|
351
|
-
const
|
|
560
|
+
const parent = parentId === null ? void 0 : this.tryGetMessage(parentId);
|
|
561
|
+
const shouldEagerlyInsertAssistant = parentId !== null && parent !== void 0 && parentId !== this.repository.headId;
|
|
562
|
+
const historicalMessages = [...shouldEagerlyInsertAssistant ? this.tryGetMessages(parentId) ?? this.repository.getMessages() : this.repository.getMessages()];
|
|
352
563
|
this.pendingError = null;
|
|
353
|
-
const assistantParentId = parentId
|
|
564
|
+
const assistantParentId = parent ? parentId : this.repository.headId;
|
|
354
565
|
let assistantMessageId;
|
|
355
566
|
const ensureAssistant = () => {
|
|
356
567
|
if (assistantMessageId) return assistantMessageId;
|
|
357
|
-
const created = this.insertAssistantPlaceholder();
|
|
568
|
+
const created = this.insertAssistantPlaceholder(assistantParentId ?? null);
|
|
358
569
|
assistantMessageId = created;
|
|
359
570
|
this.markPendingAssistantHistory(created, assistantParentId ?? null);
|
|
360
571
|
return created;
|
|
361
572
|
};
|
|
573
|
+
if (shouldEagerlyInsertAssistant) ensureAssistant();
|
|
362
574
|
const applyUpdate = (update) => {
|
|
363
575
|
const resolved = this.updateAssistantMessage(ensureAssistant(), update);
|
|
364
576
|
if (resolved !== assistantMessageId) assistantMessageId = resolved;
|
|
@@ -370,8 +582,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
370
582
|
onServerMessageId: (serverId) => {
|
|
371
583
|
const placeholder = ensureAssistant();
|
|
372
584
|
if (placeholder === serverId) return;
|
|
373
|
-
this.reassignAssistantId(placeholder, serverId);
|
|
374
|
-
assistantMessageId = serverId;
|
|
585
|
+
if (this.reassignAssistantId(placeholder, serverId)) assistantMessageId = serverId;
|
|
375
586
|
}
|
|
376
587
|
});
|
|
377
588
|
const dispatch = (event) => this.handleEvent(aggregator, event);
|
|
@@ -461,7 +672,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
461
672
|
unstable_threadId: ctx.threadId,
|
|
462
673
|
unstable_parentId: ctx.parentId,
|
|
463
674
|
unstable_getMessage: () => {
|
|
464
|
-
const message = this.
|
|
675
|
+
const message = this.tryGetMessage(currentId())?.message;
|
|
465
676
|
if (!message) throw new Error("[agui] resume stream requested the assistant message before it existed");
|
|
466
677
|
return message;
|
|
467
678
|
}
|
|
@@ -484,7 +695,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
484
695
|
return;
|
|
485
696
|
}
|
|
486
697
|
if (ctx.abortSignal.aborted) return;
|
|
487
|
-
const current = this.
|
|
698
|
+
const current = this.tryGetMessage(currentId())?.message;
|
|
488
699
|
if (!current || current.status?.type === "running") ctx.applyUpdate({ status: {
|
|
489
700
|
type: "complete",
|
|
490
701
|
reason: "unknown"
|
|
@@ -492,7 +703,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
492
703
|
}
|
|
493
704
|
buildRunInput(runId, runConfig, historyMessages, resume) {
|
|
494
705
|
const threadId = this.agent.threadId || "main";
|
|
495
|
-
const messages = toAgUiMessages(historyMessages ?? this.
|
|
706
|
+
const messages = toAgUiMessages(historyMessages ?? this.repository.getMessages());
|
|
496
707
|
const context = this.runtime?.thread.getModelContext();
|
|
497
708
|
return {
|
|
498
709
|
threadId,
|
|
@@ -535,7 +746,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
535
746
|
if (this.abortController === controller) this.abortController = null;
|
|
536
747
|
this.setRunning(false);
|
|
537
748
|
}
|
|
538
|
-
insertAssistantPlaceholder() {
|
|
749
|
+
insertAssistantPlaceholder(parentId) {
|
|
539
750
|
const id = generateOptimisticId();
|
|
540
751
|
const assistant = {
|
|
541
752
|
id,
|
|
@@ -552,44 +763,48 @@ var AgUiThreadRuntimeCore = class {
|
|
|
552
763
|
custom: {}
|
|
553
764
|
}
|
|
554
765
|
};
|
|
555
|
-
this.
|
|
766
|
+
this.addOrUpdateMessage(parentId ?? this.repository.headId, assistant);
|
|
767
|
+
this.switchToBranch(id);
|
|
556
768
|
this.notifyUpdate();
|
|
557
769
|
return id;
|
|
558
770
|
}
|
|
559
771
|
reassignAssistantId(oldId, newId) {
|
|
560
|
-
if (oldId === newId) return;
|
|
561
|
-
|
|
562
|
-
|
|
772
|
+
if (oldId === newId) return true;
|
|
773
|
+
const oldItem = this.tryGetMessage(oldId);
|
|
774
|
+
if (!oldItem) return false;
|
|
775
|
+
const collidesWithExisting = this.hasMessage(newId);
|
|
776
|
+
if (collidesWithExisting) {
|
|
777
|
+
this.logger.debug?.("[agui] reassignAssistantId: server id already present in messages or repository, dropping placeholder", {
|
|
563
778
|
oldId,
|
|
564
779
|
newId
|
|
565
780
|
});
|
|
566
|
-
this.
|
|
567
|
-
} else
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
...m,
|
|
781
|
+
this.deleteMessage(oldId, oldItem.parentId ?? null);
|
|
782
|
+
} else {
|
|
783
|
+
const { isOptimistic: _, ...metadata } = oldItem.message.metadata;
|
|
784
|
+
this.addOrUpdateMessage(oldItem.parentId, {
|
|
785
|
+
...oldItem.message,
|
|
572
786
|
id: newId,
|
|
573
787
|
metadata
|
|
574
|
-
};
|
|
575
|
-
|
|
788
|
+
});
|
|
789
|
+
this.switchToBranch(newId);
|
|
790
|
+
this.tryDeleteMessage(oldId);
|
|
791
|
+
}
|
|
576
792
|
const pendingParent = this.assistantHistoryParents.get(oldId);
|
|
577
793
|
if (pendingParent !== void 0) {
|
|
578
794
|
this.assistantHistoryParents.delete(oldId);
|
|
579
|
-
if (!this.assistantHistoryParents.has(newId)) this.assistantHistoryParents.set(newId, pendingParent);
|
|
795
|
+
if (!collidesWithExisting && !this.assistantHistoryParents.has(newId)) this.assistantHistoryParents.set(newId, pendingParent);
|
|
580
796
|
}
|
|
581
797
|
if (this.recordedHistoryIds.has(oldId)) {
|
|
582
798
|
this.recordedHistoryIds.delete(oldId);
|
|
583
|
-
this.recordedHistoryIds.add(newId);
|
|
799
|
+
if (!collidesWithExisting) this.recordedHistoryIds.add(newId);
|
|
584
800
|
}
|
|
585
801
|
this.notifyUpdate();
|
|
802
|
+
return !collidesWithExisting;
|
|
586
803
|
}
|
|
587
804
|
updateAssistantMessage(messageId, update) {
|
|
588
|
-
let touched = false;
|
|
589
805
|
let latestStatus;
|
|
590
|
-
|
|
591
|
-
if (message.
|
|
592
|
-
touched = true;
|
|
806
|
+
if (!this.updateMessage(messageId, (message) => {
|
|
807
|
+
if (message.role !== "assistant") return message;
|
|
593
808
|
const assistant = message;
|
|
594
809
|
const metadata = update.metadata ? this.mergeAssistantMetadata(assistant.metadata, update.metadata) : assistant.metadata;
|
|
595
810
|
latestStatus = update.status ?? assistant.status;
|
|
@@ -600,8 +815,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
600
815
|
status: latestStatus,
|
|
601
816
|
metadata
|
|
602
817
|
};
|
|
603
|
-
});
|
|
604
|
-
if (!touched) return messageId;
|
|
818
|
+
})) return messageId;
|
|
605
819
|
let resolvedMessageId = messageId;
|
|
606
820
|
if (latestStatus !== void 0 && latestStatus.type !== "running" && isOptimisticId(messageId)) {
|
|
607
821
|
const stableId = generateId();
|
|
@@ -614,12 +828,11 @@ var AgUiThreadRuntimeCore = class {
|
|
|
614
828
|
}
|
|
615
829
|
preserveToolResults(previous, next) {
|
|
616
830
|
const resolved = /* @__PURE__ */ new Map();
|
|
617
|
-
for (const part of previous) if (part.type === "tool-call" &&
|
|
831
|
+
for (const part of previous) if (part.type === "tool-call" && isResolvedToolCall(part)) resolved.set(part.toolCallId, part);
|
|
618
832
|
if (resolved.size === 0) return next;
|
|
619
833
|
let changed = false;
|
|
620
834
|
const merged = next.map((part) => {
|
|
621
|
-
if (part.type !== "tool-call") return part;
|
|
622
|
-
if ("result" in part && part.result !== void 0) return part;
|
|
835
|
+
if (part.type !== "tool-call" || isResolvedToolCall(part)) return part;
|
|
623
836
|
const prior = resolved.get(part.toolCallId);
|
|
624
837
|
if (!prior) return part;
|
|
625
838
|
changed = true;
|
|
@@ -679,33 +892,94 @@ var AgUiThreadRuntimeCore = class {
|
|
|
679
892
|
}
|
|
680
893
|
aggregator.handle(event);
|
|
681
894
|
return;
|
|
895
|
+
case "ACTIVITY_SNAPSHOT": {
|
|
896
|
+
const toolCallId = event.content["toolCallId"];
|
|
897
|
+
if (event.activityType === "mcp-apps" && typeof toolCallId === "string" && !aggregator.hasToolCall(toolCallId)) {
|
|
898
|
+
const messageId = this.findMessageIdForToolCall(toolCallId);
|
|
899
|
+
if (messageId !== void 0) {
|
|
900
|
+
this.applyCrossRunActivitySnapshot(messageId, toolCallId, event);
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
aggregator.handle(event);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
682
907
|
default: aggregator.handle(event);
|
|
683
908
|
}
|
|
684
909
|
}
|
|
685
910
|
applyCrossRunToolResult(messageId, event) {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (message.id !== messageId || message.role !== "assistant") return message;
|
|
911
|
+
if (!this.updateMessage(messageId, (message) => {
|
|
912
|
+
if (message.role !== "assistant") return message;
|
|
689
913
|
const assistant = message;
|
|
690
914
|
let matchedToolCall = false;
|
|
691
915
|
const content = assistant.content.map((part) => {
|
|
692
916
|
if (part.type !== "tool-call" || part.toolCallId !== event.toolCallId) return part;
|
|
693
917
|
matchedToolCall = true;
|
|
918
|
+
if (part.mcp?.app !== void 0 && isPlainObject(part.result) && Array.isArray(part.result["content"])) return {
|
|
919
|
+
...part,
|
|
920
|
+
...part.modelContent === void 0 && event.content ? { modelContent: [{
|
|
921
|
+
type: "text",
|
|
922
|
+
text: event.content
|
|
923
|
+
}] } : {},
|
|
924
|
+
...part.isError === void 0 ? typeof event.mcpResult?.isError === "boolean" ? { isError: event.mcpResult.isError } : event.role === "tool" ? { isError: false } : {} : {},
|
|
925
|
+
...event.messageId ? { unstable_toolMessageId: event.messageId } : {}
|
|
926
|
+
};
|
|
694
927
|
return {
|
|
695
928
|
...part,
|
|
696
|
-
result: tryParseJSON(event.content ?? ""),
|
|
697
|
-
...event.
|
|
929
|
+
result: event.mcpResult ?? tryParseJSON(event.content ?? ""),
|
|
930
|
+
...event.mcpResult !== void 0 ? { modelContent: [{
|
|
931
|
+
type: "text",
|
|
932
|
+
text: event.content
|
|
933
|
+
}] } : {},
|
|
934
|
+
...typeof event.mcpResult?.isError === "boolean" ? { isError: event.mcpResult.isError } : event.role === "tool" ? { isError: false } : {},
|
|
698
935
|
...event.messageId ? { unstable_toolMessageId: event.messageId } : {}
|
|
699
936
|
};
|
|
700
937
|
});
|
|
701
938
|
if (!matchedToolCall) return message;
|
|
702
|
-
updated = true;
|
|
703
939
|
return {
|
|
704
940
|
...assistant,
|
|
705
941
|
content
|
|
706
942
|
};
|
|
707
|
-
});
|
|
708
|
-
|
|
943
|
+
})) return;
|
|
944
|
+
this.notifyUpdate();
|
|
945
|
+
this.maybeCompleteAfterToolResults(messageId);
|
|
946
|
+
}
|
|
947
|
+
applyCrossRunActivitySnapshot(messageId, toolCallId, event) {
|
|
948
|
+
const resourceUri = event.content["resourceUri"];
|
|
949
|
+
if (typeof resourceUri !== "string" || !isMcpAppUri(resourceUri)) return;
|
|
950
|
+
const serverId = event.content["serverId"];
|
|
951
|
+
const serverHash = event.content["serverHash"];
|
|
952
|
+
const appServerId = typeof serverId === "string" && serverId.length > 0 ? serverId : typeof serverHash === "string" && serverHash.length > 0 ? serverHash : void 0;
|
|
953
|
+
const result = event.content["result"];
|
|
954
|
+
if (!this.updateMessage(messageId, (message) => {
|
|
955
|
+
if (message.role !== "assistant") return message;
|
|
956
|
+
const assistant = message;
|
|
957
|
+
let matchedToolCall = false;
|
|
958
|
+
const content = assistant.content.map((part) => {
|
|
959
|
+
if (part.type !== "tool-call" || part.toolCallId !== toolCallId) return part;
|
|
960
|
+
matchedToolCall = true;
|
|
961
|
+
return {
|
|
962
|
+
...part,
|
|
963
|
+
mcp: { app: {
|
|
964
|
+
resourceUri,
|
|
965
|
+
...appServerId ? { serverId: appServerId } : {}
|
|
966
|
+
} },
|
|
967
|
+
...isPlainObject(result) ? {
|
|
968
|
+
...part.result !== void 0 && part.modelContent === void 0 ? { modelContent: [{
|
|
969
|
+
type: "text",
|
|
970
|
+
text: typeof part.result === "string" ? part.result : JSON.stringify(part.result)
|
|
971
|
+
}] } : {},
|
|
972
|
+
result,
|
|
973
|
+
isError: result["isError"] === true
|
|
974
|
+
} : {}
|
|
975
|
+
};
|
|
976
|
+
});
|
|
977
|
+
if (!matchedToolCall) return message;
|
|
978
|
+
return {
|
|
979
|
+
...assistant,
|
|
980
|
+
content
|
|
981
|
+
};
|
|
982
|
+
})) return;
|
|
709
983
|
this.notifyUpdate();
|
|
710
984
|
this.maybeCompleteAfterToolResults(messageId);
|
|
711
985
|
}
|
|
@@ -726,15 +1000,6 @@ var AgUiThreadRuntimeCore = class {
|
|
|
726
1000
|
toThreadMessage(message) {
|
|
727
1001
|
return fromThreadMessageLike(message, generateId(), FALLBACK_USER_STATUS);
|
|
728
1002
|
}
|
|
729
|
-
resetHead(parentId) {
|
|
730
|
-
if (!parentId) {
|
|
731
|
-
if (this.messages.length) this.messages = [];
|
|
732
|
-
return;
|
|
733
|
-
}
|
|
734
|
-
const idx = this.messages.findIndex((message) => message.id === parentId);
|
|
735
|
-
if (idx === -1) return;
|
|
736
|
-
this.messages = this.messages.slice(0, idx + 1);
|
|
737
|
-
}
|
|
738
1003
|
isTerminalStatus(status) {
|
|
739
1004
|
return status?.type === "complete" || status?.type === "incomplete";
|
|
740
1005
|
}
|
|
@@ -753,7 +1018,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
753
1018
|
if (!this.history) return;
|
|
754
1019
|
const parentId = this.assistantHistoryParents.get(messageId);
|
|
755
1020
|
if (parentId === void 0) return;
|
|
756
|
-
const message = this.
|
|
1021
|
+
const message = this.tryGetMessage(messageId)?.message;
|
|
757
1022
|
if (!message || message.role !== "assistant") return;
|
|
758
1023
|
if (!this.isPersistableStatus(message.status)) return;
|
|
759
1024
|
this.assistantHistoryParents.delete(messageId);
|