@assistant-ui/react-ag-ui 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/index.d.ts +3 -4
  2. package/dist/index.js +2 -2
  3. package/dist/runtime/AgUiThreadRuntimeCore.d.ts +85 -82
  4. package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
  5. package/dist/runtime/AgUiThreadRuntimeCore.js +542 -627
  6. package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
  7. package/dist/runtime/adapter/conversions.d.ts +39 -36
  8. package/dist/runtime/adapter/conversions.d.ts.map +1 -1
  9. package/dist/runtime/adapter/conversions.js +294 -390
  10. package/dist/runtime/adapter/conversions.js.map +1 -1
  11. package/dist/runtime/adapter/run-aggregator.d.ts +54 -47
  12. package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
  13. package/dist/runtime/adapter/run-aggregator.js +367 -364
  14. package/dist/runtime/adapter/run-aggregator.js.map +1 -1
  15. package/dist/runtime/adapter/subscriber.d.ts +94 -91
  16. package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
  17. package/dist/runtime/adapter/subscriber.js +77 -86
  18. package/dist/runtime/adapter/subscriber.js.map +1 -1
  19. package/dist/runtime/event-parser.d.ts +9 -5
  20. package/dist/runtime/event-parser.d.ts.map +1 -1
  21. package/dist/runtime/event-parser.js +172 -177
  22. package/dist/runtime/event-parser.js.map +1 -1
  23. package/dist/runtime/logger.d.ts +7 -4
  24. package/dist/runtime/logger.d.ts.map +1 -1
  25. package/dist/runtime/logger.js +7 -3
  26. package/dist/runtime/logger.js.map +1 -1
  27. package/dist/runtime/types.d.ts +121 -117
  28. package/dist/runtime/types.d.ts.map +1 -1
  29. package/dist/runtime/types.js +0 -2
  30. package/dist/useAgUiRuntime.d.ts +10 -6
  31. package/dist/useAgUiRuntime.d.ts.map +1 -1
  32. package/dist/useAgUiRuntime.js +136 -142
  33. package/dist/useAgUiRuntime.js.map +1 -1
  34. package/package.json +9 -8
  35. package/src/runtime/AgUiThreadRuntimeCore.ts +1 -0
  36. package/src/runtime/adapter/run-aggregator.ts +111 -45
  37. package/dist/index.d.ts.map +0 -1
  38. package/dist/index.js.map +0 -1
  39. package/dist/runtime/types.js.map +0 -1
@@ -1,367 +1,370 @@
1
1
  "use client";
2
- export const AG_UI_METADATA_NAMESPACE = "agui";
2
+ //#region src/runtime/adapter/run-aggregator.ts
3
+ const AG_UI_METADATA_NAMESPACE = "agui";
3
4
  /**
4
- * Collects AG-UI events into assistant-ui run snapshots that can be yielded from a ChatModelAdapter.
5
- *
6
- * The aggregator keeps a single assistant message worth of parts. Each incoming event updates the parts and
7
- * emits a fresh snapshot through the provided `emit` callback.
8
- */
9
- export class RunAggregator {
10
- emitUpdate;
11
- showThinking;
12
- logger;
13
- onServerMessageId;
14
- status;
15
- interrupts;
16
- textParts = new Map();
17
- activeTextMessageId;
18
- reasoningBuffer = "";
19
- reasoningActive = false;
20
- toolCalls = new Map();
21
- partOrder = [];
22
- hasReasoningPart = false;
23
- textPartCounter = 0;
24
- serverMessageIdReported = false;
25
- constructor(options) {
26
- this.emitUpdate = options.emit;
27
- this.showThinking = options.showThinking;
28
- this.logger = options.logger;
29
- this.onServerMessageId = options.onServerMessageId;
30
- }
31
- handle(event) {
32
- switch (event.type) {
33
- case "RUN_STARTED": {
34
- this.clearTextParts();
35
- this.reasoningBuffer = "";
36
- this.reasoningActive = false;
37
- this.toolCalls.clear();
38
- this.partOrder.length = 0;
39
- this.hasReasoningPart = false;
40
- this.textPartCounter = 0;
41
- this.activeTextMessageId = undefined;
42
- this.interrupts = undefined;
43
- this.serverMessageIdReported = false;
44
- this.status = { type: "running" };
45
- this.emit();
46
- break;
47
- }
48
- case "RUN_FINISHED": {
49
- if (event.outcome?.type === "interrupt") {
50
- this.interrupts = event.outcome.interrupts;
51
- this.status = { type: "requires-action", reason: "interrupt" };
52
- this.emit();
53
- break;
54
- }
55
- this.interrupts = undefined;
56
- const hasUnresolvedToolCalls = Array.from(this.toolCalls.values()).some((tc) => tc.result === undefined);
57
- this.status =
58
- event.outcome?.type === "success" || !hasUnresolvedToolCalls
59
- ? { type: "complete", reason: "unknown" }
60
- : { type: "requires-action", reason: "tool-calls" };
61
- this.emit();
62
- break;
63
- }
64
- case "RUN_ERROR": {
65
- this.status = {
66
- type: "incomplete",
67
- reason: "error",
68
- ...(event.message !== undefined ? { error: event.message } : {}),
69
- };
70
- this.emit();
71
- break;
72
- }
73
- case "RUN_CANCELLED": {
74
- this.status = { type: "incomplete", reason: "cancelled" };
75
- this.emit();
76
- break;
77
- }
78
- case "TEXT_MESSAGE_START": {
79
- this.reportServerMessageId(event.messageId);
80
- const id = this.startTextMessage(event.messageId);
81
- if (id) {
82
- this.markTextPartTouched(id);
83
- }
84
- this.emit();
85
- break;
86
- }
87
- case "TEXT_MESSAGE_CONTENT":
88
- case "TEXT_MESSAGE_CHUNK": {
89
- const incomingId = "messageId" in event ? event.messageId : undefined;
90
- this.reportServerMessageId(incomingId);
91
- if (!event.delta)
92
- break;
93
- const id = this.resolveTextMessageId(incomingId);
94
- this.appendText(id, event.delta);
95
- this.emit();
96
- break;
97
- }
98
- case "TEXT_MESSAGE_END": {
99
- this.reportServerMessageId(event.messageId);
100
- if (event.messageId && this.activeTextMessageId === event.messageId) {
101
- this.activeTextMessageId = undefined;
102
- }
103
- this.emit();
104
- break;
105
- }
106
- case "THINKING_START":
107
- case "THINKING_TEXT_MESSAGE_START":
108
- case "REASONING_START":
109
- case "REASONING_MESSAGE_START":
110
- this.handleReasoningStart();
111
- break;
112
- case "THINKING_TEXT_MESSAGE_CONTENT":
113
- case "REASONING_MESSAGE_CONTENT":
114
- this.handleReasoningContent(event.delta);
115
- break;
116
- case "THINKING_TEXT_MESSAGE_END":
117
- case "THINKING_END":
118
- case "REASONING_MESSAGE_END":
119
- case "REASONING_END":
120
- this.handleReasoningEnd();
121
- break;
122
- case "TOOL_CALL_START": {
123
- this.reportServerMessageId(event.parentMessageId);
124
- this.startToolCall(event.toolCallId, event.toolCallName, event.parentMessageId);
125
- this.emit();
126
- break;
127
- }
128
- case "TOOL_CALL_ARGS":
129
- case "TOOL_CALL_CHUNK": {
130
- if (event.type === "TOOL_CALL_CHUNK") {
131
- this.reportServerMessageId(event.parentMessageId);
132
- }
133
- if (!event.delta)
134
- break;
135
- this.appendToolArgs(event.toolCallId, event.delta);
136
- this.emit();
137
- break;
138
- }
139
- case "TOOL_CALL_END": {
140
- this.emit();
141
- break;
142
- }
143
- case "TOOL_CALL_RESULT": {
144
- this.finishToolCall(event.toolCallId, event.content ?? "", event.role === "tool" ? false : undefined, event.messageId);
145
- this.emit();
146
- break;
147
- }
148
- default: {
149
- this.logger.debug?.("[agui] aggregator ignored event", event);
150
- }
151
- }
152
- }
153
- reportServerMessageId(messageId) {
154
- if (this.serverMessageIdReported || !messageId)
155
- return;
156
- this.serverMessageIdReported = true;
157
- this.onServerMessageId?.(messageId);
158
- }
159
- clearTextParts() {
160
- this.textParts.clear();
161
- }
162
- generateTextKey() {
163
- this.textPartCounter += 1;
164
- return `text-${this.textPartCounter}`;
165
- }
166
- startTextMessage(messageId) {
167
- const id = messageId ?? this.generateTextKey();
168
- this.ensureTextPart(id);
169
- this.activeTextMessageId = id;
170
- return id;
171
- }
172
- resolveTextMessageId(messageId) {
173
- if (messageId) {
174
- this.ensureTextPart(messageId);
175
- this.activeTextMessageId = messageId;
176
- return messageId;
177
- }
178
- if (this.activeTextMessageId) {
179
- return this.activeTextMessageId;
180
- }
181
- const generated = this.generateTextKey();
182
- this.ensureTextPart(generated);
183
- this.activeTextMessageId = generated;
184
- return generated;
185
- }
186
- ensureTextPart(id) {
187
- if (!this.textParts.has(id)) {
188
- this.textParts.set(id, { buffer: "", touched: false });
189
- if (!this.partOrder.some((part) => part.kind === "text" && part.key === id)) {
190
- this.partOrder.push({ kind: "text", key: id });
191
- }
192
- }
193
- }
194
- markTextPartTouched(id) {
195
- const entry = this.textParts.get(id);
196
- if (!entry)
197
- return;
198
- entry.touched = true;
199
- }
200
- appendText(id, delta) {
201
- this.ensureTextPart(id);
202
- const entry = this.textParts.get(id);
203
- if (!entry)
204
- return;
205
- entry.buffer += delta;
206
- entry.touched = true;
207
- }
208
- startToolCall(id, name, parentMessageId) {
209
- if (!id)
210
- return;
211
- if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) {
212
- this.partOrder.push({ kind: "tool-call", toolCallId: id });
213
- }
214
- const state = {
215
- toolCallId: id,
216
- toolCallName: name ?? "tool",
217
- argsText: "",
218
- parsedArgs: undefined,
219
- result: undefined,
220
- isError: undefined,
221
- };
222
- if (parentMessageId) {
223
- state.parentMessageId = parentMessageId;
224
- }
225
- this.toolCalls.set(id, state);
226
- }
227
- appendToolArgs(id, delta) {
228
- const entry = id ? this.toolCalls.get(id) : undefined;
229
- if (!entry)
230
- return;
231
- entry.argsText += delta;
232
- try {
233
- const parsed = JSON.parse(entry.argsText);
234
- if (parsed && typeof parsed === "object") {
235
- entry.parsedArgs = parsed;
236
- }
237
- else {
238
- entry.parsedArgs = undefined;
239
- }
240
- }
241
- catch {
242
- entry.parsedArgs = undefined;
243
- }
244
- }
245
- finishToolCall(id, content, isError, toolMessageId) {
246
- if (!id)
247
- return;
248
- let entry = this.toolCalls.get(id);
249
- if (!entry) {
250
- entry = {
251
- toolCallId: id,
252
- toolCallName: "tool",
253
- argsText: "",
254
- parsedArgs: undefined,
255
- result: undefined,
256
- isError: undefined,
257
- };
258
- this.toolCalls.set(id, entry);
259
- }
260
- if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) {
261
- this.partOrder.push({ kind: "tool-call", toolCallId: id });
262
- }
263
- entry.result = this.tryParseJSON(content);
264
- entry.isError = isError;
265
- if (toolMessageId) {
266
- entry.toolMessageId = toolMessageId;
267
- }
268
- }
269
- tryParseJSON(value) {
270
- if (!value)
271
- return value;
272
- try {
273
- return JSON.parse(value);
274
- }
275
- catch {
276
- return value;
277
- }
278
- }
279
- emit() {
280
- const snapshot = [];
281
- for (const part of this.partOrder) {
282
- if (part.kind === "reasoning") {
283
- if (this.showThinking &&
284
- (this.reasoningActive || this.reasoningBuffer.length > 0)) {
285
- snapshot.push({
286
- type: "reasoning",
287
- text: this.reasoningBuffer,
288
- });
289
- }
290
- continue;
291
- }
292
- if (part.kind === "text") {
293
- const entry = this.textParts.get(part.key);
294
- if (entry?.touched) {
295
- snapshot.push({ type: "text", text: entry.buffer });
296
- }
297
- continue;
298
- }
299
- const entry = this.toolCalls.get(part.toolCallId);
300
- if (!entry)
301
- continue;
302
- const toolPart = {
303
- type: "tool-call",
304
- toolCallId: entry.toolCallId,
305
- toolName: entry.toolCallName,
306
- args: (entry.parsedArgs ?? {}),
307
- argsText: entry.argsText,
308
- ...(entry.result !== undefined ? { result: entry.result } : {}),
309
- ...(entry.isError !== undefined ? { isError: entry.isError } : {}),
310
- ...(entry.parentMessageId ? { parentId: entry.parentMessageId } : {}),
311
- ...(entry.toolMessageId
312
- ? { unstable_toolMessageId: entry.toolMessageId }
313
- : {}),
314
- };
315
- snapshot.push(toolPart);
316
- }
317
- const result = {
318
- content: snapshot,
319
- ...(this.status ? { status: this.status } : undefined),
320
- ...(this.interrupts
321
- ? {
322
- metadata: {
323
- custom: {
324
- [AG_UI_METADATA_NAMESPACE]: {
325
- interrupts: this.interrupts,
326
- },
327
- },
328
- },
329
- }
330
- : undefined),
331
- };
332
- this.emitUpdate(result);
333
- }
334
- handleReasoningStart() {
335
- if (!this.showThinking)
336
- return;
337
- this.reasoningActive = true;
338
- this.ensureReasoningPart();
339
- this.emit();
340
- }
341
- handleReasoningContent(delta) {
342
- if (!this.showThinking || !delta)
343
- return;
344
- this.reasoningBuffer += delta;
345
- this.ensureReasoningPart();
346
- this.emit();
347
- }
348
- handleReasoningEnd() {
349
- if (!this.showThinking)
350
- return;
351
- this.emit();
352
- }
353
- ensureReasoningPart() {
354
- if (this.hasReasoningPart)
355
- return;
356
- // ensure reasoning appears before the first text segment if possible
357
- const textIndex = this.partOrder.findIndex((part) => part.kind === "text");
358
- if (textIndex === -1) {
359
- this.partOrder.push({ kind: "reasoning" });
360
- }
361
- else {
362
- this.partOrder.splice(textIndex, 0, { kind: "reasoning" });
363
- }
364
- this.hasReasoningPart = true;
365
- }
366
- }
5
+ * Collects AG-UI events into assistant-ui run snapshots that can be yielded from a ChatModelAdapter.
6
+ *
7
+ * The aggregator keeps a single assistant message worth of parts. Each incoming event updates the parts and
8
+ * emits a fresh snapshot through the provided `emit` callback.
9
+ */
10
+ var RunAggregator = class {
11
+ emitUpdate;
12
+ showThinking;
13
+ logger;
14
+ onServerMessageId;
15
+ status;
16
+ interrupts;
17
+ textParts = /* @__PURE__ */ new Map();
18
+ activeTextMessageId;
19
+ reasoningParts = /* @__PURE__ */ new Map();
20
+ activeReasoningKey;
21
+ reasoningPartCounter = 0;
22
+ toolCalls = /* @__PURE__ */ new Map();
23
+ partOrder = [];
24
+ textPartCounter = 0;
25
+ serverMessageIdReported = false;
26
+ streamStartTime;
27
+ firstTokenTime;
28
+ totalChunks = 0;
29
+ constructor(options) {
30
+ this.emitUpdate = options.emit;
31
+ this.showThinking = options.showThinking;
32
+ this.logger = options.logger;
33
+ this.onServerMessageId = options.onServerMessageId;
34
+ }
35
+ handle(event) {
36
+ switch (event.type) {
37
+ case "RUN_STARTED":
38
+ this.clearTextParts();
39
+ this.reasoningParts.clear();
40
+ this.activeReasoningKey = void 0;
41
+ this.reasoningPartCounter = 0;
42
+ this.toolCalls.clear();
43
+ this.partOrder.length = 0;
44
+ this.textPartCounter = 0;
45
+ this.activeTextMessageId = void 0;
46
+ this.interrupts = void 0;
47
+ this.serverMessageIdReported = false;
48
+ this.streamStartTime = Date.now();
49
+ this.firstTokenTime = void 0;
50
+ this.totalChunks = 0;
51
+ this.status = { type: "running" };
52
+ this.emit();
53
+ break;
54
+ case "RUN_FINISHED": {
55
+ if (event.outcome?.type === "interrupt") {
56
+ this.interrupts = event.outcome.interrupts;
57
+ this.status = {
58
+ type: "requires-action",
59
+ reason: "interrupt"
60
+ };
61
+ this.emit();
62
+ break;
63
+ }
64
+ this.interrupts = void 0;
65
+ const hasUnresolvedToolCalls = Array.from(this.toolCalls.values()).some((tc) => tc.result === void 0);
66
+ this.status = event.outcome?.type === "success" || !hasUnresolvedToolCalls ? {
67
+ type: "complete",
68
+ reason: "unknown"
69
+ } : {
70
+ type: "requires-action",
71
+ reason: "tool-calls"
72
+ };
73
+ this.emit();
74
+ break;
75
+ }
76
+ case "RUN_ERROR":
77
+ this.status = {
78
+ type: "incomplete",
79
+ reason: "error",
80
+ ...event.message !== void 0 ? { error: event.message } : {}
81
+ };
82
+ this.emit();
83
+ break;
84
+ case "RUN_CANCELLED":
85
+ this.status = {
86
+ type: "incomplete",
87
+ reason: "cancelled"
88
+ };
89
+ this.emit();
90
+ break;
91
+ case "TEXT_MESSAGE_START": {
92
+ this.reportServerMessageId(event.messageId);
93
+ const id = this.startTextMessage(event.messageId);
94
+ if (id) this.markTextPartTouched(id);
95
+ this.emit();
96
+ break;
97
+ }
98
+ case "TEXT_MESSAGE_CONTENT":
99
+ case "TEXT_MESSAGE_CHUNK": {
100
+ const incomingId = "messageId" in event ? event.messageId : void 0;
101
+ this.reportServerMessageId(incomingId);
102
+ if (!event.delta) break;
103
+ this.recordFirstToken();
104
+ const id = this.resolveTextMessageId(incomingId);
105
+ this.appendText(id, event.delta);
106
+ this.totalChunks++;
107
+ this.emit();
108
+ break;
109
+ }
110
+ case "TEXT_MESSAGE_END":
111
+ this.reportServerMessageId(event.messageId);
112
+ if (event.messageId && this.activeTextMessageId === event.messageId) this.activeTextMessageId = void 0;
113
+ this.emit();
114
+ break;
115
+ case "THINKING_START":
116
+ case "THINKING_TEXT_MESSAGE_START":
117
+ case "REASONING_START":
118
+ case "REASONING_MESSAGE_START":
119
+ this.handleReasoningStart("messageId" in event ? event.messageId : void 0);
120
+ break;
121
+ case "THINKING_TEXT_MESSAGE_CONTENT":
122
+ this.handleReasoningContent(event.delta);
123
+ this.totalChunks++;
124
+ this.recordFirstToken();
125
+ break;
126
+ case "REASONING_MESSAGE_CONTENT":
127
+ this.handleReasoningContent(event.delta, "messageId" in event ? event.messageId : void 0);
128
+ this.totalChunks++;
129
+ this.recordFirstToken();
130
+ break;
131
+ case "THINKING_TEXT_MESSAGE_END":
132
+ case "THINKING_END":
133
+ case "REASONING_MESSAGE_END":
134
+ case "REASONING_END":
135
+ this.handleReasoningEnd();
136
+ break;
137
+ case "TOOL_CALL_START":
138
+ this.reportServerMessageId(event.parentMessageId);
139
+ this.startToolCall(event.toolCallId, event.toolCallName, event.parentMessageId);
140
+ this.emit();
141
+ break;
142
+ case "TOOL_CALL_ARGS":
143
+ case "TOOL_CALL_CHUNK":
144
+ if (event.type === "TOOL_CALL_CHUNK") this.reportServerMessageId(event.parentMessageId);
145
+ if (!event.delta) break;
146
+ this.appendToolArgs(event.toolCallId, event.delta);
147
+ this.emit();
148
+ break;
149
+ case "TOOL_CALL_END":
150
+ this.emit();
151
+ break;
152
+ case "TOOL_CALL_RESULT":
153
+ this.finishToolCall(event.toolCallId, event.content ?? "", event.role === "tool" ? false : void 0, event.messageId);
154
+ this.emit();
155
+ break;
156
+ default: this.logger.debug?.("[agui] aggregator ignored event", event);
157
+ }
158
+ }
159
+ reportServerMessageId(messageId) {
160
+ if (this.serverMessageIdReported || !messageId) return;
161
+ this.serverMessageIdReported = true;
162
+ this.onServerMessageId?.(messageId);
163
+ }
164
+ clearTextParts() {
165
+ this.textParts.clear();
166
+ }
167
+ generateTextKey() {
168
+ this.textPartCounter += 1;
169
+ return `text-${this.textPartCounter}`;
170
+ }
171
+ startTextMessage(messageId) {
172
+ const id = messageId ?? this.generateTextKey();
173
+ this.ensureTextPart(id);
174
+ this.activeTextMessageId = id;
175
+ return id;
176
+ }
177
+ resolveTextMessageId(messageId) {
178
+ if (messageId) {
179
+ this.ensureTextPart(messageId);
180
+ this.activeTextMessageId = messageId;
181
+ return messageId;
182
+ }
183
+ if (this.activeTextMessageId) return this.activeTextMessageId;
184
+ const generated = this.generateTextKey();
185
+ this.ensureTextPart(generated);
186
+ this.activeTextMessageId = generated;
187
+ return generated;
188
+ }
189
+ ensureTextPart(id) {
190
+ if (!this.textParts.has(id)) {
191
+ this.textParts.set(id, {
192
+ buffer: "",
193
+ touched: false
194
+ });
195
+ if (!this.partOrder.some((part) => part.kind === "text" && part.key === id)) this.partOrder.push({
196
+ kind: "text",
197
+ key: id
198
+ });
199
+ }
200
+ }
201
+ markTextPartTouched(id) {
202
+ const entry = this.textParts.get(id);
203
+ if (!entry) return;
204
+ entry.touched = true;
205
+ }
206
+ appendText(id, delta) {
207
+ this.ensureTextPart(id);
208
+ const entry = this.textParts.get(id);
209
+ if (!entry) return;
210
+ entry.buffer += delta;
211
+ entry.touched = true;
212
+ }
213
+ startToolCall(id, name, parentMessageId) {
214
+ if (!id) return;
215
+ this.activeTextMessageId = void 0;
216
+ if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) this.partOrder.push({
217
+ kind: "tool-call",
218
+ toolCallId: id
219
+ });
220
+ const state = {
221
+ toolCallId: id,
222
+ toolCallName: name ?? "tool",
223
+ argsText: "",
224
+ parsedArgs: void 0,
225
+ result: void 0,
226
+ isError: void 0
227
+ };
228
+ if (parentMessageId) state.parentMessageId = parentMessageId;
229
+ this.toolCalls.set(id, state);
230
+ }
231
+ appendToolArgs(id, delta) {
232
+ const entry = id ? this.toolCalls.get(id) : void 0;
233
+ if (!entry) return;
234
+ entry.argsText += delta;
235
+ try {
236
+ const parsed = JSON.parse(entry.argsText);
237
+ if (parsed && typeof parsed === "object") entry.parsedArgs = parsed;
238
+ else entry.parsedArgs = void 0;
239
+ } catch {
240
+ entry.parsedArgs = void 0;
241
+ }
242
+ }
243
+ finishToolCall(id, content, isError, toolMessageId) {
244
+ if (!id) return;
245
+ let entry = this.toolCalls.get(id);
246
+ if (!entry) {
247
+ entry = {
248
+ toolCallId: id,
249
+ toolCallName: "tool",
250
+ argsText: "",
251
+ parsedArgs: void 0,
252
+ result: void 0,
253
+ isError: void 0
254
+ };
255
+ this.toolCalls.set(id, entry);
256
+ }
257
+ if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) this.partOrder.push({
258
+ kind: "tool-call",
259
+ toolCallId: id
260
+ });
261
+ entry.result = this.tryParseJSON(content);
262
+ entry.isError = isError;
263
+ if (toolMessageId) entry.toolMessageId = toolMessageId;
264
+ }
265
+ tryParseJSON(value) {
266
+ if (!value) return value;
267
+ try {
268
+ return JSON.parse(value);
269
+ } catch {
270
+ return value;
271
+ }
272
+ }
273
+ emit() {
274
+ const snapshot = [];
275
+ for (const part of this.partOrder) {
276
+ if (part.kind === "reasoning") {
277
+ if (this.showThinking) {
278
+ const buffer = this.reasoningParts.get(part.key) ?? "";
279
+ if (buffer.length > 0 || this.activeReasoningKey === part.key) snapshot.push({
280
+ type: "reasoning",
281
+ text: buffer
282
+ });
283
+ }
284
+ continue;
285
+ }
286
+ if (part.kind === "text") {
287
+ const entry = this.textParts.get(part.key);
288
+ if (entry?.touched) snapshot.push({
289
+ type: "text",
290
+ text: entry.buffer
291
+ });
292
+ continue;
293
+ }
294
+ const entry = this.toolCalls.get(part.toolCallId);
295
+ if (!entry) continue;
296
+ const toolPart = {
297
+ type: "tool-call",
298
+ toolCallId: entry.toolCallId,
299
+ toolName: entry.toolCallName,
300
+ args: entry.parsedArgs ?? {},
301
+ argsText: entry.argsText,
302
+ ...entry.result !== void 0 ? { result: entry.result } : {},
303
+ ...entry.isError !== void 0 ? { isError: entry.isError } : {},
304
+ ...entry.parentMessageId ? { parentId: entry.parentMessageId } : {},
305
+ ...entry.toolMessageId ? { unstable_toolMessageId: entry.toolMessageId } : {}
306
+ };
307
+ snapshot.push(toolPart);
308
+ }
309
+ const timing = this.getTiming();
310
+ const metadata = {
311
+ ...timing ? { timing } : {},
312
+ ...this.interrupts ? { custom: { [AG_UI_METADATA_NAMESPACE]: { interrupts: this.interrupts } } } : {}
313
+ };
314
+ const result = {
315
+ content: snapshot,
316
+ ...this.status ? { status: this.status } : void 0,
317
+ ...Object.keys(metadata).length > 0 ? { metadata } : void 0
318
+ };
319
+ this.emitUpdate(result);
320
+ }
321
+ recordFirstToken() {
322
+ if (this.firstTokenTime === void 0 && this.streamStartTime !== void 0) this.firstTokenTime = Date.now() - this.streamStartTime;
323
+ }
324
+ getTiming() {
325
+ if (this.streamStartTime === void 0) return void 0;
326
+ const totalStreamTime = Date.now() - this.streamStartTime;
327
+ const tokenCount = this.totalChunks > 0 ? Math.ceil(Array.from(this.textParts.values()).reduce((sum, p) => sum + p.buffer.length, 0) / 4) : void 0;
328
+ const tokensPerSecond = tokenCount && totalStreamTime > 0 ? tokenCount / totalStreamTime * 1e3 : void 0;
329
+ return {
330
+ streamStartTime: this.streamStartTime,
331
+ ...this.firstTokenTime !== void 0 ? { firstTokenTime: this.firstTokenTime } : {},
332
+ totalStreamTime,
333
+ ...tokenCount !== void 0 ? { tokenCount } : {},
334
+ ...tokensPerSecond !== void 0 ? { tokensPerSecond } : {},
335
+ totalChunks: this.totalChunks,
336
+ toolCallCount: this.toolCalls.size
337
+ };
338
+ }
339
+ handleReasoningStart(messageId) {
340
+ if (!this.showThinking) return;
341
+ this.activeTextMessageId = void 0;
342
+ const key = messageId ?? `__auto-reasoning-${++this.reasoningPartCounter}`;
343
+ if (!this.reasoningParts.has(key)) {
344
+ this.reasoningParts.set(key, "");
345
+ this.partOrder.push({
346
+ kind: "reasoning",
347
+ key
348
+ });
349
+ }
350
+ this.activeReasoningKey = key;
351
+ this.emit();
352
+ }
353
+ handleReasoningContent(delta, messageId) {
354
+ if (!this.showThinking || !delta) return;
355
+ if (!this.activeReasoningKey) this.handleReasoningStart(messageId);
356
+ const key = this.activeReasoningKey;
357
+ if (!key) return;
358
+ this.reasoningParts.set(key, (this.reasoningParts.get(key) ?? "") + delta);
359
+ this.emit();
360
+ }
361
+ handleReasoningEnd() {
362
+ if (!this.showThinking) return;
363
+ this.activeReasoningKey = void 0;
364
+ this.emit();
365
+ }
366
+ };
367
+ //#endregion
368
+ export { AG_UI_METADATA_NAMESPACE, RunAggregator };
369
+
367
370
  //# sourceMappingURL=run-aggregator.js.map