@assistant-ui/react-ag-ui 0.0.64 → 0.0.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts +19 -3
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js +193 -39
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +19 -29
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +4 -16
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +100 -23
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/event-parser.d.ts.map +1 -1
- package/dist/runtime/event-parser.js +16 -8
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/types.d.ts +30 -5
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js +8 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/useAgUiRuntime.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js +80 -33
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +7 -6
- package/src/runtime/AgUiThreadRuntimeCore.test.ts +380 -6
- package/src/runtime/AgUiThreadRuntimeCore.ts +314 -70
- package/src/runtime/adapter/conversions.content.test.ts +41 -0
- package/src/runtime/adapter/conversions.nested-tool-calls.test.ts +107 -0
- package/src/runtime/adapter/conversions.ts +37 -64
- package/src/runtime/adapter/run-aggregator.reasoning.test.ts +143 -0
- package/src/runtime/adapter/run-aggregator.ts +163 -40
- package/src/runtime/event-parser.ts +18 -4
- package/src/runtime/types.ts +43 -11
- package/src/useAgUiRuntime.external-store.test.tsx +51 -0
- package/src/useAgUiRuntime.queue.test.tsx +63 -2
- package/src/useAgUiRuntime.thread-switch.test.tsx +587 -3
- package/src/useAgUiRuntime.ts +106 -44
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { readMcpAppResourceUri } from "../mcp-tool-result.js";
|
|
3
|
+
import { AG_UI_METADATA_NAMESPACE } from "../types.js";
|
|
3
4
|
import { projectAgUiToolApprovals } from "./tool-approval.js";
|
|
4
5
|
import { isMcpAppUri } from "@assistant-ui/core";
|
|
5
6
|
import jsonpatch from "fast-json-patch";
|
|
6
|
-
import { applyA2uiOperations,
|
|
7
|
+
import { applyA2uiOperations, surfaceToPresentToolCall } from "@assistant-ui/generative-ui/a2ui";
|
|
7
8
|
//#region src/runtime/adapter/run-aggregator.ts
|
|
8
|
-
const AG_UI_METADATA_NAMESPACE = "agui";
|
|
9
9
|
const ROOT_SCOPE = "";
|
|
10
10
|
const MAX_SUBAGENT_DEPTH = 16;
|
|
11
11
|
const createJSONContainerScanner = () => ({
|
|
@@ -62,8 +62,6 @@ const scanJSONContainerDelta = (scanner, delta) => {
|
|
|
62
62
|
}
|
|
63
63
|
return completed && scanner.state === "complete";
|
|
64
64
|
};
|
|
65
|
-
const MCP_APPS_ACTIVITY_TYPE = "mcp-apps";
|
|
66
|
-
const A2UI_SURFACE_ACTIVITY_TYPE = "a2ui-surface";
|
|
67
65
|
const isPlainObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
68
66
|
/**
|
|
69
67
|
* Collects AG-UI events into assistant-ui run snapshots that can be yielded from a ChatModelAdapter.
|
|
@@ -108,6 +106,7 @@ var RunAggregator = class {
|
|
|
108
106
|
activityParts = /* @__PURE__ */ new Map();
|
|
109
107
|
lastResolvedToolCallIdByScope = /* @__PURE__ */ new Map();
|
|
110
108
|
partOrder = [];
|
|
109
|
+
lastReasoningBeforeToolCall;
|
|
111
110
|
textPartCounter = 0;
|
|
112
111
|
serverMessageIdReported = false;
|
|
113
112
|
reportedServerMessageId;
|
|
@@ -228,7 +227,7 @@ var RunAggregator = class {
|
|
|
228
227
|
case "THINKING_TEXT_MESSAGE_START":
|
|
229
228
|
case "REASONING_START":
|
|
230
229
|
case "REASONING_MESSAGE_START":
|
|
231
|
-
this.handleReasoningStart(this.scopeOf("subagentRunId" in event ? event : {}), "messageId" in event ? event.messageId : void 0, event.type === "REASONING_MESSAGE_START");
|
|
230
|
+
this.handleReasoningStart(this.scopeOf("subagentRunId" in event ? event : {}), "messageId" in event ? event.messageId : void 0, event.type === "REASONING_MESSAGE_START", event.timestamp);
|
|
232
231
|
break;
|
|
233
232
|
case "REASONING_ENCRYPTED_VALUE":
|
|
234
233
|
if (event.subtype === "message") {
|
|
@@ -259,11 +258,11 @@ var RunAggregator = class {
|
|
|
259
258
|
break;
|
|
260
259
|
case "THINKING_TEXT_MESSAGE_END":
|
|
261
260
|
case "THINKING_END":
|
|
262
|
-
this.handleReasoningEnd(ROOT_SCOPE);
|
|
261
|
+
this.handleReasoningEnd(ROOT_SCOPE, event.timestamp);
|
|
263
262
|
break;
|
|
264
263
|
case "REASONING_MESSAGE_END":
|
|
265
264
|
case "REASONING_END":
|
|
266
|
-
this.handleReasoningEnd(this.scopeOf(event));
|
|
265
|
+
this.handleReasoningEnd(this.scopeOf(event), event.timestamp);
|
|
267
266
|
break;
|
|
268
267
|
case "TOOL_CALL_START": {
|
|
269
268
|
const scope = this.scopeOf(event);
|
|
@@ -441,19 +440,19 @@ var RunAggregator = class {
|
|
|
441
440
|
for (const bucket of this.a2uiBuckets.values()) for (const [surfaceId, surface] of bucket) surfaces.set(surfaceId, surface);
|
|
442
441
|
const activeToolCallIds = /* @__PURE__ */ new Set();
|
|
443
442
|
for (const [surfaceId, surface] of surfaces) {
|
|
444
|
-
const
|
|
445
|
-
const { spec, warnings } = convertSurfaceToUISpec(surface);
|
|
443
|
+
const { toolCall, warnings } = surfaceToPresentToolCall(surfaceId, surface);
|
|
446
444
|
for (const warning of warnings) this.logger.debug("[agui] a2ui surface conversion warning", warning);
|
|
447
|
-
if (!
|
|
445
|
+
if (!toolCall) continue;
|
|
446
|
+
const { toolCallId } = toolCall;
|
|
448
447
|
activeToolCallIds.add(toolCallId);
|
|
449
448
|
const entry = {
|
|
450
|
-
toolCallId,
|
|
451
|
-
toolCallName:
|
|
452
|
-
argsText:
|
|
453
|
-
parsedArgs:
|
|
454
|
-
result:
|
|
449
|
+
toolCallId: toolCall.toolCallId,
|
|
450
|
+
toolCallName: toolCall.toolName,
|
|
451
|
+
argsText: toolCall.argsText,
|
|
452
|
+
parsedArgs: toolCall.args,
|
|
453
|
+
result: toolCall.result,
|
|
455
454
|
isError: void 0,
|
|
456
|
-
artifact:
|
|
455
|
+
artifact: toolCall.artifact,
|
|
457
456
|
snapshotResultApplied: false
|
|
458
457
|
};
|
|
459
458
|
if (!this.toolCalls.has(toolCallId)) this.partOrder.push({
|
|
@@ -508,6 +507,7 @@ var RunAggregator = class {
|
|
|
508
507
|
this.activityParts.clear();
|
|
509
508
|
this.lastResolvedToolCallIdByScope.clear();
|
|
510
509
|
this.partOrder.length = 0;
|
|
510
|
+
this.lastReasoningBeforeToolCall = void 0;
|
|
511
511
|
this.textPartCounter = 0;
|
|
512
512
|
this.activeTextMessageIdByScope.clear();
|
|
513
513
|
this.reportedServerMessageId = void 0;
|
|
@@ -523,8 +523,70 @@ var RunAggregator = class {
|
|
|
523
523
|
}
|
|
524
524
|
beginDistinctTextMessage(messageId) {
|
|
525
525
|
if (!messageId || this.lastTextMessageId === void 0 || this.lastTextMessageId === messageId || !this.onTextMessageStart) return;
|
|
526
|
+
const carried = this.takeTrailingReasoning();
|
|
527
|
+
if (carried.parts.length > 0 || carried.hiddenSignatures.length > 0) this.emit();
|
|
528
|
+
const reasoningPartCounter = this.reasoningPartCounter;
|
|
526
529
|
this.resetMessageParts();
|
|
527
530
|
this.onTextMessageStart(messageId);
|
|
531
|
+
this.reasoningPartCounter = reasoningPartCounter;
|
|
532
|
+
this.restoreReasoning(carried);
|
|
533
|
+
}
|
|
534
|
+
takeTrailingReasoning() {
|
|
535
|
+
const parts = [];
|
|
536
|
+
let last = this.partOrder.at(-1);
|
|
537
|
+
while (last?.kind === "reasoning" && last.subagentRunId === void 0 && last !== this.lastReasoningBeforeToolCall) {
|
|
538
|
+
this.partOrder.pop();
|
|
539
|
+
parts.unshift({
|
|
540
|
+
key: last.key,
|
|
541
|
+
entry: this.reasoningParts.get(last.key) ?? { buffer: "" },
|
|
542
|
+
signature: this.reasoningSignatures.get(last.key),
|
|
543
|
+
signatureId: this.reasoningSignatureIds.get(last.key),
|
|
544
|
+
reasoningId: this.reasoningMessageIds.get(last.key),
|
|
545
|
+
anonymous: this.anonymousReasoningKeys.has(last.key)
|
|
546
|
+
});
|
|
547
|
+
last = this.partOrder.at(-1);
|
|
548
|
+
}
|
|
549
|
+
const cut = this.partOrder.length;
|
|
550
|
+
const hiddenSignatures = Array.from(this.hiddenSignatures).filter(([id]) => this.hiddenSignatureAnchors.get(id) >= cut);
|
|
551
|
+
for (const [id] of hiddenSignatures) {
|
|
552
|
+
this.hiddenSignatures.delete(id);
|
|
553
|
+
this.hiddenSignatureAnchors.delete(id);
|
|
554
|
+
}
|
|
555
|
+
const hiddenBlockIds = Array.from(this.hiddenBlockAnchors).filter(([, anchor]) => anchor >= cut).map(([id]) => id);
|
|
556
|
+
const hiddenAnonymous = this.hiddenAnonymousAnchor !== void 0 && this.hiddenAnonymousAnchor >= cut;
|
|
557
|
+
const activeCarried = this.hiddenActiveReasoning === "identified" && hiddenBlockIds.length > 0 || this.hiddenActiveReasoning === "anonymous" && hiddenAnonymous;
|
|
558
|
+
return {
|
|
559
|
+
parts,
|
|
560
|
+
activeKey: this.activeReasoningKeyByScope.get(ROOT_SCOPE),
|
|
561
|
+
hiddenSignatures,
|
|
562
|
+
hiddenBlockIds,
|
|
563
|
+
hiddenAnonymous,
|
|
564
|
+
hiddenActiveReasoning: activeCarried ? this.hiddenActiveReasoning : "none"
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
restoreReasoning(carried) {
|
|
568
|
+
for (const part of carried.parts) {
|
|
569
|
+
this.partOrder.push({
|
|
570
|
+
kind: "reasoning",
|
|
571
|
+
key: part.key
|
|
572
|
+
});
|
|
573
|
+
this.reasoningParts.set(part.key, part.entry);
|
|
574
|
+
if (part.signature !== void 0) this.reasoningSignatures.set(part.key, part.signature);
|
|
575
|
+
if (part.signatureId !== void 0) this.reasoningSignatureIds.set(part.key, part.signatureId);
|
|
576
|
+
if (part.reasoningId !== void 0) this.reasoningMessageIds.set(part.key, part.reasoningId);
|
|
577
|
+
if (part.anonymous) this.anonymousReasoningKeys.add(part.key);
|
|
578
|
+
}
|
|
579
|
+
if (carried.activeKey !== void 0 && this.reasoningParts.has(carried.activeKey)) this.activeReasoningKeyByScope.set(ROOT_SCOPE, carried.activeKey);
|
|
580
|
+
for (const [id, encryptedValue] of carried.hiddenSignatures) {
|
|
581
|
+
this.hiddenSignatures.set(id, encryptedValue);
|
|
582
|
+
this.hiddenSignatureAnchors.set(id, 0);
|
|
583
|
+
}
|
|
584
|
+
for (const id of carried.hiddenBlockIds) {
|
|
585
|
+
this.hiddenReasoningIds.add(id);
|
|
586
|
+
this.hiddenBlockAnchors.set(id, 0);
|
|
587
|
+
}
|
|
588
|
+
if (carried.hiddenAnonymous) this.hiddenAnonymousAnchor = 0;
|
|
589
|
+
this.hiddenActiveReasoning = carried.hiddenActiveReasoning;
|
|
528
590
|
}
|
|
529
591
|
generateTextKey() {
|
|
530
592
|
this.textPartCounter += 1;
|
|
@@ -571,7 +633,10 @@ var RunAggregator = class {
|
|
|
571
633
|
startToolCall(scope, id, name, parentMessageId) {
|
|
572
634
|
if (!id) return;
|
|
573
635
|
this.activeTextMessageIdByScope.delete(scope);
|
|
574
|
-
if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id))
|
|
636
|
+
if (!this.partOrder.some((part) => part.kind === "tool-call" && part.toolCallId === id)) {
|
|
637
|
+
if (scope === ROOT_SCOPE) this.lastReasoningBeforeToolCall = this.partOrder.findLast((part) => part.kind === "reasoning" && part.subagentRunId === void 0);
|
|
638
|
+
this.insertToolPart(scope, id, parentMessageId);
|
|
639
|
+
}
|
|
575
640
|
const state = {
|
|
576
641
|
toolCallId: id,
|
|
577
642
|
toolCallName: name ?? "tool",
|
|
@@ -773,7 +838,8 @@ var RunAggregator = class {
|
|
|
773
838
|
const rawScope = "subagentRunId" in part ? part.subagentRunId ?? ROOT_SCOPE : ROOT_SCOPE;
|
|
774
839
|
if (part.kind === "reasoning") {
|
|
775
840
|
if (this.showThinking) {
|
|
776
|
-
const
|
|
841
|
+
const entry = this.reasoningParts.get(part.key);
|
|
842
|
+
const buffer = entry?.buffer ?? "";
|
|
777
843
|
const isActive = this.activeReasoningKeyByScope.get(rawScope) === part.key;
|
|
778
844
|
if (buffer.length > 0 || isActive) {
|
|
779
845
|
const encryptedValue = this.reasoningSignatures.get(part.key);
|
|
@@ -785,6 +851,7 @@ var RunAggregator = class {
|
|
|
785
851
|
snapshot.push({
|
|
786
852
|
type: "reasoning",
|
|
787
853
|
text: buffer,
|
|
854
|
+
...entry?.timing ? { timing: entry.timing } : {},
|
|
788
855
|
...Object.keys(meta).length > 0 ? { providerMetadata: { [AG_UI_METADATA_NAMESPACE]: meta } } : {}
|
|
789
856
|
});
|
|
790
857
|
materialized();
|
|
@@ -905,7 +972,7 @@ var RunAggregator = class {
|
|
|
905
972
|
toolCallCount: this.toolCalls.size
|
|
906
973
|
};
|
|
907
974
|
}
|
|
908
|
-
handleReasoningStart(scope, messageId, isMessageId = false) {
|
|
975
|
+
handleReasoningStart(scope, messageId, isMessageId = false, timestamp) {
|
|
909
976
|
if (!this.showThinking) {
|
|
910
977
|
if (scope !== ROOT_SCOPE) return;
|
|
911
978
|
const anchor = this.partOrder.length;
|
|
@@ -924,7 +991,7 @@ var RunAggregator = class {
|
|
|
924
991
|
if (messageId === void 0) this.anonymousReasoningKeys.add(key);
|
|
925
992
|
else if (isMessageId) this.reasoningMessageIds.set(key, messageId);
|
|
926
993
|
if (!this.reasoningParts.has(key)) {
|
|
927
|
-
this.reasoningParts.set(key, "");
|
|
994
|
+
this.reasoningParts.set(key, { buffer: "" });
|
|
928
995
|
this.partOrder.push(scope === ROOT_SCOPE ? {
|
|
929
996
|
kind: "reasoning",
|
|
930
997
|
key
|
|
@@ -934,6 +1001,9 @@ var RunAggregator = class {
|
|
|
934
1001
|
subagentRunId: scope
|
|
935
1002
|
});
|
|
936
1003
|
}
|
|
1004
|
+
const entry = this.reasoningParts.get(key);
|
|
1005
|
+
if (entry?.timing) entry.timing = { startedAt: entry.timing.startedAt };
|
|
1006
|
+
else if (entry && typeof timestamp === "number" && Number.isFinite(timestamp)) entry.timing = { startedAt: timestamp };
|
|
937
1007
|
this.activeReasoningKeyByScope.set(scope, key);
|
|
938
1008
|
this.emit();
|
|
939
1009
|
}
|
|
@@ -947,14 +1017,21 @@ var RunAggregator = class {
|
|
|
947
1017
|
if (!this.activeReasoningKeyByScope.has(scope)) this.handleReasoningStart(scope, messageId, isMessageId);
|
|
948
1018
|
const key = this.activeReasoningKeyByScope.get(scope);
|
|
949
1019
|
if (!key) return;
|
|
950
|
-
|
|
1020
|
+
const entry = this.reasoningParts.get(key);
|
|
1021
|
+
if (entry) entry.buffer += delta;
|
|
951
1022
|
this.emit();
|
|
952
1023
|
}
|
|
953
|
-
handleReasoningEnd(scope) {
|
|
1024
|
+
handleReasoningEnd(scope, timestamp) {
|
|
954
1025
|
if (!this.showThinking) {
|
|
955
1026
|
if (scope === ROOT_SCOPE) this.hiddenActiveReasoning = "none";
|
|
956
1027
|
return;
|
|
957
1028
|
}
|
|
1029
|
+
const key = this.activeReasoningKeyByScope.get(scope);
|
|
1030
|
+
const entry = key ? this.reasoningParts.get(key) : void 0;
|
|
1031
|
+
if (entry?.timing && typeof timestamp === "number" && Number.isFinite(timestamp)) entry.timing = {
|
|
1032
|
+
...entry.timing,
|
|
1033
|
+
completedAt: timestamp
|
|
1034
|
+
};
|
|
958
1035
|
this.activeReasoningKeyByScope.delete(scope);
|
|
959
1036
|
this.emit();
|
|
960
1037
|
}
|
|
@@ -968,6 +1045,6 @@ function tryParseJSON(value) {
|
|
|
968
1045
|
}
|
|
969
1046
|
}
|
|
970
1047
|
//#endregion
|
|
971
|
-
export {
|
|
1048
|
+
export { RunAggregator, isPlainObject, tryParseJSON };
|
|
972
1049
|
|
|
973
1050
|
//# sourceMappingURL=run-aggregator.js.map
|