@assistant-ui/react-ag-ui 0.0.60 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agUiExtras.d.ts +1 -3
- package/dist/agUiExtras.d.ts.map +1 -1
- package/dist/hooks.d.ts +3 -5
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts +152 -144
- package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadRuntimeCore.js +141 -23
- package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts +51 -53
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +65 -21
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/run-aggregator.d.ts +89 -88
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +35 -2
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/adapter/subscriber.d.ts +107 -108
- package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
- package/dist/runtime/adapter/tool-approval.d.ts +3 -4
- package/dist/runtime/adapter/tool-approval.d.ts.map +1 -1
- package/dist/runtime/event-parser.d.ts +3 -5
- package/dist/runtime/event-parser.d.ts.map +1 -1
- package/dist/runtime/interrupt-internals.d.ts +1 -3
- package/dist/runtime/interrupt-internals.d.ts.map +1 -1
- package/dist/runtime/logger.d.ts +2 -4
- package/dist/runtime/logger.d.ts.map +1 -1
- package/dist/runtime/mcp-tool-result.d.ts +4 -6
- package/dist/runtime/mcp-tool-result.d.ts.map +1 -1
- package/dist/runtime/types.d.ts +237 -238
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/useAgUiRuntime.d.ts +13 -15
- package/dist/useAgUiRuntime.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js +9 -2
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +6 -6
- package/src/runtime/AgUiThreadRuntimeCore.ts +239 -32
- package/src/runtime/adapter/conversions.content.test.ts +56 -0
- package/src/runtime/adapter/conversions.ts +112 -44
- package/src/runtime/adapter/run-aggregator.ts +53 -2
- package/src/useAgUiRuntime.history.test.tsx +93 -2
- package/src/useAgUiRuntime.thread-switch.test.tsx +84 -4
- package/src/useAgUiRuntime.ts +12 -3
- package/src/useAgUiRuntime.voice.test.tsx +402 -0
|
@@ -5,7 +5,7 @@ import { AG_UI_METADATA_NAMESPACE, RunAggregator, isPlainObject, tryParseJSON }
|
|
|
5
5
|
import { fromAgUiMessages, toAgUiMessages, toAgUiTools } from "./adapter/conversions.js";
|
|
6
6
|
import { createAgUiSubscriber } from "./adapter/subscriber.js";
|
|
7
7
|
import { fromThreadMessageLike, generateId, isMcpAppUri } from "@assistant-ui/core";
|
|
8
|
-
import { createMessageRepositorySession, invokeUserCallback, iterateToolCallParts, mapToolCallPartsDeep } from "@assistant-ui/core/internal";
|
|
8
|
+
import { appendToolInteraction, createMessageRepositorySession, invokeUserCallback, iterateToolCallParts, mapToolCallPartsDeep } from "@assistant-ui/core/internal";
|
|
9
9
|
import jsonpatch from "fast-json-patch";
|
|
10
10
|
//#region src/runtime/AgUiThreadRuntimeCore.ts
|
|
11
11
|
const optimisticPrefix = "__optimistic__";
|
|
@@ -162,6 +162,13 @@ var AgUiThreadRuntimeCore = class {
|
|
|
162
162
|
if (!startRun || !ownsThread) return;
|
|
163
163
|
await this.startRun(threadMessageId, message.runConfig);
|
|
164
164
|
}
|
|
165
|
+
appendVoiceTranscript(message) {
|
|
166
|
+
const parentId = this.session.headId;
|
|
167
|
+
this.session.addOrUpdateMessage(parentId, message);
|
|
168
|
+
this.session.switchToBranch(message.id);
|
|
169
|
+
this.notifyUpdate();
|
|
170
|
+
this.recordHistoryEntry(parentId, message);
|
|
171
|
+
}
|
|
165
172
|
maybeAutoCancelPendingToolCalls() {
|
|
166
173
|
if (this.autoCancelPendingToolCalls === false) return;
|
|
167
174
|
const pending = this.getPendingToolCalls();
|
|
@@ -484,6 +491,38 @@ var AgUiThreadRuntimeCore = class {
|
|
|
484
491
|
this.notifyUpdate();
|
|
485
492
|
this.maybeResumeAfterToolResults(sessionMessageId);
|
|
486
493
|
}
|
|
494
|
+
async recordToolInteraction(options) {
|
|
495
|
+
const sessionMessageId = this.session.tryGetMessage(options.messageId) ? options.messageId : this.findMessageIdForToolCall(options.toolCallId);
|
|
496
|
+
if (sessionMessageId === void 0) throw new Error(`[agui] recordToolInteraction: message "${options.messageId}" was not found`);
|
|
497
|
+
const item = this.session.tryGetMessage(sessionMessageId);
|
|
498
|
+
if (!item) throw new Error(`[agui] recordToolInteraction: message "${sessionMessageId}" was not found`);
|
|
499
|
+
let recorded = false;
|
|
500
|
+
const updated = this.session.updateMessage(sessionMessageId, (message) => {
|
|
501
|
+
if (message.role !== "assistant") return message;
|
|
502
|
+
const assistant = message;
|
|
503
|
+
const { content } = mapToolCallPartsDeep(assistant.content, (part) => {
|
|
504
|
+
if (part.toolCallId !== options.toolCallId) return part;
|
|
505
|
+
recorded = true;
|
|
506
|
+
return {
|
|
507
|
+
...part,
|
|
508
|
+
unstable_interactions: appendToolInteraction(part.unstable_interactions, options.interaction)
|
|
509
|
+
};
|
|
510
|
+
});
|
|
511
|
+
return recorded ? {
|
|
512
|
+
...assistant,
|
|
513
|
+
content
|
|
514
|
+
} : assistant;
|
|
515
|
+
});
|
|
516
|
+
if (!recorded || !updated) throw new Error(`[agui] recordToolInteraction: tool call "${options.toolCallId}" was not found on message "${options.messageId}"`);
|
|
517
|
+
this.notifyUpdate();
|
|
518
|
+
const message = this.session.tryGetMessage(sessionMessageId)?.message;
|
|
519
|
+
const history = this.history;
|
|
520
|
+
if (!message || !history?.update || !this.isPersistableStatus(message.status)) return;
|
|
521
|
+
await this.chainHistoryWrite(sessionMessageId, () => history.update({
|
|
522
|
+
parentId: item.parentId,
|
|
523
|
+
message
|
|
524
|
+
}));
|
|
525
|
+
}
|
|
487
526
|
sendA2uiAction(action) {
|
|
488
527
|
this.assertNoPendingInterrupts();
|
|
489
528
|
this.maybeAutoCancelPendingToolCalls();
|
|
@@ -543,6 +582,18 @@ var AgUiThreadRuntimeCore = class {
|
|
|
543
582
|
});
|
|
544
583
|
}
|
|
545
584
|
applyExternalMessages(messages) {
|
|
585
|
+
messages = messages.map((message) => {
|
|
586
|
+
if (message.role === "system" || message.metadata.modality !== void 0) return message;
|
|
587
|
+
const modality = this.session.tryGetMessage(message.id)?.message.metadata.modality;
|
|
588
|
+
if (modality === void 0) return message;
|
|
589
|
+
return {
|
|
590
|
+
...message,
|
|
591
|
+
metadata: {
|
|
592
|
+
...message.metadata,
|
|
593
|
+
modality
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
});
|
|
546
597
|
this.pendingA2uiResumeOwner = null;
|
|
547
598
|
this.pendingA2uiAction = void 0;
|
|
548
599
|
this.assistantHistoryParents.clear();
|
|
@@ -597,6 +648,26 @@ var AgUiThreadRuntimeCore = class {
|
|
|
597
648
|
this.stateSnapshot = void 0;
|
|
598
649
|
this.notifyUpdate();
|
|
599
650
|
}
|
|
651
|
+
resetThreadState() {
|
|
652
|
+
const controller = this.abortController;
|
|
653
|
+
const activeRunAgent = this.activeRunAgent;
|
|
654
|
+
this.stateSnapshot = void 0;
|
|
655
|
+
this.pendingResume = null;
|
|
656
|
+
this.pendingA2uiResumeOwner = null;
|
|
657
|
+
this.pendingA2uiAction = void 0;
|
|
658
|
+
if (controller) {
|
|
659
|
+
this.abortController = null;
|
|
660
|
+
this.activeRunAgent = null;
|
|
661
|
+
this.setRunning(false);
|
|
662
|
+
try {
|
|
663
|
+
(activeRunAgent ?? this.agent).abortRun();
|
|
664
|
+
} catch (error) {
|
|
665
|
+
this.logger.error?.("[agui] agent abortRun failed", error);
|
|
666
|
+
} finally {
|
|
667
|
+
controller.abort();
|
|
668
|
+
}
|
|
669
|
+
} else this.notifyUpdate();
|
|
670
|
+
}
|
|
600
671
|
async startRun(parentId, runConfig, resume, resumeStream) {
|
|
601
672
|
if (!this.supersedeActiveRun()) return;
|
|
602
673
|
const normalizedRunConfig = runConfig ?? {};
|
|
@@ -652,6 +723,8 @@ var AgUiThreadRuntimeCore = class {
|
|
|
652
723
|
}
|
|
653
724
|
} else assistantCollided = true;
|
|
654
725
|
};
|
|
726
|
+
const abortController = new AbortController();
|
|
727
|
+
const abortSignal = abortController.signal;
|
|
655
728
|
const aggregator = new RunAggregator({
|
|
656
729
|
showThinking: this.showThinking,
|
|
657
730
|
logger: this.logger,
|
|
@@ -661,9 +734,11 @@ var AgUiThreadRuntimeCore = class {
|
|
|
661
734
|
},
|
|
662
735
|
onTextMessageStart: (serverId) => adoptServerMessageId(serverId, true)
|
|
663
736
|
});
|
|
664
|
-
const dispatch = (event) =>
|
|
665
|
-
|
|
666
|
-
|
|
737
|
+
const dispatch = (event) => {
|
|
738
|
+
if (this.abortController !== abortController) return;
|
|
739
|
+
const nextAssistantMessageId = this.handleEvent(aggregator, event, assistantMessageId);
|
|
740
|
+
if (event.type === "MESSAGES_SNAPSHOT") assistantMessageId = nextAssistantMessageId;
|
|
741
|
+
};
|
|
667
742
|
this.abortController = abortController;
|
|
668
743
|
const runAgentInstance = this.agent;
|
|
669
744
|
this.activeRunAgent = runAgentInstance;
|
|
@@ -948,22 +1023,36 @@ var AgUiThreadRuntimeCore = class {
|
|
|
948
1023
|
return resolvedMessageId;
|
|
949
1024
|
}
|
|
950
1025
|
preserveToolResults(previous, next) {
|
|
951
|
-
const
|
|
952
|
-
for (const part of iterateToolCallParts(previous)) if (isResolvedToolCall(part))
|
|
953
|
-
if (
|
|
1026
|
+
const preserved = /* @__PURE__ */ new Map();
|
|
1027
|
+
for (const part of iterateToolCallParts(previous)) if (isResolvedToolCall(part)) preserved.set(part.toolCallId, part);
|
|
1028
|
+
if (preserved.size === 0) return this.preserveToolInteractions(previous, next);
|
|
954
1029
|
const { content: merged, changed } = mapToolCallPartsDeep(next, (part) => {
|
|
955
|
-
|
|
956
|
-
const prior = resolved.get(part.toolCallId);
|
|
1030
|
+
const prior = preserved.get(part.toolCallId);
|
|
957
1031
|
if (!prior) return part;
|
|
958
|
-
return {
|
|
1032
|
+
if (!isResolvedToolCall(part) && isResolvedToolCall(prior)) return {
|
|
959
1033
|
...part,
|
|
960
1034
|
result: prior.result,
|
|
961
1035
|
...prior.artifact !== void 0 ? { artifact: prior.artifact } : {},
|
|
962
1036
|
...prior.isError !== void 0 ? { isError: prior.isError } : {},
|
|
963
1037
|
...prior.modelContent !== void 0 ? { modelContent: prior.modelContent } : {}
|
|
964
1038
|
};
|
|
1039
|
+
return part;
|
|
965
1040
|
});
|
|
966
|
-
return changed ? merged : next;
|
|
1041
|
+
return this.preserveToolInteractions(previous, changed ? merged : next);
|
|
1042
|
+
}
|
|
1043
|
+
preserveToolInteractions(previous, next) {
|
|
1044
|
+
const interactions = /* @__PURE__ */ new Map();
|
|
1045
|
+
for (const part of iterateToolCallParts(previous)) if (part.unstable_interactions !== void 0) interactions.set(part.toolCallId, part.unstable_interactions);
|
|
1046
|
+
if (interactions.size === 0) return next;
|
|
1047
|
+
const { content, changed } = mapToolCallPartsDeep(next, (part) => {
|
|
1048
|
+
const interaction = interactions.get(part.toolCallId);
|
|
1049
|
+
if (interaction === void 0 || part.unstable_interactions !== void 0) return part;
|
|
1050
|
+
return {
|
|
1051
|
+
...part,
|
|
1052
|
+
unstable_interactions: interaction
|
|
1053
|
+
};
|
|
1054
|
+
});
|
|
1055
|
+
return changed ? content : next;
|
|
967
1056
|
}
|
|
968
1057
|
mergeAssistantMetadata(current, incoming) {
|
|
969
1058
|
const annotations = incoming.unstable_annotations ? [...current.unstable_annotations, ...incoming.unstable_annotations] : current.unstable_annotations;
|
|
@@ -983,46 +1072,69 @@ var AgUiThreadRuntimeCore = class {
|
|
|
983
1072
|
switch (event.type) {
|
|
984
1073
|
case "STATE_SNAPSHOT":
|
|
985
1074
|
this.stateSnapshot = event.snapshot;
|
|
986
|
-
this.
|
|
987
|
-
|
|
1075
|
+
this.updateActiveAssistantState(activeAssistantId);
|
|
1076
|
+
break;
|
|
988
1077
|
case "STATE_DELTA":
|
|
989
|
-
if (event.delta.length === 0)
|
|
1078
|
+
if (event.delta.length === 0) break;
|
|
990
1079
|
try {
|
|
991
1080
|
const state = this.stateSnapshot ?? {};
|
|
992
1081
|
const result = jsonpatch.applyPatch(state, event.delta, true, false);
|
|
993
1082
|
this.stateSnapshot = result.newDocument;
|
|
994
|
-
this.
|
|
1083
|
+
this.updateActiveAssistantState(activeAssistantId);
|
|
995
1084
|
} catch (error) {
|
|
996
1085
|
this.logger.error?.("[agui] failed to apply state delta", error);
|
|
997
1086
|
}
|
|
998
|
-
|
|
999
|
-
case "MESSAGES_SNAPSHOT":
|
|
1087
|
+
break;
|
|
1088
|
+
case "MESSAGES_SNAPSHOT": {
|
|
1089
|
+
const previousHeadId = this.session.headId;
|
|
1090
|
+
const activeAssistant = activeAssistantId === void 0 ? void 0 : this.session.tryGetMessage(activeAssistantId)?.message;
|
|
1091
|
+
const hasActiveText = activeAssistant?.role === "assistant" && activeAssistant.content.some((part) => part.type === "text");
|
|
1000
1092
|
this.importMessagesSnapshot(event.messages, activeAssistantId);
|
|
1001
|
-
|
|
1093
|
+
const headId = this.session.headId;
|
|
1094
|
+
if (hasActiveText && headId !== previousHeadId) activeAssistantId = (headId === null ? void 0 : this.session.tryGetMessage(headId)?.message)?.role === "assistant" ? headId ?? void 0 : void 0;
|
|
1095
|
+
this.updateActiveAssistantState(activeAssistantId);
|
|
1096
|
+
break;
|
|
1097
|
+
}
|
|
1002
1098
|
case "TOOL_CALL_RESULT":
|
|
1003
1099
|
if (!aggregator.hasToolCall(event.toolCallId)) {
|
|
1004
1100
|
const messageId = this.findMessageIdForToolCall(event.toolCallId);
|
|
1005
1101
|
if (messageId !== void 0) {
|
|
1006
1102
|
this.applyCrossRunToolResult(messageId, event);
|
|
1007
|
-
|
|
1103
|
+
break;
|
|
1008
1104
|
}
|
|
1009
1105
|
}
|
|
1010
1106
|
aggregator.handle(event);
|
|
1011
|
-
|
|
1107
|
+
break;
|
|
1012
1108
|
case "ACTIVITY_SNAPSHOT": {
|
|
1013
1109
|
const toolCallId = event.content["toolCallId"];
|
|
1014
1110
|
if (event.activityType === "mcp-apps" && typeof toolCallId === "string" && !aggregator.hasToolCall(toolCallId)) {
|
|
1015
1111
|
const messageId = this.findMessageIdForToolCall(toolCallId);
|
|
1016
1112
|
if (messageId !== void 0) {
|
|
1017
1113
|
this.applyCrossRunActivitySnapshot(messageId, toolCallId, event);
|
|
1018
|
-
|
|
1114
|
+
break;
|
|
1019
1115
|
}
|
|
1020
1116
|
}
|
|
1021
1117
|
aggregator.handle(event);
|
|
1022
|
-
|
|
1118
|
+
break;
|
|
1023
1119
|
}
|
|
1024
1120
|
default: aggregator.handle(event);
|
|
1025
1121
|
}
|
|
1122
|
+
return activeAssistantId;
|
|
1123
|
+
}
|
|
1124
|
+
updateActiveAssistantState(messageId) {
|
|
1125
|
+
const activeAssistantId = (messageId === void 0 ? void 0 : this.session.tryGetMessage(messageId)?.message)?.role === "assistant" && this.session.headId === messageId ? messageId : this.session.headId;
|
|
1126
|
+
if (activeAssistantId !== null && activeAssistantId !== void 0) this.session.updateMessage(activeAssistantId, (message) => {
|
|
1127
|
+
if (message.role !== "assistant") return message;
|
|
1128
|
+
const assistant = message;
|
|
1129
|
+
return {
|
|
1130
|
+
...assistant,
|
|
1131
|
+
metadata: {
|
|
1132
|
+
...assistant.metadata,
|
|
1133
|
+
unstable_state: this.stateSnapshot ?? null
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
});
|
|
1137
|
+
this.notifyUpdate();
|
|
1026
1138
|
}
|
|
1027
1139
|
applyCrossRunToolResult(messageId, event) {
|
|
1028
1140
|
if (!this.session.updateMessage(messageId, (message) => {
|
|
@@ -1109,7 +1221,13 @@ var AgUiThreadRuntimeCore = class {
|
|
|
1109
1221
|
const normalized = fromAgUiMessages(rawMessages, { showThinking: this.showThinking });
|
|
1110
1222
|
const converted = [];
|
|
1111
1223
|
for (const message of normalized) try {
|
|
1112
|
-
|
|
1224
|
+
const convertedMessage = fromThreadMessageLike(message, generateId(), FALLBACK_USER_STATUS);
|
|
1225
|
+
const existing = this.session.tryGetMessage(convertedMessage.id)?.message;
|
|
1226
|
+
if (convertedMessage.role === "assistant" && existing?.role === "assistant") converted.push({
|
|
1227
|
+
...convertedMessage,
|
|
1228
|
+
content: this.preserveToolInteractions(existing.content, convertedMessage.content)
|
|
1229
|
+
});
|
|
1230
|
+
else converted.push(convertedMessage);
|
|
1113
1231
|
} catch (error) {
|
|
1114
1232
|
this.logger.error?.("[agui] failed to import message from snapshot", error);
|
|
1115
1233
|
}
|