@assistant-ui/react-ag-ui 0.0.71 → 0.1.0
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/README.md +1 -1
- package/dist/runtime/{AgUiThreadRuntimeCore.d.ts → AgUiThreadController.d.ts} +6 -12
- package/dist/runtime/AgUiThreadController.d.ts.map +1 -0
- package/dist/runtime/{AgUiThreadRuntimeCore.js → AgUiThreadController.js} +246 -159
- package/dist/runtime/AgUiThreadController.js.map +1 -0
- package/dist/runtime/adapter/conversions.d.ts +4 -4
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +111 -33
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +3 -5
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +47 -61
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/adapter/subscriber.d.ts +0 -24
- package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
- package/dist/runtime/adapter/subscriber.js +1 -22
- package/dist/runtime/adapter/subscriber.js.map +1 -1
- package/dist/runtime/agUiThreadState.d.ts +60 -0
- package/dist/runtime/agUiThreadState.d.ts.map +1 -0
- package/dist/runtime/agUiThreadState.js +95 -0
- package/dist/runtime/agUiThreadState.js.map +1 -0
- package/dist/runtime/event-parser.d.ts.map +1 -1
- package/dist/runtime/event-parser.js +45 -48
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/mcp-tool-result.d.ts +3 -1
- package/dist/runtime/mcp-tool-result.d.ts.map +1 -1
- package/dist/runtime/mcp-tool-result.js +6 -3
- package/dist/runtime/mcp-tool-result.js.map +1 -1
- package/dist/runtime/types.d.ts +11 -35
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/useAgUiRuntime.js +2 -2
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +12 -11
- package/src/runtime/{AgUiThreadRuntimeCore.interrupt-cancel.test.ts → AgUiThreadController.interrupt-cancel.test.ts} +4 -4
- package/src/runtime/{AgUiThreadRuntimeCore.test.ts → AgUiThreadController.test.ts} +35 -6
- package/src/runtime/{AgUiThreadRuntimeCore.ts → AgUiThreadController.ts} +356 -171
- package/src/runtime/adapter/conversions.content.test.ts +37 -5
- package/src/runtime/adapter/conversions.tools.test.ts +2 -1
- package/src/runtime/adapter/conversions.ts +235 -58
- package/src/runtime/adapter/run-aggregator.ts +79 -114
- package/src/runtime/adapter/subscriber.ts +1 -44
- package/src/runtime/agUiThreadState.test.ts +205 -0
- package/src/runtime/agUiThreadState.ts +130 -0
- package/src/runtime/event-parser.ts +40 -58
- package/src/runtime/mcp-tool-result.ts +16 -2
- package/src/runtime/types.ts +16 -28
- package/src/useAgUiRuntime.fast-refresh.test.tsx +3 -3
- package/src/useAgUiRuntime.thread-switch.test.tsx +4 -4
- package/src/useAgUiRuntime.ts +3 -3
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +0 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +0 -1
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { createAgUiThreadState, reduceAgUiThreadState } from "./agUiThreadState.js";
|
|
3
|
+
import { readMcpAppResourceUri, toolContentText } from "./mcp-tool-result.js";
|
|
3
4
|
import { AG_UI_METADATA_NAMESPACE } from "./types.js";
|
|
4
5
|
import { buildToolApprovalResume, projectAgUiToolApprovals, withSettledToolApprovals, withToolApprovalDecision } from "./adapter/tool-approval.js";
|
|
5
6
|
import { RunAggregator, isPlainObject, tryParseJSON } from "./adapter/run-aggregator.js";
|
|
6
7
|
import { fromAgUiMessages, toAgUiMessages, toAgUiTools } from "./adapter/conversions.js";
|
|
7
8
|
import { createAgUiSubscriber } from "./adapter/subscriber.js";
|
|
8
9
|
import { fromThreadMessageLike, generateId, isMcpAppUri } from "@assistant-ui/core";
|
|
9
|
-
import { appendToolInteraction, createMessageRepositorySession, invokeUserCallback, iterateToolCallParts, mapToolCallPartsDeep } from "@assistant-ui/core/internal";
|
|
10
|
+
import { appendToolInteraction, createHistoryWriteChain, createMessageRepositorySession, invokeUserCallback, iterateToolCallParts, mapToolCallPartsDeep } from "@assistant-ui/core/internal";
|
|
10
11
|
import jsonpatch from "fast-json-patch";
|
|
11
|
-
//#region src/runtime/
|
|
12
|
+
//#region src/runtime/AgUiThreadController.ts
|
|
12
13
|
const optimisticPrefix = "__optimistic__";
|
|
13
14
|
const generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
|
|
14
15
|
const isOptimisticId = (id) => id.startsWith(optimisticPrefix);
|
|
15
16
|
const isResolvedToolCall = (part) => part.type === "tool-call" && "result" in part && part.result !== void 0;
|
|
17
|
+
const listedPendingToolCallIds = (assistant) => {
|
|
18
|
+
const ids = assistant.metadata.custom[AG_UI_METADATA_NAMESPACE]?.pendingToolCallIds;
|
|
19
|
+
return ids?.length ? new Set(ids) : void 0;
|
|
20
|
+
};
|
|
21
|
+
const withoutPendingToolCallIds = (metadata) => {
|
|
22
|
+
const namespace = metadata.custom[AG_UI_METADATA_NAMESPACE];
|
|
23
|
+
if (!namespace || !("pendingToolCallIds" in namespace)) return metadata;
|
|
24
|
+
const { pendingToolCallIds: _pendingToolCallIds, ...remainingNamespace } = namespace;
|
|
25
|
+
const { [AG_UI_METADATA_NAMESPACE]: _namespace, ...remainingCustom } = metadata.custom;
|
|
26
|
+
return {
|
|
27
|
+
...metadata,
|
|
28
|
+
custom: {
|
|
29
|
+
...remainingCustom,
|
|
30
|
+
...Object.keys(remainingNamespace).length > 0 ? { [AG_UI_METADATA_NAMESPACE]: remainingNamespace } : {}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
};
|
|
16
34
|
const isActivityPart = (part) => part.type === "data" && part.name.startsWith("agui-activity/");
|
|
17
35
|
const FALLBACK_USER_STATUS = {
|
|
18
36
|
type: "complete",
|
|
@@ -34,7 +52,7 @@ const mergeAgUiNamespace = (current, incoming) => {
|
|
|
34
52
|
};
|
|
35
53
|
return merged;
|
|
36
54
|
};
|
|
37
|
-
var
|
|
55
|
+
var AgUiThreadController = class {
|
|
38
56
|
agent;
|
|
39
57
|
logger;
|
|
40
58
|
showThinking;
|
|
@@ -63,24 +81,16 @@ var AgUiThreadRuntimeCore = class {
|
|
|
63
81
|
headId: repository.headId
|
|
64
82
|
};
|
|
65
83
|
} });
|
|
66
|
-
|
|
84
|
+
state = createAgUiThreadState();
|
|
67
85
|
abortController = null;
|
|
68
86
|
activeRunAgent = null;
|
|
69
|
-
stateSnapshot;
|
|
70
87
|
history;
|
|
71
|
-
lastRunConfig;
|
|
72
88
|
assistantHistoryParents = /* @__PURE__ */ new Map();
|
|
73
89
|
snapshotHistoryIds = /* @__PURE__ */ new Set();
|
|
74
90
|
persistedHistoryIds = /* @__PURE__ */ new Set();
|
|
75
|
-
historyWrites =
|
|
76
|
-
_isLoading = false;
|
|
91
|
+
historyWrites = createHistoryWriteChain();
|
|
77
92
|
_historyImportPromise;
|
|
78
|
-
historyMutationGeneration = 0;
|
|
79
93
|
_loadPromise;
|
|
80
|
-
_loadRequested = false;
|
|
81
|
-
pendingResume = null;
|
|
82
|
-
pendingA2uiResumeOwner = null;
|
|
83
|
-
pendingA2uiAction;
|
|
84
94
|
constructor(options) {
|
|
85
95
|
this.agent = options.agent;
|
|
86
96
|
this.logger = options.logger;
|
|
@@ -99,11 +109,14 @@ var AgUiThreadRuntimeCore = class {
|
|
|
99
109
|
return () => this.listeners.delete(listener);
|
|
100
110
|
};
|
|
101
111
|
getSnapshot = () => this.snapshot ??= {
|
|
102
|
-
isLoading: this.
|
|
103
|
-
isRunning: this.
|
|
112
|
+
isLoading: this.state.isLoading,
|
|
113
|
+
isRunning: this.state.isRunning,
|
|
104
114
|
messageRepository: this.session.export(),
|
|
105
|
-
state: this.stateSnapshot
|
|
115
|
+
state: this.state.stateSnapshot
|
|
106
116
|
};
|
|
117
|
+
dispatch(action) {
|
|
118
|
+
this.state = reduceAgUiThreadState(this.state, action);
|
|
119
|
+
}
|
|
107
120
|
publishUpdate() {
|
|
108
121
|
this.snapshot = void 0;
|
|
109
122
|
for (const listener of this.listeners) listener();
|
|
@@ -120,7 +133,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
120
133
|
this.onCancel = options.onCancel;
|
|
121
134
|
const previousHistory = this.history;
|
|
122
135
|
this.history = options.history;
|
|
123
|
-
if (this.
|
|
136
|
+
if (this.state.loadRequested && !this._loadPromise && !previousHistory && options.history && this.session.getMessages().length === 0) this.__internal_load();
|
|
124
137
|
}
|
|
125
138
|
attachRuntime(runtime) {
|
|
126
139
|
this.runtime = runtime;
|
|
@@ -138,16 +151,16 @@ var AgUiThreadRuntimeCore = class {
|
|
|
138
151
|
return this.session.export();
|
|
139
152
|
}
|
|
140
153
|
getState() {
|
|
141
|
-
return this.stateSnapshot;
|
|
154
|
+
return this.state.stateSnapshot;
|
|
142
155
|
}
|
|
143
156
|
isRunning() {
|
|
144
|
-
return this.
|
|
157
|
+
return this.state.isRunning;
|
|
145
158
|
}
|
|
146
159
|
get isLoading() {
|
|
147
|
-
return this.
|
|
160
|
+
return this.state.isLoading;
|
|
148
161
|
}
|
|
149
162
|
__internal_load() {
|
|
150
|
-
this.
|
|
163
|
+
this.dispatch({ type: "loadRequested" });
|
|
151
164
|
if (this._loadPromise) return this._loadPromise;
|
|
152
165
|
if (!this.history) return Promise.resolve();
|
|
153
166
|
const promise = this.history.load().then((repo) => {
|
|
@@ -161,7 +174,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
161
174
|
if (repo.state !== void 0) this.loadExternalState(repo.state);
|
|
162
175
|
return repo;
|
|
163
176
|
});
|
|
164
|
-
this.
|
|
177
|
+
this.dispatch({ type: "loadStarted" });
|
|
165
178
|
this._historyImportPromise = promise.then(() => {
|
|
166
179
|
this._historyImportPromise = void 0;
|
|
167
180
|
}, () => {
|
|
@@ -171,13 +184,13 @@ var AgUiThreadRuntimeCore = class {
|
|
|
171
184
|
if (repo?.unstable_resume) {
|
|
172
185
|
const parentId = repo.headId ?? this.session.headId;
|
|
173
186
|
const resumeStream = this.history?.resume?.bind(this.history);
|
|
174
|
-
await this.startRun(parentId, this.lastRunConfig, void 0, resumeStream);
|
|
187
|
+
await this.startRun(parentId, this.state.lastRunConfig, void 0, resumeStream);
|
|
175
188
|
}
|
|
176
189
|
}).catch((error) => {
|
|
177
190
|
this.logger.error?.("[agui] failed to load history", error);
|
|
178
191
|
this.reportError(error);
|
|
179
192
|
}).finally(() => {
|
|
180
|
-
this.
|
|
193
|
+
this.dispatch({ type: "loadFinished" });
|
|
181
194
|
this.publishUpdate();
|
|
182
195
|
});
|
|
183
196
|
this.publishUpdate();
|
|
@@ -186,15 +199,15 @@ var AgUiThreadRuntimeCore = class {
|
|
|
186
199
|
waitForHistoryImport() {
|
|
187
200
|
const historyImport = this._historyImportPromise;
|
|
188
201
|
if (!historyImport) return void 0;
|
|
189
|
-
const generation = this.historyMutationGeneration;
|
|
190
|
-
return historyImport.then(() => generation === this.historyMutationGeneration && !this.isThreadSwitching?.());
|
|
202
|
+
const generation = this.state.historyMutationGeneration;
|
|
203
|
+
return historyImport.then(() => generation === this.state.historyMutationGeneration && !this.isThreadSwitching?.());
|
|
191
204
|
}
|
|
192
205
|
deferUntilHistoryImported(callback) {
|
|
193
206
|
const historyImport = this._historyImportPromise;
|
|
194
207
|
if (!historyImport) return false;
|
|
195
|
-
const generation = this.historyMutationGeneration;
|
|
208
|
+
const generation = this.state.historyMutationGeneration;
|
|
196
209
|
historyImport.then(() => {
|
|
197
|
-
if (generation !== this.historyMutationGeneration || this.isThreadSwitching?.()) return;
|
|
210
|
+
if (generation !== this.state.historyMutationGeneration || this.isThreadSwitching?.()) return;
|
|
198
211
|
try {
|
|
199
212
|
callback();
|
|
200
213
|
} catch (error) {
|
|
@@ -207,9 +220,9 @@ var AgUiThreadRuntimeCore = class {
|
|
|
207
220
|
const historyImport = this._historyImportPromise;
|
|
208
221
|
if (historyImport) {
|
|
209
222
|
const wasAtTail = message.parentId === this.session.headId;
|
|
210
|
-
const generation = this.historyMutationGeneration;
|
|
223
|
+
const generation = this.state.historyMutationGeneration;
|
|
211
224
|
await historyImport;
|
|
212
|
-
if (generation !== this.historyMutationGeneration || this.isThreadSwitching?.()) return;
|
|
225
|
+
if (generation !== this.state.historyMutationGeneration || this.isThreadSwitching?.()) return;
|
|
213
226
|
if (wasAtTail) message = {
|
|
214
227
|
...message,
|
|
215
228
|
parentId: this.session.headId
|
|
@@ -235,10 +248,10 @@ var AgUiThreadRuntimeCore = class {
|
|
|
235
248
|
}
|
|
236
249
|
maybeAutoCancelPendingToolCalls() {
|
|
237
250
|
if (this.autoCancelPendingToolCalls === false) return;
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
251
|
+
for (const assistant of this.getPendingToolCallMessages()) {
|
|
252
|
+
this.cancelUnresolvedToolCalls(assistant.id);
|
|
253
|
+
this.maybeCompleteAfterToolResults(assistant.id);
|
|
254
|
+
}
|
|
242
255
|
}
|
|
243
256
|
appendEntry(message) {
|
|
244
257
|
const threadMessage = this.toThreadMessage(message);
|
|
@@ -260,7 +273,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
260
273
|
await this.startRun(parentId, config.runConfig);
|
|
261
274
|
}
|
|
262
275
|
async cancel() {
|
|
263
|
-
this.
|
|
276
|
+
this.dispatch({ type: "historyMutationAdvanced" });
|
|
264
277
|
this.abortActiveRun();
|
|
265
278
|
}
|
|
266
279
|
abortActiveRun() {
|
|
@@ -286,7 +299,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
286
299
|
const historyImport = this.waitForHistoryImport();
|
|
287
300
|
if (historyImport && !await historyImport) return;
|
|
288
301
|
this.assertNoPendingInterrupts();
|
|
289
|
-
await this.startRun(config.parentId, config.runConfig ?? this.lastRunConfig, void 0, config.stream);
|
|
302
|
+
await this.startRun(config.parentId, config.runConfig ?? this.state.lastRunConfig, void 0, config.stream);
|
|
290
303
|
}
|
|
291
304
|
async resumeInFlightRun(messages) {
|
|
292
305
|
const historyImport = this.waitForHistoryImport();
|
|
@@ -300,7 +313,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
300
313
|
}
|
|
301
314
|
const parentId = messages.at(-1)?.id ?? null;
|
|
302
315
|
try {
|
|
303
|
-
await this.startRun(parentId, this.lastRunConfig, void 0, resumeStream);
|
|
316
|
+
await this.startRun(parentId, this.state.lastRunConfig, void 0, resumeStream);
|
|
304
317
|
} catch {}
|
|
305
318
|
}
|
|
306
319
|
assertNoPendingInterrupts() {
|
|
@@ -312,6 +325,19 @@ var AgUiThreadRuntimeCore = class {
|
|
|
312
325
|
if (!assistant || assistant.status?.type !== "requires-action" || assistant.status.reason !== reason) return null;
|
|
313
326
|
return assistant;
|
|
314
327
|
}
|
|
328
|
+
getTrailingAssistantTurn() {
|
|
329
|
+
const messages = this.getMessages();
|
|
330
|
+
const turn = [];
|
|
331
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
332
|
+
const message = messages[index];
|
|
333
|
+
if (message?.role !== "assistant") break;
|
|
334
|
+
turn.unshift(message);
|
|
335
|
+
}
|
|
336
|
+
return turn;
|
|
337
|
+
}
|
|
338
|
+
getPendingToolCallMessages() {
|
|
339
|
+
return this.getTrailingAssistantTurn().filter((message) => message.status?.type === "requires-action" && message.status.reason === "tool-calls");
|
|
340
|
+
}
|
|
315
341
|
getPendingInterrupts() {
|
|
316
342
|
const assistant = this.findRequiresActionAssistant("interrupt");
|
|
317
343
|
if (!assistant) return null;
|
|
@@ -323,16 +349,18 @@ var AgUiThreadRuntimeCore = class {
|
|
|
323
349
|
};
|
|
324
350
|
}
|
|
325
351
|
getPendingToolCalls() {
|
|
326
|
-
const assistant = this.findRequiresActionAssistant("tool-calls");
|
|
327
|
-
if (!assistant) return null;
|
|
328
352
|
const toolCallIds = [];
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
353
|
+
let messageId;
|
|
354
|
+
for (const assistant of this.getPendingToolCallMessages()) {
|
|
355
|
+
const listed = listedPendingToolCallIds(assistant);
|
|
356
|
+
for (const part of iterateToolCallParts(assistant.content)) {
|
|
357
|
+
if (isResolvedToolCall(part) || listed && !listed.has(part.toolCallId)) continue;
|
|
358
|
+
messageId ??= assistant.id;
|
|
359
|
+
toolCallIds.push(part.toolCallId);
|
|
360
|
+
}
|
|
332
361
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
messageId: assistant.id,
|
|
362
|
+
return messageId === void 0 ? null : {
|
|
363
|
+
messageId,
|
|
336
364
|
toolCallIds
|
|
337
365
|
};
|
|
338
366
|
}
|
|
@@ -345,7 +373,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
345
373
|
const openIds = pending.interrupts.map((i) => i.id);
|
|
346
374
|
const missing = openIds.filter((id) => !responsesById.has(id));
|
|
347
375
|
if (missing.length > 0) throw new Error(`[agui] submitInterruptResponses: missing responses for open interrupts: ${missing.join(", ")}`);
|
|
348
|
-
this.assertInterruptsAnswerable("submitInterruptResponses", pending.interrupts);
|
|
376
|
+
this.assertInterruptsAnswerable("submitInterruptResponses", pending.interrupts, responsesById);
|
|
349
377
|
await this.resumeWithResponses(pending.messageId, openIds.map((id) => responsesById.get(id)));
|
|
350
378
|
}
|
|
351
379
|
/**
|
|
@@ -356,7 +384,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
356
384
|
*/
|
|
357
385
|
async resumeWithResponses(messageId, resume) {
|
|
358
386
|
this.clearPendingInterrupts(messageId, resume);
|
|
359
|
-
await this.startRun(messageId, this.lastRunConfig, {
|
|
387
|
+
await this.startRun(messageId, this.state.lastRunConfig, {
|
|
360
388
|
entries: resume,
|
|
361
389
|
interruptedMessageId: messageId
|
|
362
390
|
});
|
|
@@ -375,15 +403,15 @@ var AgUiThreadRuntimeCore = class {
|
|
|
375
403
|
}
|
|
376
404
|
invokeRuntimeCallback("onError", this.onError, error instanceof Error ? error : new Error(String(error)));
|
|
377
405
|
}
|
|
378
|
-
assertInterruptsAnswerable(method, interrupts) {
|
|
406
|
+
assertInterruptsAnswerable(method, interrupts, responsesById) {
|
|
379
407
|
const now = Date.now();
|
|
380
408
|
for (const interrupt of interrupts) {
|
|
381
409
|
if (!interrupt.expiresAt) continue;
|
|
382
410
|
const expiry = new Date(interrupt.expiresAt).getTime();
|
|
383
411
|
if (Number.isNaN(expiry)) throw new Error(`[agui] ${method}: interrupt ${interrupt.id} has malformed expiresAt "${interrupt.expiresAt}"`);
|
|
384
|
-
if (expiry <= now) throw new Error(`[agui] ${method}: interrupt ${interrupt.id} expired at ${interrupt.expiresAt}`);
|
|
412
|
+
if (expiry <= now && responsesById?.get(interrupt.id)?.status !== "cancelled") throw new Error(`[agui] ${method}: interrupt ${interrupt.id} expired at ${interrupt.expiresAt}`);
|
|
385
413
|
}
|
|
386
|
-
if (this.
|
|
414
|
+
if (this.state.isRunning) throw new Error(`[agui] ${method}: a run is already in progress`);
|
|
387
415
|
}
|
|
388
416
|
async respondToToolApproval(options) {
|
|
389
417
|
const historyImport = this.waitForHistoryImport();
|
|
@@ -415,12 +443,13 @@ var AgUiThreadRuntimeCore = class {
|
|
|
415
443
|
if (historyImport && !await historyImport) return;
|
|
416
444
|
const pending = this.getPendingInterrupts();
|
|
417
445
|
if (!pending) {
|
|
418
|
-
|
|
419
|
-
if (pendingTools) {
|
|
446
|
+
if (this.getPendingToolCalls()) {
|
|
420
447
|
if (responses?.length) throw new Error("[agui] steerAway: responses are only valid for pending interrupts");
|
|
421
|
-
if (this.
|
|
422
|
-
this.
|
|
423
|
-
|
|
448
|
+
if (this.state.isRunning) throw new Error("[agui] steerAway: a run is already in progress");
|
|
449
|
+
for (const assistant of this.getPendingToolCallMessages()) {
|
|
450
|
+
this.cancelUnresolvedToolCalls(assistant.id);
|
|
451
|
+
this.maybeCompleteAfterToolResults(assistant.id);
|
|
452
|
+
}
|
|
424
453
|
const normalized = this.toAppendMessage(message);
|
|
425
454
|
const threadMessageId = this.appendEntry(normalized);
|
|
426
455
|
await this.startRun(threadMessageId, normalized.runConfig);
|
|
@@ -431,7 +460,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
431
460
|
return;
|
|
432
461
|
}
|
|
433
462
|
const resume = this.resolveSteerAwayResume(pending.interrupts, responses);
|
|
434
|
-
if (this.
|
|
463
|
+
if (this.state.isRunning) throw new Error("[agui] steerAway: a run is already in progress");
|
|
435
464
|
const normalized = this.toAppendMessage(message);
|
|
436
465
|
this.clearPendingInterrupts(pending.messageId, resume);
|
|
437
466
|
const threadMessageId = this.appendEntry(normalized);
|
|
@@ -597,7 +626,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
597
626
|
const message = this.session.tryGetMessage(sessionMessageId)?.message;
|
|
598
627
|
const history = this.history;
|
|
599
628
|
if (!message || !history?.update || !this.isPersistableStatus(message.status)) return;
|
|
600
|
-
await this.
|
|
629
|
+
await this.historyWrites.chain(sessionMessageId, () => history.update({
|
|
601
630
|
parentId: item.parentId,
|
|
602
631
|
message
|
|
603
632
|
}));
|
|
@@ -614,25 +643,38 @@ var AgUiThreadRuntimeCore = class {
|
|
|
614
643
|
const userAction = { ...action };
|
|
615
644
|
delete userAction.type;
|
|
616
645
|
if (!("timestamp" in userAction)) userAction.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
617
|
-
this.
|
|
646
|
+
this.dispatch({
|
|
647
|
+
type: "a2uiActionDeferred",
|
|
648
|
+
action: userAction
|
|
649
|
+
});
|
|
618
650
|
const owner = this.abortController;
|
|
619
651
|
if (owner) {
|
|
620
|
-
this.
|
|
652
|
+
this.dispatch({
|
|
653
|
+
type: "a2uiResumeDeferred",
|
|
654
|
+
owner
|
|
655
|
+
});
|
|
621
656
|
return;
|
|
622
657
|
}
|
|
623
658
|
this.startResumeRun(parentId);
|
|
624
659
|
}
|
|
625
660
|
maybeResumeAfterToolResults(messageId) {
|
|
626
661
|
if (!this.maybeCompleteAfterToolResults(messageId)) return;
|
|
662
|
+
if (this.getPendingInterrupts()) return;
|
|
663
|
+
const turn = this.getTrailingAssistantTurn();
|
|
664
|
+
if (!turn.some((message) => message.id === messageId)) return;
|
|
665
|
+
if (this.getPendingToolCalls()) return;
|
|
666
|
+
const headId = turn.at(-1)?.id;
|
|
667
|
+
if (headId === void 0) return;
|
|
627
668
|
const owner = this.abortController;
|
|
628
669
|
if (owner) {
|
|
629
|
-
this.
|
|
670
|
+
this.dispatch({
|
|
671
|
+
type: "resumeDeferred",
|
|
630
672
|
owner,
|
|
631
|
-
messageId
|
|
632
|
-
};
|
|
673
|
+
messageId: headId
|
|
674
|
+
});
|
|
633
675
|
return;
|
|
634
676
|
}
|
|
635
|
-
this.startResumeRun(
|
|
677
|
+
this.startResumeRun(headId);
|
|
636
678
|
}
|
|
637
679
|
maybeCompleteAfterToolResults(messageId) {
|
|
638
680
|
const message = this.session.tryGetMessage(messageId)?.message;
|
|
@@ -640,9 +682,13 @@ var AgUiThreadRuntimeCore = class {
|
|
|
640
682
|
const assistant = message;
|
|
641
683
|
if (assistant.status?.type !== "requires-action" || assistant.status.reason !== "tool-calls") return false;
|
|
642
684
|
let allResolved = true;
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
685
|
+
const listed = listedPendingToolCallIds(assistant);
|
|
686
|
+
for (const part of iterateToolCallParts(assistant.content)) {
|
|
687
|
+
if (listed && !listed.has(part.toolCallId)) continue;
|
|
688
|
+
if (!isResolvedToolCall(part)) {
|
|
689
|
+
allResolved = false;
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
646
692
|
}
|
|
647
693
|
if (!allResolved) return false;
|
|
648
694
|
if (!this.session.updateMessage(messageId, (current) => current.role === "assistant" ? {
|
|
@@ -650,14 +696,15 @@ var AgUiThreadRuntimeCore = class {
|
|
|
650
696
|
status: {
|
|
651
697
|
type: "complete",
|
|
652
698
|
reason: "unknown"
|
|
653
|
-
}
|
|
699
|
+
},
|
|
700
|
+
metadata: withoutPendingToolCallIds(current.metadata)
|
|
654
701
|
} : current)) return false;
|
|
655
702
|
this.publishUpdate();
|
|
656
703
|
this.persistAssistantHistory(messageId);
|
|
657
704
|
return true;
|
|
658
705
|
}
|
|
659
706
|
startResumeRun(messageId) {
|
|
660
|
-
this.startRun(messageId, this.lastRunConfig).catch((error) => {
|
|
707
|
+
this.startRun(messageId, this.state.lastRunConfig).catch((error) => {
|
|
661
708
|
this.reportError(error);
|
|
662
709
|
});
|
|
663
710
|
}
|
|
@@ -674,8 +721,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
674
721
|
}
|
|
675
722
|
};
|
|
676
723
|
});
|
|
677
|
-
this.
|
|
678
|
-
this.pendingA2uiAction = void 0;
|
|
724
|
+
this.dispatch({ type: "a2uiContinuationsCleared" });
|
|
679
725
|
this.assistantHistoryParents.clear();
|
|
680
726
|
if (messages.length === 0) this.session.clear();
|
|
681
727
|
else {
|
|
@@ -712,30 +758,34 @@ var AgUiThreadRuntimeCore = class {
|
|
|
712
758
|
}
|
|
713
759
|
this.snapshotHistoryIds.clear();
|
|
714
760
|
for (const { message } of this.getMessageRepository().messages) this.snapshotHistoryIds.add(message.id);
|
|
715
|
-
const resumeTarget = this.pendingResume?.messageId;
|
|
716
|
-
if (resumeTarget !== void 0 && !this.session.getMessages().some((message) => message.id === resumeTarget)) this.
|
|
761
|
+
const resumeTarget = this.state.pendingResume?.messageId;
|
|
762
|
+
if (resumeTarget !== void 0 && !this.session.getMessages().some((message) => message.id === resumeTarget)) this.dispatch({ type: "resumeCleared" });
|
|
717
763
|
this.publishUpdate();
|
|
718
764
|
}
|
|
719
765
|
loadExternalState(state) {
|
|
720
|
-
this.
|
|
766
|
+
this.dispatch({
|
|
767
|
+
type: "stateSnapshot",
|
|
768
|
+
snapshot: state
|
|
769
|
+
});
|
|
721
770
|
this.publishUpdate();
|
|
722
771
|
}
|
|
723
772
|
setState(next) {
|
|
724
|
-
|
|
773
|
+
const snapshot = typeof next === "function" ? next(this.state.stateSnapshot) : next;
|
|
774
|
+
this.dispatch({
|
|
775
|
+
type: "stateSnapshot",
|
|
776
|
+
snapshot
|
|
777
|
+
});
|
|
725
778
|
this.publishUpdate();
|
|
726
779
|
}
|
|
727
780
|
resetState() {
|
|
728
|
-
this.
|
|
781
|
+
this.dispatch({ type: "resetState" });
|
|
729
782
|
this.publishUpdate();
|
|
730
783
|
}
|
|
731
784
|
resetThreadState() {
|
|
732
|
-
this.
|
|
785
|
+
this.dispatch({ type: "historyMutationAdvanced" });
|
|
733
786
|
const controller = this.abortController;
|
|
734
787
|
const activeRunAgent = this.activeRunAgent;
|
|
735
|
-
this.
|
|
736
|
-
this.pendingResume = null;
|
|
737
|
-
this.pendingA2uiResumeOwner = null;
|
|
738
|
-
this.pendingA2uiAction = void 0;
|
|
788
|
+
this.dispatch({ type: "resetThread" });
|
|
739
789
|
if (controller) {
|
|
740
790
|
this.abortController = null;
|
|
741
791
|
this.activeRunAgent = null;
|
|
@@ -753,7 +803,10 @@ var AgUiThreadRuntimeCore = class {
|
|
|
753
803
|
if (this.isThreadSwitching?.()) return;
|
|
754
804
|
if (!this.supersedeActiveRun()) return;
|
|
755
805
|
const normalizedRunConfig = runConfig ?? {};
|
|
756
|
-
this.
|
|
806
|
+
this.dispatch({
|
|
807
|
+
type: "runConfigRecorded",
|
|
808
|
+
runConfig: normalizedRunConfig
|
|
809
|
+
});
|
|
757
810
|
const parent = parentId === null ? void 0 : this.session.tryGetMessage(parentId);
|
|
758
811
|
const shouldEagerlyInsertAssistant = parentId !== null && parent !== void 0 && parentId !== this.session.headId;
|
|
759
812
|
const historicalMessages = [...shouldEagerlyInsertAssistant ? this.session.tryGetMessages(parentId) ?? this.session.getMessages() : this.session.getMessages()];
|
|
@@ -764,6 +817,9 @@ var AgUiThreadRuntimeCore = class {
|
|
|
764
817
|
const assistantParentId = parent ? parentId : this.session.headId;
|
|
765
818
|
let assistantMessageId;
|
|
766
819
|
let assistantCollided = false;
|
|
820
|
+
const heldMessages = /* @__PURE__ */ new Map();
|
|
821
|
+
let restrictedPendingToolCallIds;
|
|
822
|
+
let settlingRun = false;
|
|
767
823
|
const ensureAssistant = (allowRecreate = false) => {
|
|
768
824
|
const cached = assistantMessageId;
|
|
769
825
|
if (cached !== void 0 && this.session.tryGetMessage(cached)) return cached;
|
|
@@ -776,14 +832,58 @@ var AgUiThreadRuntimeCore = class {
|
|
|
776
832
|
return created;
|
|
777
833
|
};
|
|
778
834
|
if (shouldEagerlyInsertAssistant) ensureAssistant();
|
|
835
|
+
const settleHeldMessages = (terminalStatus) => {
|
|
836
|
+
const pendingMessages = [];
|
|
837
|
+
for (const [messageId, openToolCallIds] of heldMessages) {
|
|
838
|
+
let requiresToolResult = false;
|
|
839
|
+
if (this.session.updateMessage(messageId, (message) => {
|
|
840
|
+
if (message.role !== "assistant") return message;
|
|
841
|
+
const assistant = message;
|
|
842
|
+
const pendingToolCallIds = Array.from(openToolCallIds).filter((id) => !restrictedPendingToolCallIds || restrictedPendingToolCallIds.has(id));
|
|
843
|
+
const status = terminalStatus.type === "complete" || terminalStatus.type === "requires-action" ? pendingToolCallIds.length > 0 ? {
|
|
844
|
+
type: "requires-action",
|
|
845
|
+
reason: "tool-calls"
|
|
846
|
+
} : {
|
|
847
|
+
type: "complete",
|
|
848
|
+
reason: "unknown"
|
|
849
|
+
} : terminalStatus;
|
|
850
|
+
requiresToolResult = status.type === "requires-action";
|
|
851
|
+
const metadata = withoutPendingToolCallIds(assistant.metadata);
|
|
852
|
+
return {
|
|
853
|
+
...assistant,
|
|
854
|
+
status,
|
|
855
|
+
metadata: status.type === "requires-action" && restrictedPendingToolCallIds ? {
|
|
856
|
+
...metadata,
|
|
857
|
+
custom: {
|
|
858
|
+
...metadata.custom,
|
|
859
|
+
["agui"]: {
|
|
860
|
+
...metadata.custom["agui"],
|
|
861
|
+
pendingToolCallIds
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
} : metadata
|
|
865
|
+
};
|
|
866
|
+
})) {
|
|
867
|
+
this.publishUpdate();
|
|
868
|
+
this.persistAssistantHistory(messageId);
|
|
869
|
+
if (requiresToolResult) pendingMessages.push(messageId);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
heldMessages.clear();
|
|
873
|
+
return pendingMessages;
|
|
874
|
+
};
|
|
779
875
|
const applyUpdate = (update) => {
|
|
876
|
+
const terminalStatus = update.status;
|
|
877
|
+
const pendingMessages = settlingRun && terminalStatus && terminalStatus.type !== "running" ? settleHeldMessages(terminalStatus) : [];
|
|
780
878
|
const hasStreamContent = Array.isArray(update.content) && update.content.some((part) => part.type !== "data");
|
|
781
879
|
const resolved = this.updateAssistantMessage(ensureAssistant(hasStreamContent), update);
|
|
782
880
|
if (resolved !== assistantMessageId) assistantMessageId = resolved;
|
|
881
|
+
for (const messageId of pendingMessages) this.maybeResumeAfterToolResults(messageId);
|
|
783
882
|
};
|
|
784
|
-
const adoptServerMessageId = (serverId, startNewMessage) => {
|
|
883
|
+
const adoptServerMessageId = (serverId, startNewMessage, openToolCallIds = []) => {
|
|
785
884
|
if (startNewMessage && assistantMessageId !== void 0) {
|
|
786
|
-
|
|
885
|
+
if (openToolCallIds.length > 0) heldMessages.set(assistantMessageId, new Set(openToolCallIds));
|
|
886
|
+
else applyUpdate({ status: {
|
|
787
887
|
type: "complete",
|
|
788
888
|
reason: "unknown"
|
|
789
889
|
} });
|
|
@@ -817,14 +917,24 @@ var AgUiThreadRuntimeCore = class {
|
|
|
817
917
|
onServerMessageId: (serverId) => {
|
|
818
918
|
adoptServerMessageId(serverId, false);
|
|
819
919
|
},
|
|
820
|
-
onTextMessageStart: (serverId) => adoptServerMessageId(serverId, true)
|
|
920
|
+
onTextMessageStart: (serverId, openToolCallIds) => adoptServerMessageId(serverId, true, openToolCallIds)
|
|
821
921
|
});
|
|
822
922
|
let runFinished = false;
|
|
823
923
|
const dispatch = (event) => {
|
|
824
924
|
if (this.abortController !== abortController) return;
|
|
825
|
-
if (event.type === "RUN_FINISHED")
|
|
826
|
-
|
|
827
|
-
|
|
925
|
+
if (event.type === "RUN_FINISHED") {
|
|
926
|
+
runFinished = true;
|
|
927
|
+
const ids = event.outcome?.type === "success" ? event.outcome.pendingToolCallIds : void 0;
|
|
928
|
+
restrictedPendingToolCallIds = ids?.length ? new Set(ids) : void 0;
|
|
929
|
+
}
|
|
930
|
+
if (event.type === "TOOL_CALL_RESULT") for (const openToolCallIds of heldMessages.values()) openToolCallIds.delete(event.toolCallId);
|
|
931
|
+
settlingRun = event.type === "RUN_FINISHED" || event.type === "RUN_ERROR" || event.type === "RUN_CANCELLED";
|
|
932
|
+
try {
|
|
933
|
+
const nextAssistantMessageId = this.handleEvent(aggregator, event, assistantMessageId, joinStrategy, runStartMessageIds, hasRunUserBoundary);
|
|
934
|
+
if (event.type === "MESSAGES_SNAPSHOT") assistantMessageId = nextAssistantMessageId;
|
|
935
|
+
} finally {
|
|
936
|
+
settlingRun = false;
|
|
937
|
+
}
|
|
828
938
|
};
|
|
829
939
|
this.abortController = abortController;
|
|
830
940
|
const runAgentInstance = this.agent;
|
|
@@ -898,16 +1008,16 @@ var AgUiThreadRuntimeCore = class {
|
|
|
898
1008
|
this.clearDeferredContinuations(abortController);
|
|
899
1009
|
throw err;
|
|
900
1010
|
}
|
|
901
|
-
if (this.pendingResume?.owner === abortController) {
|
|
902
|
-
const { messageId } = this.pendingResume;
|
|
903
|
-
this.
|
|
1011
|
+
if (this.state.pendingResume?.owner === abortController) {
|
|
1012
|
+
const { messageId } = this.state.pendingResume;
|
|
1013
|
+
this.dispatch({ type: "resumeCleared" });
|
|
904
1014
|
if (!abortSignal.aborted) this.startResumeRun(messageId);
|
|
905
1015
|
}
|
|
906
|
-
if (this.pendingA2uiResumeOwner === abortController) {
|
|
907
|
-
this.
|
|
908
|
-
if (!abortSignal.aborted && this.pendingA2uiAction !== void 0) {
|
|
1016
|
+
if (this.state.pendingA2uiResumeOwner === abortController) {
|
|
1017
|
+
this.dispatch({ type: "a2uiResumeCleared" });
|
|
1018
|
+
if (!abortSignal.aborted && this.state.pendingA2uiAction !== void 0) {
|
|
909
1019
|
if (this.getPendingInterrupts()) {
|
|
910
|
-
this.
|
|
1020
|
+
this.dispatch({ type: "a2uiActionCleared" });
|
|
911
1021
|
this.logger.debug("[agui] sendA2uiAction: pending interrupts, dropping action");
|
|
912
1022
|
return;
|
|
913
1023
|
}
|
|
@@ -915,15 +1025,14 @@ var AgUiThreadRuntimeCore = class {
|
|
|
915
1025
|
const parentId = this.session.headId;
|
|
916
1026
|
if (parentId !== null) this.startResumeRun(parentId);
|
|
917
1027
|
else {
|
|
918
|
-
this.
|
|
1028
|
+
this.dispatch({ type: "a2uiActionCleared" });
|
|
919
1029
|
this.logger.debug("[agui] sendA2uiAction: no messages to resume, dropping action");
|
|
920
1030
|
}
|
|
921
|
-
} else this.
|
|
1031
|
+
} else this.dispatch({ type: "a2uiActionCleared" });
|
|
922
1032
|
}
|
|
923
1033
|
}
|
|
924
1034
|
async consumeResumeStream(stream, ctx) {
|
|
925
|
-
this.
|
|
926
|
-
this.pendingA2uiResumeOwner = null;
|
|
1035
|
+
this.dispatch({ type: "a2uiContinuationsCleared" });
|
|
927
1036
|
const assistantId = ctx.ensureAssistant();
|
|
928
1037
|
const currentId = () => ctx.getAssistantMessageId() ?? assistantId;
|
|
929
1038
|
const options = {
|
|
@@ -964,8 +1073,8 @@ var AgUiThreadRuntimeCore = class {
|
|
|
964
1073
|
} });
|
|
965
1074
|
}
|
|
966
1075
|
buildRunInput(runId, runConfig, historyMessages, resume) {
|
|
967
|
-
const pendingA2uiAction = this.pendingA2uiAction;
|
|
968
|
-
this.
|
|
1076
|
+
const pendingA2uiAction = this.state.pendingA2uiAction;
|
|
1077
|
+
this.dispatch({ type: "a2uiActionCleared" });
|
|
969
1078
|
const threadId = this.agent.threadId || "main";
|
|
970
1079
|
const messages = toAgUiMessages(this.selectRunMessages(historyMessages ?? this.session.getMessages(), resume));
|
|
971
1080
|
const context = this.runtime?.thread.getModelContext();
|
|
@@ -983,7 +1092,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
983
1092
|
return {
|
|
984
1093
|
threadId,
|
|
985
1094
|
runId,
|
|
986
|
-
state: this.stateSnapshot ?? null,
|
|
1095
|
+
state: this.state.stateSnapshot ?? null,
|
|
987
1096
|
messages,
|
|
988
1097
|
tools: toAgUiTools(context?.tools),
|
|
989
1098
|
context: [...context?.system ? [{
|
|
@@ -1013,14 +1122,11 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1013
1122
|
return messages.slice(anchor + 1);
|
|
1014
1123
|
}
|
|
1015
1124
|
clearDeferredContinuations(owner) {
|
|
1016
|
-
if (this.pendingResume?.owner === owner) this.
|
|
1017
|
-
if (this.pendingA2uiResumeOwner === owner) {
|
|
1018
|
-
this.pendingA2uiResumeOwner = null;
|
|
1019
|
-
this.pendingA2uiAction = void 0;
|
|
1020
|
-
}
|
|
1125
|
+
if (this.state.pendingResume?.owner === owner) this.dispatch({ type: "resumeCleared" });
|
|
1126
|
+
if (this.state.pendingA2uiResumeOwner === owner) this.dispatch({ type: "a2uiContinuationsCleared" });
|
|
1021
1127
|
}
|
|
1022
1128
|
setRunning(running) {
|
|
1023
|
-
this.
|
|
1129
|
+
this.dispatch({ type: running ? "runStarted" : "runFinished" });
|
|
1024
1130
|
this.publishUpdate();
|
|
1025
1131
|
}
|
|
1026
1132
|
finishRun(controller) {
|
|
@@ -1037,7 +1143,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1037
1143
|
status: { type: "running" },
|
|
1038
1144
|
content: [],
|
|
1039
1145
|
metadata: {
|
|
1040
|
-
unstable_state: this.stateSnapshot ?? null,
|
|
1146
|
+
unstable_state: this.state.stateSnapshot ?? null,
|
|
1041
1147
|
unstable_annotations: [],
|
|
1042
1148
|
unstable_data: [],
|
|
1043
1149
|
steps: [],
|
|
@@ -1080,21 +1186,11 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1080
1186
|
ids.delete(oldId);
|
|
1081
1187
|
if (!collidesWithExisting) ids.add(newId);
|
|
1082
1188
|
}
|
|
1083
|
-
const pendingWrite = this.historyWrites.
|
|
1084
|
-
if (pendingWrite) {
|
|
1085
|
-
this.
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
const settle = () => {
|
|
1089
|
-
if (this.historyWrites.get(newId) === pendingWrite) this.historyWrites.delete(newId);
|
|
1090
|
-
};
|
|
1091
|
-
pendingWrite.then(() => {
|
|
1092
|
-
this.persistedHistoryIds.delete(oldId);
|
|
1093
|
-
this.persistedHistoryIds.add(newId);
|
|
1094
|
-
settle();
|
|
1095
|
-
}, settle);
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1189
|
+
const pendingWrite = this.historyWrites.move(oldId, collidesWithExisting ? void 0 : newId);
|
|
1190
|
+
if (pendingWrite && !collidesWithExisting) pendingWrite.then(() => {
|
|
1191
|
+
this.persistedHistoryIds.delete(oldId);
|
|
1192
|
+
this.persistedHistoryIds.add(newId);
|
|
1193
|
+
}, () => {});
|
|
1098
1194
|
this.publishUpdate();
|
|
1099
1195
|
return !collidesWithExisting;
|
|
1100
1196
|
}
|
|
@@ -1103,8 +1199,9 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1103
1199
|
if (!this.session.updateMessage(messageId, (message) => {
|
|
1104
1200
|
if (message.role !== "assistant") return message;
|
|
1105
1201
|
const assistant = message;
|
|
1106
|
-
const
|
|
1202
|
+
const mergedMetadata = update.metadata ? this.mergeAssistantMetadata(assistant.metadata, update.metadata) : assistant.metadata;
|
|
1107
1203
|
latestStatus = update.status ?? assistant.status;
|
|
1204
|
+
const metadata = latestStatus?.type === "requires-action" && latestStatus.reason === "tool-calls" ? mergedMetadata : withoutPendingToolCallIds(mergedMetadata);
|
|
1108
1205
|
const content = update.content !== void 0 ? this.preserveToolResults(assistant.content, update.content) : assistant.content;
|
|
1109
1206
|
return {
|
|
1110
1207
|
...assistant,
|
|
@@ -1243,15 +1340,20 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1243
1340
|
handleEvent(aggregator, event, activeAssistantId, joinStrategy, runStartMessageIds, hasRunUserBoundary) {
|
|
1244
1341
|
switch (event.type) {
|
|
1245
1342
|
case "STATE_SNAPSHOT":
|
|
1246
|
-
this.
|
|
1343
|
+
this.dispatch({
|
|
1344
|
+
type: "stateSnapshot",
|
|
1345
|
+
snapshot: event.snapshot
|
|
1346
|
+
});
|
|
1247
1347
|
this.updateActiveAssistantState(activeAssistantId);
|
|
1248
1348
|
break;
|
|
1249
1349
|
case "STATE_DELTA":
|
|
1250
1350
|
if (event.delta.length === 0) break;
|
|
1251
1351
|
try {
|
|
1252
|
-
const
|
|
1253
|
-
|
|
1254
|
-
|
|
1352
|
+
const result = jsonpatch.applyPatch(this.state.stateSnapshot ?? {}, event.delta, true, false);
|
|
1353
|
+
this.dispatch({
|
|
1354
|
+
type: "stateSnapshot",
|
|
1355
|
+
snapshot: result.newDocument
|
|
1356
|
+
});
|
|
1255
1357
|
this.updateActiveAssistantState(activeAssistantId);
|
|
1256
1358
|
} catch (error) {
|
|
1257
1359
|
this.logger.error?.("[agui] failed to apply state delta", error);
|
|
@@ -1302,7 +1404,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1302
1404
|
...assistant,
|
|
1303
1405
|
metadata: {
|
|
1304
1406
|
...assistant.metadata,
|
|
1305
|
-
unstable_state: this.stateSnapshot ?? null
|
|
1407
|
+
unstable_state: this.state.stateSnapshot ?? null
|
|
1306
1408
|
}
|
|
1307
1409
|
};
|
|
1308
1410
|
});
|
|
@@ -1313,25 +1415,27 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1313
1415
|
if (message.role !== "assistant") return message;
|
|
1314
1416
|
const assistant = message;
|
|
1315
1417
|
const mcpAppUri = readMcpAppResourceUri(event.mcpResult?._meta);
|
|
1418
|
+
const modelText = toolContentText(event.content);
|
|
1316
1419
|
let matchedToolCall = false;
|
|
1317
1420
|
const { content } = mapToolCallPartsDeep(assistant.content, (part) => {
|
|
1318
1421
|
if (part.toolCallId !== event.toolCallId) return part;
|
|
1319
1422
|
matchedToolCall = true;
|
|
1320
1423
|
if (part.mcp?.app !== void 0 && isPlainObject(part.result) && Array.isArray(part.result["content"])) return {
|
|
1321
1424
|
...part,
|
|
1322
|
-
...part.modelContent === void 0
|
|
1425
|
+
...part.modelContent === void 0 ? { modelContent: [{
|
|
1323
1426
|
type: "text",
|
|
1324
|
-
text:
|
|
1427
|
+
text: modelText
|
|
1325
1428
|
}] } : {},
|
|
1326
1429
|
...part.isError === void 0 ? typeof event.mcpResult?.isError === "boolean" ? { isError: event.mcpResult.isError } : event.role === "tool" ? { isError: false } : {} : {},
|
|
1327
1430
|
...event.messageId ? { unstable_toolMessageId: event.messageId } : {}
|
|
1328
1431
|
};
|
|
1432
|
+
const { modelContent: _modelContent, ...partWithoutModelContent } = part;
|
|
1329
1433
|
return {
|
|
1330
|
-
...part,
|
|
1331
|
-
result: event.mcpResult ??
|
|
1434
|
+
...event.mcpResult === void 0 && Array.isArray(event.content) ? partWithoutModelContent : part,
|
|
1435
|
+
result: event.mcpResult ?? (Array.isArray(event.content) ? event.content : tryParseJSON(event.content)),
|
|
1332
1436
|
...event.mcpResult !== void 0 ? { modelContent: [{
|
|
1333
1437
|
type: "text",
|
|
1334
|
-
text:
|
|
1438
|
+
text: modelText
|
|
1335
1439
|
}] } : {},
|
|
1336
1440
|
...typeof event.mcpResult?.isError === "boolean" ? { isError: event.mcpResult.isError } : event.role === "tool" ? { isError: false } : {},
|
|
1337
1441
|
...part.mcp === void 0 && mcpAppUri !== void 0 ? { mcp: { app: { resourceUri: mcpAppUri } } } : {},
|
|
@@ -1501,7 +1605,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1501
1605
|
const wasPersisted = this.persistedHistoryIds.has(messageId);
|
|
1502
1606
|
const update = history.update;
|
|
1503
1607
|
if (update !== void 0 && (wasPersisted || this.snapshotHistoryIds.has(messageId))) {
|
|
1504
|
-
const write = this.
|
|
1608
|
+
const write = this.historyWrites.chain(messageId, () => update.call(history, {
|
|
1505
1609
|
parentId,
|
|
1506
1610
|
message
|
|
1507
1611
|
}));
|
|
@@ -1509,7 +1613,7 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1509
1613
|
write.then(() => {
|
|
1510
1614
|
this.persistedHistoryIds.add(messageId);
|
|
1511
1615
|
}, (error) => {
|
|
1512
|
-
const pending = this.historyWrites.
|
|
1616
|
+
const pending = this.historyWrites.pending(messageId);
|
|
1513
1617
|
if (pending === void 0 || pending === write) this.assistantHistoryParents.set(messageId, parentId);
|
|
1514
1618
|
this.logger.error?.("[agui] failed to update history entry", error);
|
|
1515
1619
|
});
|
|
@@ -1523,17 +1627,17 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1523
1627
|
if (!write) return;
|
|
1524
1628
|
this.assistantHistoryParents.delete(messageId);
|
|
1525
1629
|
write.then(() => {}, (error) => {
|
|
1526
|
-
const pending = this.historyWrites.
|
|
1630
|
+
const pending = this.historyWrites.pending(messageId);
|
|
1527
1631
|
if (pending === void 0 || pending === write) this.assistantHistoryParents.set(messageId, parentId);
|
|
1528
1632
|
this.logger.error?.("[agui] failed to append history entry", error);
|
|
1529
1633
|
});
|
|
1530
1634
|
}
|
|
1531
1635
|
appendHistoryItem(parentId, message) {
|
|
1532
1636
|
if (!this.history || this.persistedHistoryIds.has(message.id)) return;
|
|
1533
|
-
const pending = this.historyWrites.
|
|
1637
|
+
const pending = this.historyWrites.pending(message.id);
|
|
1534
1638
|
if (pending) return pending;
|
|
1535
1639
|
const append = this.history.append.bind(this.history);
|
|
1536
|
-
const write = this.
|
|
1640
|
+
const write = this.historyWrites.chain(message.id, () => append({
|
|
1537
1641
|
parentId,
|
|
1538
1642
|
message
|
|
1539
1643
|
}));
|
|
@@ -1542,25 +1646,8 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1542
1646
|
}, () => {});
|
|
1543
1647
|
return write;
|
|
1544
1648
|
}
|
|
1545
|
-
chainHistoryWrite(id, write) {
|
|
1546
|
-
const pending = this.historyWrites.get(id);
|
|
1547
|
-
let next;
|
|
1548
|
-
if (pending) next = pending.then(write, write);
|
|
1549
|
-
else try {
|
|
1550
|
-
next = Promise.resolve(write());
|
|
1551
|
-
} catch (error) {
|
|
1552
|
-
next = Promise.reject(error);
|
|
1553
|
-
}
|
|
1554
|
-
this.historyWrites.set(id, next);
|
|
1555
|
-
next.then(() => {
|
|
1556
|
-
if (this.historyWrites.get(id) === next) this.historyWrites.delete(id);
|
|
1557
|
-
}, () => {
|
|
1558
|
-
if (this.historyWrites.get(id) === next) this.historyWrites.delete(id);
|
|
1559
|
-
});
|
|
1560
|
-
return next;
|
|
1561
|
-
}
|
|
1562
1649
|
};
|
|
1563
1650
|
//#endregion
|
|
1564
|
-
export {
|
|
1651
|
+
export { AgUiThreadController };
|
|
1565
1652
|
|
|
1566
|
-
//# sourceMappingURL=
|
|
1653
|
+
//# sourceMappingURL=AgUiThreadController.js.map
|