@assistant-ui/react-ag-ui 0.0.57 → 0.0.58
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 +16 -0
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts +3 -4
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js +29 -43
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +34 -11
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +13 -3
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +326 -119
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/adapter/subscriber.d.ts +9 -0
- package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
- package/dist/runtime/adapter/subscriber.js +4 -1
- package/dist/runtime/adapter/subscriber.js.map +1 -1
- package/dist/runtime/adapter/tool-approval.d.ts +3 -1
- package/dist/runtime/adapter/tool-approval.d.ts.map +1 -1
- package/dist/runtime/adapter/tool-approval.js +11 -12
- package/dist/runtime/adapter/tool-approval.js.map +1 -1
- package/dist/runtime/event-parser.d.ts.map +1 -1
- package/dist/runtime/event-parser.js +176 -45
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/types.d.ts +42 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js +1 -0
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +9 -9
- package/src/runtime/AgUiThreadRuntimeCore.ts +40 -60
- package/src/runtime/adapter/conversions.ts +87 -17
- package/src/runtime/adapter/run-aggregator.approval.test.ts +128 -0
- package/src/runtime/adapter/run-aggregator.ts +510 -139
- package/src/runtime/adapter/subscriber.ts +10 -1
- package/src/runtime/adapter/tool-approval.test.ts +75 -0
- package/src/runtime/adapter/tool-approval.ts +17 -12
- package/src/runtime/event-parser.ts +216 -36
- package/src/runtime/types.ts +70 -12
- package/src/useAgUiRuntime.approval.test.tsx +34 -24
- package/src/useAgUiRuntime.toolDeferral.test.tsx +186 -0
- package/src/useAgUiRuntime.ts +1 -0
|
@@ -5,6 +5,8 @@ import { isMcpAppUri } from "@assistant-ui/core";
|
|
|
5
5
|
import { applyA2uiOperations, convertSurfaceToUISpec } from "@assistant-ui/react-generative-ui/a2ui";
|
|
6
6
|
//#region src/runtime/adapter/run-aggregator.ts
|
|
7
7
|
const AG_UI_METADATA_NAMESPACE = "agui";
|
|
8
|
+
const ROOT_SCOPE = "";
|
|
9
|
+
const MAX_SUBAGENT_DEPTH = 16;
|
|
8
10
|
const MCP_APPS_ACTIVITY_TYPE = "mcp-apps";
|
|
9
11
|
const A2UI_SURFACE_ACTIVITY_TYPE = "a2ui-surface";
|
|
10
12
|
const isPlainObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -27,7 +29,7 @@ var RunAggregator = class {
|
|
|
27
29
|
status;
|
|
28
30
|
interrupts;
|
|
29
31
|
textParts = /* @__PURE__ */ new Map();
|
|
30
|
-
|
|
32
|
+
activeTextMessageIdByScope = /* @__PURE__ */ new Map();
|
|
31
33
|
reasoningParts = /* @__PURE__ */ new Map();
|
|
32
34
|
reasoningSignatures = /* @__PURE__ */ new Map();
|
|
33
35
|
reasoningSignatureIds = /* @__PURE__ */ new Map();
|
|
@@ -41,12 +43,14 @@ var RunAggregator = class {
|
|
|
41
43
|
loggedDroppedOpaqueIds = /* @__PURE__ */ new Set();
|
|
42
44
|
reasoningMessageIds = /* @__PURE__ */ new Map();
|
|
43
45
|
anonymousReasoningKeys = /* @__PURE__ */ new Set();
|
|
44
|
-
|
|
46
|
+
activeReasoningKeyByScope = /* @__PURE__ */ new Map();
|
|
47
|
+
subagentRuns = /* @__PURE__ */ new Map();
|
|
48
|
+
nestingMemo;
|
|
45
49
|
reasoningPartCounter = 0;
|
|
46
50
|
toolCalls = /* @__PURE__ */ new Map();
|
|
47
51
|
a2uiBuckets = /* @__PURE__ */ new Map();
|
|
48
52
|
a2uiToolCallIds = /* @__PURE__ */ new Set();
|
|
49
|
-
|
|
53
|
+
lastResolvedToolCallIdByScope = /* @__PURE__ */ new Map();
|
|
50
54
|
partOrder = [];
|
|
51
55
|
textPartCounter = 0;
|
|
52
56
|
serverMessageIdReported = false;
|
|
@@ -91,13 +95,14 @@ var RunAggregator = class {
|
|
|
91
95
|
}
|
|
92
96
|
this.interrupts = void 0;
|
|
93
97
|
const hasUnresolvedToolCalls = Array.from(this.toolCalls.values()).some((tc) => tc.result === void 0);
|
|
94
|
-
this.status =
|
|
95
|
-
type: "complete",
|
|
96
|
-
reason: "unknown"
|
|
97
|
-
} : {
|
|
98
|
+
this.status = hasUnresolvedToolCalls ? {
|
|
98
99
|
type: "requires-action",
|
|
99
100
|
reason: "tool-calls"
|
|
101
|
+
} : {
|
|
102
|
+
type: "complete",
|
|
103
|
+
reason: "unknown"
|
|
100
104
|
};
|
|
105
|
+
this.closeOpenSubagentRuns(this.status);
|
|
101
106
|
this.emit();
|
|
102
107
|
break;
|
|
103
108
|
}
|
|
@@ -107,6 +112,7 @@ var RunAggregator = class {
|
|
|
107
112
|
reason: "error",
|
|
108
113
|
...event.message !== void 0 ? { error: event.message } : {}
|
|
109
114
|
};
|
|
115
|
+
this.closeOpenSubagentRuns(this.status);
|
|
110
116
|
this.emit();
|
|
111
117
|
break;
|
|
112
118
|
case "RUN_CANCELLED":
|
|
@@ -114,36 +120,46 @@ var RunAggregator = class {
|
|
|
114
120
|
type: "incomplete",
|
|
115
121
|
reason: "cancelled"
|
|
116
122
|
};
|
|
123
|
+
this.closeOpenSubagentRuns(this.status);
|
|
117
124
|
this.emit();
|
|
118
125
|
break;
|
|
119
|
-
case "TEXT_MESSAGE_START":
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
case "TEXT_MESSAGE_START": {
|
|
127
|
+
const scope = this.scopeOf(event);
|
|
128
|
+
if (scope === ROOT_SCOPE) {
|
|
129
|
+
this.beginDistinctTextMessage(event.messageId);
|
|
130
|
+
this.reportServerMessageId(event.messageId);
|
|
131
|
+
if (event.messageId) this.lastTextMessageId = event.messageId;
|
|
132
|
+
}
|
|
133
|
+
this.startTextMessage(scope, event.messageId);
|
|
124
134
|
this.emit();
|
|
125
135
|
break;
|
|
136
|
+
}
|
|
126
137
|
case "TEXT_MESSAGE_CONTENT":
|
|
127
138
|
case "TEXT_MESSAGE_CHUNK": {
|
|
128
139
|
const incomingId = "messageId" in event ? event.messageId : void 0;
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
140
|
+
const scope = this.scopeOf(event);
|
|
141
|
+
if (scope === ROOT_SCOPE) {
|
|
142
|
+
this.beginDistinctTextMessage(incomingId);
|
|
143
|
+
this.reportServerMessageId(incomingId);
|
|
144
|
+
if (incomingId) this.lastTextMessageId = incomingId;
|
|
145
|
+
}
|
|
132
146
|
if (!event.delta) break;
|
|
133
147
|
this.recordFirstToken();
|
|
134
|
-
const id = this.resolveTextMessageId(incomingId);
|
|
148
|
+
const id = this.resolveTextMessageId(scope, incomingId);
|
|
135
149
|
this.appendText(id, event.delta);
|
|
136
150
|
this.totalChunks++;
|
|
137
151
|
this.emit();
|
|
138
152
|
break;
|
|
139
153
|
}
|
|
140
|
-
case "TEXT_MESSAGE_END":
|
|
141
|
-
this.
|
|
142
|
-
if (
|
|
154
|
+
case "TEXT_MESSAGE_END": {
|
|
155
|
+
const scope = this.scopeOf(event);
|
|
156
|
+
if (scope === ROOT_SCOPE) this.reportServerMessageId(event.messageId);
|
|
157
|
+
if (event.messageId && this.activeTextMessageIdByScope.get(scope) === this.partKey(scope, event.messageId)) this.activeTextMessageIdByScope.delete(scope);
|
|
143
158
|
this.emit();
|
|
144
159
|
break;
|
|
160
|
+
}
|
|
145
161
|
case "CUSTOM":
|
|
146
|
-
this.
|
|
162
|
+
this.activeTextMessageIdByScope.delete(ROOT_SCOPE);
|
|
147
163
|
this.partOrder.push({
|
|
148
164
|
kind: "data",
|
|
149
165
|
name: event.name,
|
|
@@ -155,17 +171,19 @@ var RunAggregator = class {
|
|
|
155
171
|
case "THINKING_TEXT_MESSAGE_START":
|
|
156
172
|
case "REASONING_START":
|
|
157
173
|
case "REASONING_MESSAGE_START":
|
|
158
|
-
this.handleReasoningStart("messageId" in event ? event.messageId : void 0, event.type === "REASONING_MESSAGE_START");
|
|
174
|
+
this.handleReasoningStart(this.scopeOf("subagentRunId" in event ? event : {}), "messageId" in event ? event.messageId : void 0, event.type === "REASONING_MESSAGE_START");
|
|
159
175
|
break;
|
|
160
176
|
case "REASONING_ENCRYPTED_VALUE":
|
|
161
177
|
if (event.subtype === "message") {
|
|
162
|
-
const
|
|
163
|
-
const
|
|
178
|
+
const scope = this.scopeOf(event);
|
|
179
|
+
const active = this.activeReasoningKeyByScope.get(scope);
|
|
180
|
+
const entityKey = this.partKey(scope, event.entityId);
|
|
181
|
+
const key = this.showThinking ? this.reasoningParts.has(entityKey) ? entityKey : active !== void 0 && this.anonymousReasoningKeys.has(active) ? active : void 0 : void 0;
|
|
164
182
|
if (key !== void 0) {
|
|
165
183
|
this.reasoningSignatures.set(key, event.encryptedValue);
|
|
166
184
|
this.reasoningSignatureIds.set(key, event.entityId);
|
|
167
185
|
this.emit();
|
|
168
|
-
} else if (!this.showThinking && event.entityId.trim().length > 0 && event.encryptedValue.trim().length > 0 && (this.hiddenReasoningIds.has(event.entityId) || this.hiddenActiveReasoning === "anonymous")) {
|
|
186
|
+
} else if (!this.showThinking && scope === ROOT_SCOPE && event.entityId.trim().length > 0 && event.encryptedValue.trim().length > 0 && (this.hiddenReasoningIds.has(event.entityId) || this.hiddenActiveReasoning === "anonymous")) {
|
|
169
187
|
this.hiddenSignatures.set(event.entityId, event.encryptedValue);
|
|
170
188
|
this.hiddenSignatureAnchors.set(event.entityId, this.hiddenBlockAnchors.get(event.entityId) ?? this.hiddenAnonymousAnchor ?? this.partOrder.length);
|
|
171
189
|
this.emit();
|
|
@@ -173,29 +191,33 @@ var RunAggregator = class {
|
|
|
173
191
|
}
|
|
174
192
|
break;
|
|
175
193
|
case "THINKING_TEXT_MESSAGE_CONTENT":
|
|
176
|
-
this.handleReasoningContent(event.delta);
|
|
194
|
+
this.handleReasoningContent(ROOT_SCOPE, event.delta);
|
|
177
195
|
this.totalChunks++;
|
|
178
196
|
this.recordFirstToken();
|
|
179
197
|
break;
|
|
180
198
|
case "REASONING_MESSAGE_CONTENT":
|
|
181
|
-
this.handleReasoningContent(event.delta, "messageId" in event ? event.messageId : void 0, true);
|
|
199
|
+
this.handleReasoningContent(this.scopeOf(event), event.delta, "messageId" in event ? event.messageId : void 0, true);
|
|
182
200
|
this.totalChunks++;
|
|
183
201
|
this.recordFirstToken();
|
|
184
202
|
break;
|
|
185
203
|
case "THINKING_TEXT_MESSAGE_END":
|
|
186
204
|
case "THINKING_END":
|
|
205
|
+
this.handleReasoningEnd(ROOT_SCOPE);
|
|
206
|
+
break;
|
|
187
207
|
case "REASONING_MESSAGE_END":
|
|
188
208
|
case "REASONING_END":
|
|
189
|
-
this.handleReasoningEnd();
|
|
209
|
+
this.handleReasoningEnd(this.scopeOf(event));
|
|
190
210
|
break;
|
|
191
|
-
case "TOOL_CALL_START":
|
|
192
|
-
this.
|
|
193
|
-
this.
|
|
211
|
+
case "TOOL_CALL_START": {
|
|
212
|
+
const scope = this.scopeOf(event);
|
|
213
|
+
if (scope === ROOT_SCOPE) this.reportServerMessageId(event.parentMessageId);
|
|
214
|
+
this.startToolCall(scope, event.toolCallId, event.toolCallName, event.parentMessageId);
|
|
194
215
|
this.emit();
|
|
195
216
|
break;
|
|
217
|
+
}
|
|
196
218
|
case "TOOL_CALL_ARGS":
|
|
197
219
|
case "TOOL_CALL_CHUNK":
|
|
198
|
-
if (event.type === "TOOL_CALL_CHUNK") this.reportServerMessageId(event.parentMessageId);
|
|
220
|
+
if (event.type === "TOOL_CALL_CHUNK" && this.scopeOf(event) === ROOT_SCOPE) this.reportServerMessageId(event.parentMessageId);
|
|
199
221
|
if (!event.delta) break;
|
|
200
222
|
this.appendToolArgs(event.toolCallId, event.delta);
|
|
201
223
|
this.emit();
|
|
@@ -204,7 +226,7 @@ var RunAggregator = class {
|
|
|
204
226
|
this.emit();
|
|
205
227
|
break;
|
|
206
228
|
case "TOOL_CALL_RESULT":
|
|
207
|
-
this.finishToolCall(event.toolCallId, event.content ?? "", typeof event.mcpResult?.isError === "boolean" ? event.mcpResult.isError : event.role === "tool" ? false : void 0, event.messageId, event.mcpResult);
|
|
229
|
+
this.finishToolCall(this.scopeOf(event), event.toolCallId, event.content ?? "", typeof event.mcpResult?.isError === "boolean" ? event.mcpResult.isError : event.role === "tool" ? false : void 0, event.messageId, event.mcpResult);
|
|
208
230
|
this.emit();
|
|
209
231
|
break;
|
|
210
232
|
case "ACTIVITY_SNAPSHOT": {
|
|
@@ -213,8 +235,10 @@ var RunAggregator = class {
|
|
|
213
235
|
break;
|
|
214
236
|
}
|
|
215
237
|
if (event.activityType !== "mcp-apps") break;
|
|
238
|
+
const activityScope = this.scopeOf(event);
|
|
216
239
|
const toolCallId = event.content.toolCallId;
|
|
217
|
-
const
|
|
240
|
+
const fallbackId = this.lastResolvedToolCallIdByScope.get(activityScope);
|
|
241
|
+
const entry = typeof toolCallId === "string" ? this.toolCalls.get(toolCallId) : fallbackId ? this.toolCalls.get(fallbackId) : void 0;
|
|
218
242
|
const resourceUri = event.content.resourceUri;
|
|
219
243
|
if (entry && typeof resourceUri === "string" && isMcpAppUri(resourceUri)) {
|
|
220
244
|
entry.mcpAppResourceUri = resourceUri;
|
|
@@ -236,6 +260,58 @@ var RunAggregator = class {
|
|
|
236
260
|
}
|
|
237
261
|
break;
|
|
238
262
|
}
|
|
263
|
+
case "SUBAGENT_STARTED": {
|
|
264
|
+
const existing = this.subagentRuns.get(event.subagentRunId);
|
|
265
|
+
if (existing) {
|
|
266
|
+
existing.name = event.name;
|
|
267
|
+
if (event.description !== void 0) existing.description = event.description;
|
|
268
|
+
existing.status = { type: "running" };
|
|
269
|
+
this.emit();
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
this.nestingMemo = void 0;
|
|
273
|
+
this.subagentRuns.set(event.subagentRunId, {
|
|
274
|
+
subagentRunId: event.subagentRunId,
|
|
275
|
+
name: event.name,
|
|
276
|
+
...event.description !== void 0 ? { description: event.description } : {},
|
|
277
|
+
...event.parentSubagentRunId !== void 0 ? { parentSubagentRunId: event.parentSubagentRunId } : {},
|
|
278
|
+
...event.parentToolCallId !== void 0 ? { parentToolCallId: event.parentToolCallId } : {},
|
|
279
|
+
...event.parentMessageId !== void 0 ? { parentMessageId: event.parentMessageId } : {},
|
|
280
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
281
|
+
status: { type: "running" }
|
|
282
|
+
});
|
|
283
|
+
this.emit();
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
case "SUBAGENT_FINISHED": {
|
|
287
|
+
const run = this.subagentRuns.get(event.subagentRunId);
|
|
288
|
+
if (run) {
|
|
289
|
+
run.status = event.outcome?.type === "suspended" ? {
|
|
290
|
+
type: "requires-action",
|
|
291
|
+
reason: "interrupt"
|
|
292
|
+
} : {
|
|
293
|
+
type: "complete",
|
|
294
|
+
reason: "unknown"
|
|
295
|
+
};
|
|
296
|
+
if (event.result !== void 0) run.result = event.result;
|
|
297
|
+
if (event.outcome?.type === "suspended" && event.outcome.interruptIds) run.interruptIds = event.outcome.interruptIds;
|
|
298
|
+
}
|
|
299
|
+
this.emit();
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case "SUBAGENT_ERROR": {
|
|
303
|
+
const run = this.subagentRuns.get(event.subagentRunId);
|
|
304
|
+
if (run) {
|
|
305
|
+
run.status = {
|
|
306
|
+
type: "incomplete",
|
|
307
|
+
reason: "error",
|
|
308
|
+
...event.message !== void 0 ? { error: event.message } : {}
|
|
309
|
+
};
|
|
310
|
+
if (event.code !== void 0) run.errorCode = event.code;
|
|
311
|
+
}
|
|
312
|
+
this.emit();
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
239
315
|
default: this.logger.debug?.("[agui] aggregator ignored event", event);
|
|
240
316
|
}
|
|
241
317
|
}
|
|
@@ -274,11 +350,13 @@ var RunAggregator = class {
|
|
|
274
350
|
kind: "tool-call",
|
|
275
351
|
toolCallId
|
|
276
352
|
});
|
|
353
|
+
this.nestingMemo = void 0;
|
|
277
354
|
this.toolCalls.set(toolCallId, entry);
|
|
278
355
|
this.a2uiToolCallIds.add(toolCallId);
|
|
279
356
|
}
|
|
280
357
|
for (const toolCallId of this.a2uiToolCallIds) {
|
|
281
358
|
if (activeToolCallIds.has(toolCallId)) continue;
|
|
359
|
+
this.nestingMemo = void 0;
|
|
282
360
|
this.toolCalls.delete(toolCallId);
|
|
283
361
|
const partIndex = this.partOrder.findIndex((part) => part.kind === "tool-call" && part.toolCallId === toolCallId);
|
|
284
362
|
if (partIndex !== -1) this.partOrder.splice(partIndex, 1);
|
|
@@ -310,17 +388,28 @@ var RunAggregator = class {
|
|
|
310
388
|
this.hiddenActiveReasoning = "none";
|
|
311
389
|
this.loggedDroppedOpaqueIds.clear();
|
|
312
390
|
this.anonymousReasoningKeys.clear();
|
|
313
|
-
this.
|
|
391
|
+
this.activeReasoningKeyByScope.clear();
|
|
392
|
+
this.nestingMemo = void 0;
|
|
393
|
+
this.subagentRuns.clear();
|
|
314
394
|
this.reasoningPartCounter = 0;
|
|
315
395
|
this.toolCalls.clear();
|
|
316
396
|
this.a2uiBuckets.clear();
|
|
317
397
|
this.a2uiToolCallIds.clear();
|
|
318
|
-
this.
|
|
398
|
+
this.lastResolvedToolCallIdByScope.clear();
|
|
319
399
|
this.partOrder.length = 0;
|
|
320
400
|
this.textPartCounter = 0;
|
|
321
|
-
this.
|
|
401
|
+
this.activeTextMessageIdByScope.clear();
|
|
322
402
|
this.reportedServerMessageId = void 0;
|
|
323
403
|
}
|
|
404
|
+
closeOpenSubagentRuns(status) {
|
|
405
|
+
for (const run of this.subagentRuns.values()) if (run.status.type === "running") run.status = status;
|
|
406
|
+
}
|
|
407
|
+
scopeOf(event) {
|
|
408
|
+
return event.subagentRunId ?? ROOT_SCOPE;
|
|
409
|
+
}
|
|
410
|
+
partKey(scope, id) {
|
|
411
|
+
return scope === ROOT_SCOPE ? id : `${scope}\u0000${id}`;
|
|
412
|
+
}
|
|
324
413
|
beginDistinctTextMessage(messageId) {
|
|
325
414
|
if (!messageId || this.lastTextMessageId === void 0 || this.lastTextMessageId === messageId || !this.onTextMessageStart) return;
|
|
326
415
|
this.resetMessageParts();
|
|
@@ -330,43 +419,48 @@ var RunAggregator = class {
|
|
|
330
419
|
this.textPartCounter += 1;
|
|
331
420
|
return `text-${this.textPartCounter}`;
|
|
332
421
|
}
|
|
333
|
-
startTextMessage(messageId) {
|
|
422
|
+
startTextMessage(scope, messageId) {
|
|
334
423
|
const id = messageId ?? this.generateTextKey();
|
|
335
|
-
this.ensureTextPart(id);
|
|
336
|
-
this.
|
|
337
|
-
return
|
|
424
|
+
const key = this.ensureTextPart(scope, id);
|
|
425
|
+
this.activeTextMessageIdByScope.set(scope, key);
|
|
426
|
+
return key;
|
|
338
427
|
}
|
|
339
|
-
resolveTextMessageId(messageId) {
|
|
428
|
+
resolveTextMessageId(scope, messageId) {
|
|
340
429
|
if (messageId) {
|
|
341
|
-
this.ensureTextPart(messageId);
|
|
342
|
-
this.
|
|
343
|
-
return
|
|
430
|
+
const key = this.ensureTextPart(scope, messageId);
|
|
431
|
+
this.activeTextMessageIdByScope.set(scope, key);
|
|
432
|
+
return key;
|
|
344
433
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
this.ensureTextPart(
|
|
348
|
-
this.
|
|
349
|
-
return
|
|
350
|
-
}
|
|
351
|
-
ensureTextPart(id) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
434
|
+
const active = this.activeTextMessageIdByScope.get(scope);
|
|
435
|
+
if (active) return active;
|
|
436
|
+
const key = this.ensureTextPart(scope, this.generateTextKey());
|
|
437
|
+
this.activeTextMessageIdByScope.set(scope, key);
|
|
438
|
+
return key;
|
|
439
|
+
}
|
|
440
|
+
ensureTextPart(scope, id) {
|
|
441
|
+
const key = this.partKey(scope, id);
|
|
442
|
+
if (!this.textParts.has(key)) {
|
|
443
|
+
this.textParts.set(key, { buffer: "" });
|
|
444
|
+
if (!this.partOrder.some((part) => part.kind === "text" && part.key === key)) this.partOrder.push(scope === ROOT_SCOPE ? {
|
|
355
445
|
kind: "text",
|
|
356
|
-
key
|
|
446
|
+
key
|
|
447
|
+
} : {
|
|
448
|
+
kind: "text",
|
|
449
|
+
key,
|
|
450
|
+
subagentRunId: scope
|
|
357
451
|
});
|
|
358
452
|
}
|
|
453
|
+
return key;
|
|
359
454
|
}
|
|
360
455
|
appendText(id, delta) {
|
|
361
|
-
this.ensureTextPart(id);
|
|
362
456
|
const entry = this.textParts.get(id);
|
|
363
457
|
if (!entry) return;
|
|
364
458
|
entry.buffer += delta;
|
|
365
459
|
}
|
|
366
|
-
startToolCall(id, name, parentMessageId) {
|
|
460
|
+
startToolCall(scope, id, name, parentMessageId) {
|
|
367
461
|
if (!id) return;
|
|
368
|
-
this.
|
|
369
|
-
if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) this.insertToolPart(id, parentMessageId);
|
|
462
|
+
this.activeTextMessageIdByScope.delete(scope);
|
|
463
|
+
if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) this.insertToolPart(scope, id, parentMessageId);
|
|
370
464
|
const state = {
|
|
371
465
|
toolCallId: id,
|
|
372
466
|
toolCallName: name ?? "tool",
|
|
@@ -377,15 +471,18 @@ var RunAggregator = class {
|
|
|
377
471
|
snapshotResultApplied: false
|
|
378
472
|
};
|
|
379
473
|
if (parentMessageId) state.parentMessageId = parentMessageId;
|
|
474
|
+
if (scope !== ROOT_SCOPE) state.subagentRunId = scope;
|
|
475
|
+
this.nestingMemo = void 0;
|
|
380
476
|
this.toolCalls.set(id, state);
|
|
381
477
|
}
|
|
382
|
-
insertToolPart(id, parentMessageId) {
|
|
478
|
+
insertToolPart(scope, id, parentMessageId) {
|
|
383
479
|
const entry = {
|
|
384
480
|
kind: "tool-call",
|
|
385
481
|
toolCallId: id
|
|
386
482
|
};
|
|
387
483
|
if (parentMessageId) {
|
|
388
|
-
const
|
|
484
|
+
const parentKey = this.partKey(scope, parentMessageId);
|
|
485
|
+
const parentIndex = this.partOrder.findIndex((part) => part.kind === "text" && part.key === parentKey);
|
|
389
486
|
if (parentIndex !== -1) {
|
|
390
487
|
let insertAt = parentIndex + 1;
|
|
391
488
|
while (insertAt < this.partOrder.length) {
|
|
@@ -414,7 +511,7 @@ var RunAggregator = class {
|
|
|
414
511
|
entry.parsedArgs = void 0;
|
|
415
512
|
}
|
|
416
513
|
}
|
|
417
|
-
finishToolCall(id, content, isError, toolMessageId, mcpResult) {
|
|
514
|
+
finishToolCall(scope, id, content, isError, toolMessageId, mcpResult) {
|
|
418
515
|
if (!id) return;
|
|
419
516
|
let entry = this.toolCalls.get(id);
|
|
420
517
|
if (!entry) {
|
|
@@ -425,8 +522,10 @@ var RunAggregator = class {
|
|
|
425
522
|
parsedArgs: void 0,
|
|
426
523
|
result: void 0,
|
|
427
524
|
isError: void 0,
|
|
428
|
-
snapshotResultApplied: false
|
|
525
|
+
snapshotResultApplied: false,
|
|
526
|
+
...scope !== ROOT_SCOPE ? { subagentRunId: scope } : {}
|
|
429
527
|
};
|
|
528
|
+
this.nestingMemo = void 0;
|
|
430
529
|
this.toolCalls.set(id, entry);
|
|
431
530
|
}
|
|
432
531
|
if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) this.partOrder.push({
|
|
@@ -456,43 +555,126 @@ var RunAggregator = class {
|
|
|
456
555
|
entry.isError = isError;
|
|
457
556
|
}
|
|
458
557
|
if (toolMessageId) entry.toolMessageId = toolMessageId;
|
|
459
|
-
this.
|
|
558
|
+
this.lastResolvedToolCallIdByScope.set(scope, id);
|
|
460
559
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
560
|
+
nesting() {
|
|
561
|
+
if (!this.nestingMemo) {
|
|
562
|
+
const subagentsByParentToolCallId = this.subagentsByParentToolCallId();
|
|
563
|
+
this.nestingMemo = {
|
|
564
|
+
subagentsByParentToolCallId,
|
|
565
|
+
reachable: this.reachableSubagentRunIds(subagentsByParentToolCallId)
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
return this.nestingMemo;
|
|
569
|
+
}
|
|
570
|
+
subagentsByParentToolCallId() {
|
|
571
|
+
const map = /* @__PURE__ */ new Map();
|
|
572
|
+
for (const run of this.subagentRuns.values()) {
|
|
573
|
+
if (!run.parentToolCallId) continue;
|
|
574
|
+
const list = map.get(run.parentToolCallId) ?? [];
|
|
575
|
+
list.push(run.subagentRunId);
|
|
576
|
+
map.set(run.parentToolCallId, list);
|
|
577
|
+
}
|
|
578
|
+
return map;
|
|
579
|
+
}
|
|
580
|
+
reachableSubagentRunIds(subagentsByParentToolCallId) {
|
|
581
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
582
|
+
const walk = (scope, depth) => {
|
|
583
|
+
if (depth > MAX_SUBAGENT_DEPTH) return;
|
|
584
|
+
for (const entry of this.toolCalls.values()) {
|
|
585
|
+
if ((entry.subagentRunId ?? ROOT_SCOPE) !== scope) continue;
|
|
586
|
+
for (const id of subagentsByParentToolCallId.get(entry.toolCallId) ?? []) {
|
|
587
|
+
if (reachable.has(id)) continue;
|
|
588
|
+
reachable.add(id);
|
|
589
|
+
walk(id, depth + 1);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
474
592
|
};
|
|
475
|
-
|
|
476
|
-
|
|
593
|
+
walk(ROOT_SCOPE, 0);
|
|
594
|
+
return reachable;
|
|
595
|
+
}
|
|
596
|
+
materializeSubagentMessage(subagentRunId, depth, ctx) {
|
|
597
|
+
const run = this.subagentRuns.get(subagentRunId);
|
|
598
|
+
if (!run || depth > MAX_SUBAGENT_DEPTH) return void 0;
|
|
599
|
+
const content = this.buildParts(subagentRunId, depth + 1, ctx);
|
|
600
|
+
return {
|
|
601
|
+
id: run.subagentRunId,
|
|
602
|
+
role: "assistant",
|
|
603
|
+
createdAt: run.createdAt,
|
|
604
|
+
status: run.status,
|
|
605
|
+
content,
|
|
606
|
+
metadata: {
|
|
607
|
+
unstable_state: null,
|
|
608
|
+
unstable_annotations: [],
|
|
609
|
+
unstable_data: [],
|
|
610
|
+
steps: [],
|
|
611
|
+
custom: { [AG_UI_METADATA_NAMESPACE]: {
|
|
612
|
+
name: run.name,
|
|
613
|
+
...run.description !== void 0 ? { description: run.description } : {},
|
|
614
|
+
...run.parentSubagentRunId !== void 0 ? { parentSubagentRunId: run.parentSubagentRunId } : {},
|
|
615
|
+
...run.result !== void 0 ? { result: run.result } : {},
|
|
616
|
+
...run.interruptIds !== void 0 ? { interruptIds: run.interruptIds } : {},
|
|
617
|
+
...run.errorCode !== void 0 ? { errorCode: run.errorCode } : {}
|
|
618
|
+
} }
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
buildParts(scope, depth, ctx) {
|
|
623
|
+
const snapshot = [];
|
|
624
|
+
const isRoot = scope === ROOT_SCOPE;
|
|
625
|
+
for (const { index, part } of ctx.partsByScope.get(scope) ?? []) {
|
|
626
|
+
const materialized = () => {
|
|
627
|
+
if (isRoot && ctx.root) ctx.root.lastMaterializedIndex = index;
|
|
628
|
+
};
|
|
629
|
+
if (part.kind === "tool-call") {
|
|
630
|
+
const entry = this.toolCalls.get(part.toolCallId);
|
|
631
|
+
if (!entry) continue;
|
|
632
|
+
const approval = ctx.approvals.get(entry.toolCallId);
|
|
633
|
+
const nestedMessages = (ctx.subagentsByParentToolCallId.get(entry.toolCallId) ?? []).filter((id) => ctx.reachable.has(id)).map((id) => this.materializeSubagentMessage(id, depth, ctx)).filter((m) => m !== void 0);
|
|
634
|
+
const toolPart = {
|
|
635
|
+
type: "tool-call",
|
|
636
|
+
toolCallId: entry.toolCallId,
|
|
637
|
+
toolName: entry.toolCallName,
|
|
638
|
+
args: entry.parsedArgs ?? {},
|
|
639
|
+
argsText: entry.argsText,
|
|
640
|
+
...approval ? { approval } : {},
|
|
641
|
+
...entry.result !== void 0 ? { result: entry.result } : {},
|
|
642
|
+
...entry.modelContent !== void 0 ? { modelContent: entry.modelContent } : {},
|
|
643
|
+
...entry.isError !== void 0 ? { isError: entry.isError } : {},
|
|
644
|
+
...entry.mcpAppResourceUri ? { mcp: { app: {
|
|
645
|
+
resourceUri: entry.mcpAppResourceUri,
|
|
646
|
+
...entry.mcpAppServerId ? { serverId: entry.mcpAppServerId } : {}
|
|
647
|
+
} } } : {},
|
|
648
|
+
...entry.parentMessageId ? { parentId: entry.parentMessageId } : {},
|
|
649
|
+
...entry.toolMessageId ? { unstable_toolMessageId: entry.toolMessageId } : {},
|
|
650
|
+
...nestedMessages.length > 0 ? { messages: nestedMessages } : {}
|
|
651
|
+
};
|
|
652
|
+
snapshot.push(toolPart);
|
|
653
|
+
materialized();
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
const rawScope = "subagentRunId" in part ? part.subagentRunId ?? ROOT_SCOPE : ROOT_SCOPE;
|
|
477
657
|
if (part.kind === "reasoning") {
|
|
478
658
|
if (this.showThinking) {
|
|
479
659
|
const buffer = this.reasoningParts.get(part.key) ?? "";
|
|
480
|
-
|
|
660
|
+
const isActive = this.activeReasoningKeyByScope.get(rawScope) === part.key;
|
|
661
|
+
if (buffer.length > 0 || isActive) {
|
|
481
662
|
const encryptedValue = this.reasoningSignatures.get(part.key);
|
|
482
663
|
const reasoningId = this.reasoningMessageIds.get(part.key);
|
|
483
664
|
const meta = {
|
|
484
665
|
...reasoningId !== void 0 ? { reasoningId } : {},
|
|
485
666
|
...encryptedValue !== void 0 ? { encryptedValue } : {}
|
|
486
667
|
};
|
|
487
|
-
|
|
668
|
+
snapshot.push({
|
|
488
669
|
type: "reasoning",
|
|
489
670
|
text: buffer,
|
|
490
671
|
...Object.keys(meta).length > 0 ? { providerMetadata: { [AG_UI_METADATA_NAMESPACE]: meta } } : {}
|
|
491
672
|
});
|
|
492
|
-
|
|
673
|
+
materialized();
|
|
674
|
+
} else if (isRoot && ctx.root) {
|
|
493
675
|
const encryptedValue = this.reasoningSignatures.get(part.key);
|
|
494
676
|
const id = this.reasoningSignatureIds.get(part.key);
|
|
495
|
-
if (id?.trim() && encryptedValue?.trim()) opaqueCandidates.push({
|
|
677
|
+
if (id?.trim() && encryptedValue?.trim()) ctx.root.opaqueCandidates.push({
|
|
496
678
|
id,
|
|
497
679
|
encryptedValue,
|
|
498
680
|
anchor: index + 1
|
|
@@ -503,41 +685,60 @@ var RunAggregator = class {
|
|
|
503
685
|
}
|
|
504
686
|
if (part.kind === "text") {
|
|
505
687
|
const entry = this.textParts.get(part.key);
|
|
506
|
-
if (entry && entry.buffer.trim().length > 0)
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
688
|
+
if (entry && entry.buffer.trim().length > 0) {
|
|
689
|
+
snapshot.push({
|
|
690
|
+
type: "text",
|
|
691
|
+
text: entry.buffer
|
|
692
|
+
});
|
|
693
|
+
materialized();
|
|
694
|
+
}
|
|
510
695
|
continue;
|
|
511
696
|
}
|
|
512
697
|
if (part.kind === "data") {
|
|
513
|
-
|
|
698
|
+
snapshot.push({
|
|
514
699
|
type: "data",
|
|
515
700
|
name: part.name,
|
|
516
701
|
data: part.value
|
|
517
702
|
});
|
|
703
|
+
materialized();
|
|
518
704
|
continue;
|
|
519
705
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
706
|
+
}
|
|
707
|
+
return snapshot;
|
|
708
|
+
}
|
|
709
|
+
emit() {
|
|
710
|
+
const { subagentsByParentToolCallId, reachable } = this.nesting();
|
|
711
|
+
const root = {
|
|
712
|
+
opaqueCandidates: Array.from(this.hiddenSignatures, ([id, encryptedValue]) => ({
|
|
713
|
+
id,
|
|
714
|
+
encryptedValue,
|
|
715
|
+
anchor: this.hiddenSignatureAnchors.get(id)
|
|
716
|
+
})),
|
|
717
|
+
lastMaterializedIndex: -1
|
|
718
|
+
};
|
|
719
|
+
const partsByScope = /* @__PURE__ */ new Map();
|
|
720
|
+
for (const [index, part] of this.partOrder.entries()) {
|
|
721
|
+
const rawScope = part.kind === "tool-call" ? this.toolCalls.get(part.toolCallId)?.subagentRunId ?? ROOT_SCOPE : "subagentRunId" in part ? part.subagentRunId ?? ROOT_SCOPE : ROOT_SCOPE;
|
|
722
|
+
const bucketScope = rawScope === ROOT_SCOPE || reachable.has(rawScope) ? rawScope : ROOT_SCOPE;
|
|
723
|
+
const bucket = partsByScope.get(bucketScope);
|
|
724
|
+
if (bucket) bucket.push({
|
|
725
|
+
index,
|
|
726
|
+
part
|
|
539
727
|
});
|
|
728
|
+
else partsByScope.set(bucketScope, [{
|
|
729
|
+
index,
|
|
730
|
+
part
|
|
731
|
+
}]);
|
|
540
732
|
}
|
|
733
|
+
const ctx = {
|
|
734
|
+
subagentsByParentToolCallId,
|
|
735
|
+
reachable,
|
|
736
|
+
partsByScope,
|
|
737
|
+
approvals: projectAgUiToolApprovals(this.status?.type === "requires-action" ? this.interrupts : void 0, new Set(Array.from(this.toolCalls.values()).map((entry) => entry.toolCallId))),
|
|
738
|
+
root
|
|
739
|
+
};
|
|
740
|
+
const snapshot = this.buildParts(ROOT_SCOPE, 0, ctx);
|
|
741
|
+
const { opaqueCandidates, lastMaterializedIndex } = root;
|
|
541
742
|
const toolMessageIds = /* @__PURE__ */ new Set();
|
|
542
743
|
for (const call of this.toolCalls.values()) if (call.toolMessageId) toolMessageIds.add(call.toolMessageId);
|
|
543
744
|
opaqueCandidates.sort((a, b) => a.anchor - b.anchor);
|
|
@@ -587,8 +788,9 @@ var RunAggregator = class {
|
|
|
587
788
|
toolCallCount: this.toolCalls.size
|
|
588
789
|
};
|
|
589
790
|
}
|
|
590
|
-
handleReasoningStart(messageId, isMessageId = false) {
|
|
791
|
+
handleReasoningStart(scope, messageId, isMessageId = false) {
|
|
591
792
|
if (!this.showThinking) {
|
|
793
|
+
if (scope !== ROOT_SCOPE) return;
|
|
592
794
|
const anchor = this.partOrder.length;
|
|
593
795
|
if (messageId === void 0) {
|
|
594
796
|
this.hiddenActiveReasoning = "anonymous";
|
|
@@ -600,38 +802,43 @@ var RunAggregator = class {
|
|
|
600
802
|
}
|
|
601
803
|
return;
|
|
602
804
|
}
|
|
603
|
-
this.
|
|
604
|
-
const key = messageId ?? `__auto-reasoning-${++this.reasoningPartCounter}
|
|
805
|
+
this.activeTextMessageIdByScope.delete(scope);
|
|
806
|
+
const key = this.partKey(scope, messageId ?? `__auto-reasoning-${++this.reasoningPartCounter}`);
|
|
605
807
|
if (messageId === void 0) this.anonymousReasoningKeys.add(key);
|
|
606
808
|
else if (isMessageId) this.reasoningMessageIds.set(key, messageId);
|
|
607
809
|
if (!this.reasoningParts.has(key)) {
|
|
608
810
|
this.reasoningParts.set(key, "");
|
|
609
|
-
this.partOrder.push({
|
|
811
|
+
this.partOrder.push(scope === ROOT_SCOPE ? {
|
|
610
812
|
kind: "reasoning",
|
|
611
813
|
key
|
|
814
|
+
} : {
|
|
815
|
+
kind: "reasoning",
|
|
816
|
+
key,
|
|
817
|
+
subagentRunId: scope
|
|
612
818
|
});
|
|
613
819
|
}
|
|
614
|
-
this.
|
|
820
|
+
this.activeReasoningKeyByScope.set(scope, key);
|
|
615
821
|
this.emit();
|
|
616
822
|
}
|
|
617
|
-
handleReasoningContent(delta, messageId, isMessageId = false) {
|
|
823
|
+
handleReasoningContent(scope, delta, messageId, isMessageId = false) {
|
|
618
824
|
if (!delta) return;
|
|
619
825
|
if (!this.showThinking) {
|
|
620
|
-
if (
|
|
826
|
+
if (scope !== ROOT_SCOPE) return;
|
|
827
|
+
if (this.hiddenActiveReasoning === "none") this.handleReasoningStart(scope, messageId, isMessageId);
|
|
621
828
|
return;
|
|
622
829
|
}
|
|
623
|
-
if (!this.
|
|
624
|
-
const key = this.
|
|
830
|
+
if (!this.activeReasoningKeyByScope.has(scope)) this.handleReasoningStart(scope, messageId, isMessageId);
|
|
831
|
+
const key = this.activeReasoningKeyByScope.get(scope);
|
|
625
832
|
if (!key) return;
|
|
626
833
|
this.reasoningParts.set(key, (this.reasoningParts.get(key) ?? "") + delta);
|
|
627
834
|
this.emit();
|
|
628
835
|
}
|
|
629
|
-
handleReasoningEnd() {
|
|
836
|
+
handleReasoningEnd(scope) {
|
|
630
837
|
if (!this.showThinking) {
|
|
631
|
-
this.hiddenActiveReasoning = "none";
|
|
838
|
+
if (scope === ROOT_SCOPE) this.hiddenActiveReasoning = "none";
|
|
632
839
|
return;
|
|
633
840
|
}
|
|
634
|
-
this.
|
|
841
|
+
this.activeReasoningKeyByScope.delete(scope);
|
|
635
842
|
this.emit();
|
|
636
843
|
}
|
|
637
844
|
};
|