@mcp-b/embedded-agent 1.1.1 → 1.2.1
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/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +224 -66
- package/dist/index.js.map +1 -1
- package/dist/web-component-standalone.iife.js +5 -5
- package/dist/web-component.d.ts +2 -0
- package/dist/web-component.d.ts.map +1 -1
- package/dist/web-component.js +224 -66
- package/dist/web-component.js.map +1 -1
- package/package.json +2 -1
package/dist/web-component.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ interface DevModeConfig {
|
|
|
14
14
|
anthropicApiKey: string;
|
|
15
15
|
/** Your OpenAI API key for voice mode (optional) */
|
|
16
16
|
openaiApiKey?: string;
|
|
17
|
+
/** Use window.location.origin instead of production API (for internal development) */
|
|
18
|
+
useLocalApi?: boolean;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Props for the EmbeddedAgent component
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-component.d.ts","names":[],"sources":["../src/web-component.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"web-component.d.ts","names":[],"sources":["../src/web-component.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;UA8DiB,aAAA;;;;;;;;;;;UAYA,kBAAA;;;;;;;YAQN;;;;;;;;;;;;cAaE,eAAe,GAAG;;;;;;;iBAgDf,mBAAA"}
|
package/dist/web-component.js
CHANGED
|
@@ -15,6 +15,7 @@ import { TabClientTransport } from "@mcp-b/transports";
|
|
|
15
15
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
16
16
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
17
17
|
import { jsonrepair } from "jsonrepair";
|
|
18
|
+
import { ToolResponse } from "assistant-stream";
|
|
18
19
|
import { Slot } from "@radix-ui/react-slot";
|
|
19
20
|
import { cva } from "class-variance-authority";
|
|
20
21
|
import { AssistantChatTransport, useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
@@ -357,7 +358,7 @@ const PillMarkdown = memo((t0) => {
|
|
|
357
358
|
a: t5,
|
|
358
359
|
ul: t6,
|
|
359
360
|
ol: t7,
|
|
360
|
-
li: _temp$
|
|
361
|
+
li: _temp$14,
|
|
361
362
|
blockquote: t8,
|
|
362
363
|
code: t9,
|
|
363
364
|
pre: t10,
|
|
@@ -415,7 +416,7 @@ const PillMarkdown = memo((t0) => {
|
|
|
415
416
|
return t16;
|
|
416
417
|
});
|
|
417
418
|
PillMarkdown.displayName = "PillMarkdown";
|
|
418
|
-
function _temp$
|
|
419
|
+
function _temp$14(t0) {
|
|
419
420
|
const { className: cn__6, ...props_6 } = t0;
|
|
420
421
|
return /* @__PURE__ */ jsx("li", {
|
|
421
422
|
className: cn("aui-md-li", cn__6),
|
|
@@ -560,7 +561,7 @@ const SummaryBlock = (t0) => {
|
|
|
560
561
|
if ($[24] !== actions) {
|
|
561
562
|
t15 = actions && actions.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
562
563
|
className: "flex flex-wrap gap-1.5 mt-2 pt-1.5 border-t border-white/5",
|
|
563
|
-
children: actions.map(_temp$
|
|
564
|
+
children: actions.map(_temp$13)
|
|
564
565
|
});
|
|
565
566
|
$[24] = actions;
|
|
566
567
|
$[25] = t15;
|
|
@@ -665,7 +666,7 @@ const WelcomeMessage = (t0) => {
|
|
|
665
666
|
} else t4 = $[5];
|
|
666
667
|
return t4;
|
|
667
668
|
};
|
|
668
|
-
function _temp$
|
|
669
|
+
function _temp$13(action, i) {
|
|
669
670
|
return /* @__PURE__ */ jsx("button", {
|
|
670
671
|
onClick: (e_0) => {
|
|
671
672
|
e_0.stopPropagation();
|
|
@@ -738,14 +739,25 @@ function formatToolDenialWithReason(reason) {
|
|
|
738
739
|
//#endregion
|
|
739
740
|
//#region src/hooks/useActions.ts
|
|
740
741
|
/**
|
|
742
|
+
* Type guard to check if an artifact is ToolCallMetadata
|
|
743
|
+
*/
|
|
744
|
+
function isToolCallMetadata(artifact) {
|
|
745
|
+
if (!artifact || typeof artifact !== "object") return false;
|
|
746
|
+
const a = artifact;
|
|
747
|
+
return typeof a.startedAt === "number" && typeof a.duration === "number" && typeof a.sourceId === "string";
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
741
750
|
* Hook to derive actions from the current thread's tool calls
|
|
742
751
|
*
|
|
743
752
|
* Actions are a view of tool calls - not separate state.
|
|
744
753
|
* This maintains compatibility with assistant-ui's data model.
|
|
754
|
+
*
|
|
755
|
+
* Metadata (timing, source info) is extracted from the artifact field
|
|
756
|
+
* which is populated by MCPToolRegistry during tool execution.
|
|
745
757
|
*/
|
|
746
758
|
function useActions() {
|
|
747
759
|
const $ = c(3);
|
|
748
|
-
const messages = useThread(_temp$
|
|
760
|
+
const messages = useThread(_temp$12);
|
|
749
761
|
let t0;
|
|
750
762
|
bb0: {
|
|
751
763
|
if (!messages || messages.length === 0) {
|
|
@@ -766,13 +778,14 @@ function useActions() {
|
|
|
766
778
|
if (part.type !== "tool-call") continue;
|
|
767
779
|
const toolPart = part;
|
|
768
780
|
const isComplete = toolPart.result !== void 0;
|
|
769
|
-
const hasError = toolPart.result && typeof toolPart.result === "object" && "error" in toolPart.result;
|
|
781
|
+
const hasError = toolPart.isError === true || toolPart.result && typeof toolPart.result === "object" && "error" in toolPart.result;
|
|
770
782
|
const requiresAction = toolPart.status?.type === "requires-action";
|
|
771
783
|
let status;
|
|
772
784
|
if (hasError) status = "error";
|
|
773
785
|
else if (isComplete) status = "success";
|
|
774
786
|
else if (requiresAction) status = "pending";
|
|
775
787
|
else status = "running";
|
|
788
|
+
const metadata = isToolCallMetadata(toolPart.artifact) ? toolPart.artifact : void 0;
|
|
776
789
|
actions.push({
|
|
777
790
|
id: toolPart.toolCallId,
|
|
778
791
|
toolName: toolPart.toolName,
|
|
@@ -780,7 +793,11 @@ function useActions() {
|
|
|
780
793
|
status,
|
|
781
794
|
args: toolPart.args,
|
|
782
795
|
result: toolPart.result,
|
|
783
|
-
error: hasError ? String(toolPart.result.error) : void 0
|
|
796
|
+
error: hasError ? String(toolPart.result.error) : void 0,
|
|
797
|
+
startedAt: metadata?.startedAt,
|
|
798
|
+
duration: metadata?.duration,
|
|
799
|
+
sourceId: metadata?.sourceId,
|
|
800
|
+
wasAborted: metadata?.wasAborted
|
|
784
801
|
});
|
|
785
802
|
}
|
|
786
803
|
}
|
|
@@ -794,7 +811,7 @@ function useActions() {
|
|
|
794
811
|
/**
|
|
795
812
|
* Hook to get the current running action (if any)
|
|
796
813
|
*/
|
|
797
|
-
function _temp$
|
|
814
|
+
function _temp$12(thread) {
|
|
798
815
|
return thread.messages;
|
|
799
816
|
}
|
|
800
817
|
function useCurrentAction() {
|
|
@@ -919,10 +936,26 @@ const SOURCE_LOCAL = "local";
|
|
|
919
936
|
const MCPToolsContext = createContext(null);
|
|
920
937
|
function MCPToolsProvider({ children, autoConnectLocal = true, onToolsChange, onPromptsChange }) {
|
|
921
938
|
const sourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
939
|
+
const inflightCallsRef = useRef(/* @__PURE__ */ new Map());
|
|
940
|
+
const callIdCounterRef = useRef(0);
|
|
922
941
|
const [, forceUpdate] = useState({});
|
|
923
942
|
const [toolsList, setToolsList] = useState([]);
|
|
924
943
|
const [promptsList, setPromptsList] = useState([]);
|
|
925
944
|
/**
|
|
945
|
+
* Abort in-flight tool calls for tools that are no longer available.
|
|
946
|
+
* Called after the tool list changes to clean up orphaned calls.
|
|
947
|
+
*/
|
|
948
|
+
const abortOrphanedCalls = useCallback((currentTools) => {
|
|
949
|
+
const currentToolNames = new Set(currentTools.map((t) => t.name));
|
|
950
|
+
inflightCallsRef.current.forEach((call, callId) => {
|
|
951
|
+
if (!currentToolNames.has(call.toolName)) {
|
|
952
|
+
console.warn(`[MCPToolsProvider] Aborting orphaned tool call: ${call.toolName} (call ID: ${callId})`);
|
|
953
|
+
call.abortController.abort(/* @__PURE__ */ new Error(`Tool '${call.toolName}' is no longer available`));
|
|
954
|
+
inflightCallsRef.current.delete(callId);
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
}, []);
|
|
958
|
+
/**
|
|
926
959
|
* Rebuild tools list from all sources
|
|
927
960
|
*/
|
|
928
961
|
const rebuildTools = useCallback(() => {
|
|
@@ -935,8 +968,9 @@ function MCPToolsProvider({ children, autoConnectLocal = true, onToolsChange, on
|
|
|
935
968
|
});
|
|
936
969
|
});
|
|
937
970
|
});
|
|
971
|
+
abortOrphanedCalls(allTools);
|
|
938
972
|
setToolsList(allTools);
|
|
939
|
-
}, []);
|
|
973
|
+
}, [abortOrphanedCalls]);
|
|
940
974
|
/**
|
|
941
975
|
* Rebuild prompts list from all sources
|
|
942
976
|
*/
|
|
@@ -1066,21 +1100,52 @@ function MCPToolsProvider({ children, autoConnectLocal = true, onToolsChange, on
|
|
|
1066
1100
|
return sourcesRef.current.get(id_2)?.state === "connected";
|
|
1067
1101
|
}, []);
|
|
1068
1102
|
/**
|
|
1069
|
-
* Call a tool on a specific source
|
|
1103
|
+
* Call a tool on a specific source with in-flight tracking and abort support.
|
|
1104
|
+
* If the tool is removed while the call is in progress, the call will be aborted.
|
|
1070
1105
|
*/
|
|
1071
1106
|
const callToolOnSource = useCallback(async (sourceId, name, args) => {
|
|
1072
1107
|
const source_5 = sourcesRef.current.get(sourceId);
|
|
1073
1108
|
if (!source_5?.client) throw new Error(`Source '${sourceId}' not connected`);
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1109
|
+
const callId_0 = `${sourceId}-${name}-${++callIdCounterRef.current}`;
|
|
1110
|
+
const abortController = new AbortController();
|
|
1111
|
+
inflightCallsRef.current.set(callId_0, {
|
|
1112
|
+
toolName: name,
|
|
1113
|
+
sourceId,
|
|
1114
|
+
abortController
|
|
1077
1115
|
});
|
|
1116
|
+
try {
|
|
1117
|
+
const abortPromise = new Promise((_, reject) => {
|
|
1118
|
+
const signal = abortController.signal;
|
|
1119
|
+
if (signal.aborted) {
|
|
1120
|
+
reject(signal.reason || /* @__PURE__ */ new Error(`Tool '${name}' call was aborted`));
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
signal.addEventListener("abort", () => {
|
|
1124
|
+
reject(signal.reason || /* @__PURE__ */ new Error(`Tool '${name}' call was aborted`));
|
|
1125
|
+
}, { once: true });
|
|
1126
|
+
});
|
|
1127
|
+
return await Promise.race([source_5.client.callTool({
|
|
1128
|
+
name,
|
|
1129
|
+
arguments: args
|
|
1130
|
+
}), abortPromise]);
|
|
1131
|
+
} catch (error_0) {
|
|
1132
|
+
if (abortController.signal.aborted) return {
|
|
1133
|
+
content: [{
|
|
1134
|
+
type: "text",
|
|
1135
|
+
text: `Tool call aborted: ${error_0 instanceof Error ? error_0.message : String(error_0)}`
|
|
1136
|
+
}],
|
|
1137
|
+
isError: true
|
|
1138
|
+
};
|
|
1139
|
+
throw error_0;
|
|
1140
|
+
} finally {
|
|
1141
|
+
inflightCallsRef.current.delete(callId_0);
|
|
1142
|
+
}
|
|
1078
1143
|
}, []);
|
|
1079
1144
|
/**
|
|
1080
1145
|
* Call a tool (auto-routes based on tool name)
|
|
1081
1146
|
*/
|
|
1082
1147
|
const callTool = useCallback(async (name_0, args_0) => {
|
|
1083
|
-
const tool_0 = toolsList.find((
|
|
1148
|
+
const tool_0 = toolsList.find((t_0) => t_0.name === name_0);
|
|
1084
1149
|
if (!tool_0) throw new Error(`Tool '${name_0}' not found`);
|
|
1085
1150
|
return callToolOnSource(tool_0._sourceId, name_0, args_0);
|
|
1086
1151
|
}, [toolsList, callToolOnSource]);
|
|
@@ -1095,7 +1160,13 @@ function MCPToolsProvider({ children, autoConnectLocal = true, onToolsChange, on
|
|
|
1095
1160
|
throw new Error(`Prompt '${name_1}' not found`);
|
|
1096
1161
|
}, []);
|
|
1097
1162
|
/**
|
|
1098
|
-
* Get sources map for context (public view)
|
|
1163
|
+
* Get sources map for context (public view).
|
|
1164
|
+
*
|
|
1165
|
+
* Note: This useMemo reads from sourcesRef but depends on toolsList/promptsList.
|
|
1166
|
+
* This is intentional - toolsList and promptsList are derived from sourcesRef,
|
|
1167
|
+
* so when they change, it means sourcesRef has changed and we need to rebuild
|
|
1168
|
+
* the public view. This avoids exposing sourcesRef as a dependency while still
|
|
1169
|
+
* triggering recomputation when source data changes.
|
|
1099
1170
|
*/
|
|
1100
1171
|
const sources = useMemo(() => {
|
|
1101
1172
|
const publicSources = /* @__PURE__ */ new Map();
|
|
@@ -1124,7 +1195,12 @@ function MCPToolsProvider({ children, autoConnectLocal = true, onToolsChange, on
|
|
|
1124
1195
|
}, [promptsList, onPromptsChange]);
|
|
1125
1196
|
useEffect(() => {
|
|
1126
1197
|
const sources_0 = sourcesRef;
|
|
1198
|
+
const inflightCalls = inflightCallsRef;
|
|
1127
1199
|
return () => {
|
|
1200
|
+
inflightCalls.current.forEach((call_0) => {
|
|
1201
|
+
call_0.abortController.abort(/* @__PURE__ */ new Error("Provider unmounted"));
|
|
1202
|
+
});
|
|
1203
|
+
inflightCalls.current.clear();
|
|
1128
1204
|
sources_0.current.forEach((source_8) => {
|
|
1129
1205
|
if (source_8.client) source_8.client.close().catch(console.error);
|
|
1130
1206
|
if (source_8.transport) source_8.transport.close().catch(console.error);
|
|
@@ -3022,6 +3098,9 @@ function useOptionalVoiceToolApproval() {
|
|
|
3022
3098
|
* Voice messages are tagged with metadata to distinguish them from text messages:
|
|
3023
3099
|
* - metadata.source: 'voice'
|
|
3024
3100
|
* - metadata.voiceSessionId: unique session identifier
|
|
3101
|
+
*
|
|
3102
|
+
* Tool calls from voice mode are also added to the thread with full metadata
|
|
3103
|
+
* (timing, source attribution) matching the text mode behavior.
|
|
3025
3104
|
*/
|
|
3026
3105
|
const VoiceThreadContext = createContext(null);
|
|
3027
3106
|
/**
|
|
@@ -3047,7 +3126,7 @@ function convertToRegisteredTool(tool) {
|
|
|
3047
3126
|
* Internal component that bridges voice events to the thread.
|
|
3048
3127
|
* Must be used inside both VoiceModeProvider and AssistantRuntimeProvider.
|
|
3049
3128
|
*/
|
|
3050
|
-
const VoiceThreadIntegrator = ({ children, sessionId, setSessionId, onConnect, onDisconnect, onError }) => {
|
|
3129
|
+
const VoiceThreadIntegrator = ({ children, sessionId, setSessionId, addToolCallRef, onConnect, onDisconnect, onError }) => {
|
|
3051
3130
|
const threadRuntime = useThreadRuntime();
|
|
3052
3131
|
const voiceMode = useOptionalVoiceModeContext();
|
|
3053
3132
|
const lastUserTranscriptRef = useRef("");
|
|
@@ -3060,6 +3139,43 @@ const VoiceThreadIntegrator = ({ children, sessionId, setSessionId, onConnect, o
|
|
|
3060
3139
|
onDisconnectRef.current = onDisconnect;
|
|
3061
3140
|
onErrorRef.current = onError;
|
|
3062
3141
|
/**
|
|
3142
|
+
* Set up the callback for adding tool calls to thread.
|
|
3143
|
+
* This is called by toolExecutor when a voice tool call completes.
|
|
3144
|
+
*/
|
|
3145
|
+
useEffect(() => {
|
|
3146
|
+
addToolCallRef.current = (data) => {
|
|
3147
|
+
if (!sessionId) {
|
|
3148
|
+
console.warn("[VoiceThreadIntegrator] Cannot add tool call - no active session");
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
threadRuntime.append({
|
|
3152
|
+
role: "assistant",
|
|
3153
|
+
content: [{
|
|
3154
|
+
type: "tool-call",
|
|
3155
|
+
toolCallId: data.toolCallId,
|
|
3156
|
+
toolName: data.toolName,
|
|
3157
|
+
args: data.args,
|
|
3158
|
+
argsText: JSON.stringify(data.args),
|
|
3159
|
+
result: data.result,
|
|
3160
|
+
isError: data.isError,
|
|
3161
|
+
artifact: data.artifact
|
|
3162
|
+
}],
|
|
3163
|
+
metadata: { custom: {
|
|
3164
|
+
source: "voice",
|
|
3165
|
+
voiceSessionId: sessionId,
|
|
3166
|
+
timestamp: Date.now()
|
|
3167
|
+
} }
|
|
3168
|
+
});
|
|
3169
|
+
};
|
|
3170
|
+
return () => {
|
|
3171
|
+
addToolCallRef.current = null;
|
|
3172
|
+
};
|
|
3173
|
+
}, [
|
|
3174
|
+
threadRuntime,
|
|
3175
|
+
sessionId,
|
|
3176
|
+
addToolCallRef
|
|
3177
|
+
]);
|
|
3178
|
+
/**
|
|
3063
3179
|
* Add a user message to the thread (from voice transcript)
|
|
3064
3180
|
*/
|
|
3065
3181
|
const addUserMessage = useCallback((text) => {
|
|
@@ -3148,8 +3264,8 @@ const VoiceThreadIntegrator = ({ children, sessionId, setSessionId, onConnect, o
|
|
|
3148
3264
|
* Must be inside VoiceToolApprovalProvider to access the approval context.
|
|
3149
3265
|
*/
|
|
3150
3266
|
const ApprovalAwareVoiceBridge = (t0) => {
|
|
3151
|
-
const $ = c(
|
|
3152
|
-
const { children, tokenEndpoint, voiceTools, sessionId, setSessionId, onConnect, onDisconnect, onError } = t0;
|
|
3267
|
+
const $ = c(21);
|
|
3268
|
+
const { children, tokenEndpoint, voiceTools, sessionId, setSessionId, addToolCallRef, onConnect, onDisconnect, onError } = t0;
|
|
3153
3269
|
const mcpTools = useOptionalMCPTools();
|
|
3154
3270
|
const toolApproval = useOptionalToolApproval();
|
|
3155
3271
|
const voiceToolApproval = useOptionalVoiceToolApproval();
|
|
@@ -3166,7 +3282,7 @@ const ApprovalAwareVoiceBridge = (t0) => {
|
|
|
3166
3282
|
if (!approved) return TOOL_DENIED_MESSAGE;
|
|
3167
3283
|
}
|
|
3168
3284
|
const result = await mcpTools.callTool(name, args);
|
|
3169
|
-
return (result.content?.find(_temp$
|
|
3285
|
+
return (result.content?.find(_temp$11))?.text ?? JSON.stringify(result);
|
|
3170
3286
|
};
|
|
3171
3287
|
$[0] = mcpTools;
|
|
3172
3288
|
$[1] = threadRuntime;
|
|
@@ -3186,37 +3302,39 @@ const ApprovalAwareVoiceBridge = (t0) => {
|
|
|
3186
3302
|
$[7] = t2;
|
|
3187
3303
|
} else t2 = $[7];
|
|
3188
3304
|
let t3;
|
|
3189
|
-
if ($[8] !==
|
|
3305
|
+
if ($[8] !== addToolCallRef || $[9] !== onConnect || $[10] !== onDisconnect || $[11] !== onError || $[12] !== sessionId || $[13] !== setSessionId || $[14] !== t2) {
|
|
3190
3306
|
t3 = /* @__PURE__ */ jsx(VoiceThreadIntegrator, {
|
|
3191
3307
|
sessionId,
|
|
3192
3308
|
setSessionId,
|
|
3309
|
+
addToolCallRef,
|
|
3193
3310
|
onConnect,
|
|
3194
3311
|
onDisconnect,
|
|
3195
3312
|
onError,
|
|
3196
3313
|
children: t2
|
|
3197
3314
|
});
|
|
3198
|
-
$[8] =
|
|
3199
|
-
$[9] =
|
|
3200
|
-
$[10] =
|
|
3201
|
-
$[11] =
|
|
3202
|
-
$[12] =
|
|
3203
|
-
$[13] =
|
|
3204
|
-
$[14] =
|
|
3205
|
-
|
|
3315
|
+
$[8] = addToolCallRef;
|
|
3316
|
+
$[9] = onConnect;
|
|
3317
|
+
$[10] = onDisconnect;
|
|
3318
|
+
$[11] = onError;
|
|
3319
|
+
$[12] = sessionId;
|
|
3320
|
+
$[13] = setSessionId;
|
|
3321
|
+
$[14] = t2;
|
|
3322
|
+
$[15] = t3;
|
|
3323
|
+
} else t3 = $[15];
|
|
3206
3324
|
let t4;
|
|
3207
|
-
if ($[
|
|
3325
|
+
if ($[16] !== t3 || $[17] !== tokenEndpoint || $[18] !== toolExecutor || $[19] !== voiceTools) {
|
|
3208
3326
|
t4 = /* @__PURE__ */ jsx(VoiceModeProvider, {
|
|
3209
3327
|
tokenEndpoint,
|
|
3210
3328
|
tools: voiceTools,
|
|
3211
3329
|
toolExecutor,
|
|
3212
3330
|
children: t3
|
|
3213
3331
|
});
|
|
3214
|
-
$[
|
|
3215
|
-
$[
|
|
3216
|
-
$[
|
|
3217
|
-
$[
|
|
3218
|
-
$[
|
|
3219
|
-
} else t4 = $[
|
|
3332
|
+
$[16] = t3;
|
|
3333
|
+
$[17] = tokenEndpoint;
|
|
3334
|
+
$[18] = toolExecutor;
|
|
3335
|
+
$[19] = voiceTools;
|
|
3336
|
+
$[20] = t4;
|
|
3337
|
+
} else t4 = $[20];
|
|
3220
3338
|
return t4;
|
|
3221
3339
|
};
|
|
3222
3340
|
/**
|
|
@@ -3225,9 +3343,9 @@ const ApprovalAwareVoiceBridge = (t0) => {
|
|
|
3225
3343
|
* When voice events occur:
|
|
3226
3344
|
* 1. User transcripts are added as user messages to the thread
|
|
3227
3345
|
* 2. Assistant transcripts are added as assistant messages
|
|
3228
|
-
* 3. Tool calls
|
|
3229
|
-
*
|
|
3230
|
-
*
|
|
3346
|
+
* 3. Tool calls are added as tool-call parts with full metadata (timing, source)
|
|
3347
|
+
* This ensures the thread is the single source of truth for all conversation history,
|
|
3348
|
+
* including tool calls from voice mode with the same metadata as text mode.
|
|
3231
3349
|
*
|
|
3232
3350
|
* Voice tool approval:
|
|
3233
3351
|
* When a destructive tool is called during voice mode, the VoiceToolApprovalProvider
|
|
@@ -3237,6 +3355,7 @@ const ApprovalAwareVoiceBridge = (t0) => {
|
|
|
3237
3355
|
const VoiceThreadBridge = ({ children, tokenEndpoint, onConnect, onDisconnect, onError }) => {
|
|
3238
3356
|
const mcpTools = useOptionalMCPTools();
|
|
3239
3357
|
const [sessionId, setSessionId] = useState(null);
|
|
3358
|
+
const addToolCallRef = useRef(null);
|
|
3240
3359
|
return /* @__PURE__ */ jsx(VoiceToolApprovalProvider, { children: /* @__PURE__ */ jsx(ApprovalAwareVoiceBridge, {
|
|
3241
3360
|
tokenEndpoint,
|
|
3242
3361
|
voiceTools: useMemo(() => {
|
|
@@ -3245,6 +3364,7 @@ const VoiceThreadBridge = ({ children, tokenEndpoint, onConnect, onDisconnect, o
|
|
|
3245
3364
|
}, [mcpTools?.tools]),
|
|
3246
3365
|
sessionId,
|
|
3247
3366
|
setSessionId,
|
|
3367
|
+
addToolCallRef,
|
|
3248
3368
|
onConnect,
|
|
3249
3369
|
onDisconnect,
|
|
3250
3370
|
onError,
|
|
@@ -3361,7 +3481,7 @@ const VoiceThreadContextProvider = (t0) => {
|
|
|
3361
3481
|
function useOptionalVoiceThread() {
|
|
3362
3482
|
return useContext(VoiceThreadContext);
|
|
3363
3483
|
}
|
|
3364
|
-
function _temp$
|
|
3484
|
+
function _temp$11(c$1) {
|
|
3365
3485
|
return c$1.type === "text";
|
|
3366
3486
|
}
|
|
3367
3487
|
|
|
@@ -3401,7 +3521,7 @@ function _temp$10(c$1) {
|
|
|
3401
3521
|
*/
|
|
3402
3522
|
function useAgent() {
|
|
3403
3523
|
const $ = c(35);
|
|
3404
|
-
const threadMessages = useThread(_temp$
|
|
3524
|
+
const threadMessages = useThread(_temp$10);
|
|
3405
3525
|
const isRunning = useThread(_temp2$7);
|
|
3406
3526
|
const actions = useActions();
|
|
3407
3527
|
const currentAction = useCurrentAction();
|
|
@@ -3522,7 +3642,7 @@ function useAgent() {
|
|
|
3522
3642
|
function _temp2$7(thread_0) {
|
|
3523
3643
|
return thread_0.isRunning;
|
|
3524
3644
|
}
|
|
3525
|
-
function _temp$
|
|
3645
|
+
function _temp$10(thread) {
|
|
3526
3646
|
return thread.messages;
|
|
3527
3647
|
}
|
|
3528
3648
|
|
|
@@ -3855,7 +3975,7 @@ function useMobileDetect() {
|
|
|
3855
3975
|
*/
|
|
3856
3976
|
function usePendingToolCalls() {
|
|
3857
3977
|
const $ = c(2);
|
|
3858
|
-
const messages = useThread(_temp$
|
|
3978
|
+
const messages = useThread(_temp$9);
|
|
3859
3979
|
let result;
|
|
3860
3980
|
if ($[0] !== messages) {
|
|
3861
3981
|
result = [];
|
|
@@ -3883,7 +4003,7 @@ function usePendingToolCalls() {
|
|
|
3883
4003
|
* Hook to check if there are any pending tool calls.
|
|
3884
4004
|
* Optimized for conditional rendering - returns boolean instead of array.
|
|
3885
4005
|
*/
|
|
3886
|
-
function _temp$
|
|
4006
|
+
function _temp$9(t) {
|
|
3887
4007
|
return t.messages;
|
|
3888
4008
|
}
|
|
3889
4009
|
function useHasPendingToolCalls() {
|
|
@@ -4054,7 +4174,7 @@ function getToolIcon(toolName) {
|
|
|
4054
4174
|
*/
|
|
4055
4175
|
function useActivityState() {
|
|
4056
4176
|
const $ = c(10);
|
|
4057
|
-
const messages = useThread(_temp$
|
|
4177
|
+
const messages = useThread(_temp$8);
|
|
4058
4178
|
const isRunning = useThread(_temp2$5);
|
|
4059
4179
|
let t0;
|
|
4060
4180
|
if ($[0] !== isRunning || $[1] !== messages) {
|
|
@@ -4148,7 +4268,7 @@ function _temp3$2(m) {
|
|
|
4148
4268
|
function _temp2$5(thread_0) {
|
|
4149
4269
|
return thread_0.isRunning;
|
|
4150
4270
|
}
|
|
4151
|
-
function _temp$
|
|
4271
|
+
function _temp$8(thread) {
|
|
4152
4272
|
return thread.messages;
|
|
4153
4273
|
}
|
|
4154
4274
|
/**
|
|
@@ -4335,6 +4455,12 @@ const IdleIndicator = (t0) => {
|
|
|
4335
4455
|
* - Approval mode can be 'ask' (require confirmation) or 'auto' (execute immediately)
|
|
4336
4456
|
* - Approval UI is handled by UnifiedToolFallback using the HITL pattern
|
|
4337
4457
|
*
|
|
4458
|
+
* Tool execution captures metadata (timing, source info) and stores it in the
|
|
4459
|
+
* assistant-ui thread via ToolResponse artifacts. This enables:
|
|
4460
|
+
* - Performance monitoring (duration tracking)
|
|
4461
|
+
* - Source attribution (which MCP server handled the call)
|
|
4462
|
+
* - Error tracking (including abort status)
|
|
4463
|
+
*
|
|
4338
4464
|
* Usage:
|
|
4339
4465
|
* <MCPToolRegistry />
|
|
4340
4466
|
*
|
|
@@ -4352,9 +4478,10 @@ function formatToolResult(result) {
|
|
|
4352
4478
|
/**
|
|
4353
4479
|
* Bridge component that registers a single tool with assistant-ui.
|
|
4354
4480
|
* Executes the tool immediately via MCP.
|
|
4481
|
+
* Captures execution metadata (timing, source) and stores in thread artifacts.
|
|
4355
4482
|
*/
|
|
4356
4483
|
const ToolBridge = (t0) => {
|
|
4357
|
-
const $ = c(
|
|
4484
|
+
const $ = c(11);
|
|
4358
4485
|
const { tool, callTool } = t0;
|
|
4359
4486
|
const t1 = tool.description ?? "";
|
|
4360
4487
|
let t2;
|
|
@@ -4365,34 +4492,63 @@ const ToolBridge = (t0) => {
|
|
|
4365
4492
|
} else t2 = $[1];
|
|
4366
4493
|
const t3 = t2;
|
|
4367
4494
|
let t4;
|
|
4368
|
-
if ($[2] !== callTool || $[3] !== tool.name) {
|
|
4495
|
+
if ($[2] !== callTool || $[3] !== tool._sourceId || $[4] !== tool.name) {
|
|
4369
4496
|
t4 = async (args) => {
|
|
4497
|
+
const startedAt = Date.now();
|
|
4498
|
+
let isError;
|
|
4499
|
+
let wasAborted;
|
|
4370
4500
|
try {
|
|
4371
|
-
|
|
4501
|
+
const result = await callTool(tool.name, args);
|
|
4502
|
+
isError = result.isError === true;
|
|
4503
|
+
wasAborted = result.content.some(_temp$7);
|
|
4504
|
+
const metadata_0 = {
|
|
4505
|
+
startedAt,
|
|
4506
|
+
duration: Date.now() - startedAt,
|
|
4507
|
+
sourceId: tool._sourceId,
|
|
4508
|
+
isError,
|
|
4509
|
+
wasAborted
|
|
4510
|
+
};
|
|
4511
|
+
return new ToolResponse({
|
|
4512
|
+
result: formatToolResult(result),
|
|
4513
|
+
artifact: metadata_0,
|
|
4514
|
+
isError
|
|
4515
|
+
});
|
|
4372
4516
|
} catch (t5$1) {
|
|
4373
4517
|
const error = t5$1;
|
|
4374
4518
|
console.error(`[ToolBridge] Tool '${tool.name}' execution failed:`, error);
|
|
4375
|
-
|
|
4519
|
+
const metadata = {
|
|
4520
|
+
startedAt,
|
|
4521
|
+
duration: Date.now() - startedAt,
|
|
4522
|
+
sourceId: tool._sourceId,
|
|
4523
|
+
isError: true,
|
|
4524
|
+
wasAborted: false
|
|
4525
|
+
};
|
|
4526
|
+
return new ToolResponse({
|
|
4527
|
+
result: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
4528
|
+
artifact: metadata,
|
|
4529
|
+
isError: true
|
|
4530
|
+
});
|
|
4376
4531
|
}
|
|
4377
4532
|
};
|
|
4378
4533
|
$[2] = callTool;
|
|
4379
|
-
$[3] = tool.
|
|
4380
|
-
$[4] =
|
|
4381
|
-
|
|
4534
|
+
$[3] = tool._sourceId;
|
|
4535
|
+
$[4] = tool.name;
|
|
4536
|
+
$[5] = t4;
|
|
4537
|
+
} else t4 = $[5];
|
|
4382
4538
|
let t5;
|
|
4383
|
-
if ($[
|
|
4539
|
+
if ($[6] !== t1 || $[7] !== t3 || $[8] !== t4 || $[9] !== tool.name) {
|
|
4384
4540
|
t5 = {
|
|
4385
4541
|
toolName: tool.name,
|
|
4386
4542
|
description: t1,
|
|
4387
4543
|
parameters: t3,
|
|
4388
4544
|
execute: t4
|
|
4389
4545
|
};
|
|
4390
|
-
$[
|
|
4391
|
-
$[
|
|
4392
|
-
$[
|
|
4393
|
-
$[
|
|
4394
|
-
$[
|
|
4395
|
-
} else t5 = $[
|
|
4546
|
+
$[6] = t1;
|
|
4547
|
+
$[7] = t3;
|
|
4548
|
+
$[8] = t4;
|
|
4549
|
+
$[9] = tool.name;
|
|
4550
|
+
$[10] = t5;
|
|
4551
|
+
} else t5 = $[10];
|
|
4396
4552
|
useAssistantTool(t5);
|
|
4397
4553
|
return null;
|
|
4398
4554
|
};
|
|
@@ -4467,6 +4623,9 @@ const MCPToolRegistry = () => {
|
|
|
4467
4623
|
} else t1 = $[8];
|
|
4468
4624
|
return t1;
|
|
4469
4625
|
};
|
|
4626
|
+
function _temp$7(c$1) {
|
|
4627
|
+
return c$1.type === "text" && typeof c$1.text === "string" && c$1.text.includes("Tool call aborted");
|
|
4628
|
+
}
|
|
4470
4629
|
|
|
4471
4630
|
//#endregion
|
|
4472
4631
|
//#region src/components/pill/ElicitationButtonBar.tsx
|
|
@@ -8774,13 +8933,12 @@ function injectStyles() {
|
|
|
8774
8933
|
*
|
|
8775
8934
|
*/
|
|
8776
8935
|
/**
|
|
8777
|
-
* Get the default API base URL
|
|
8778
|
-
*
|
|
8779
|
-
* - Development builds: use current origin (for local dev server)
|
|
8936
|
+
* Get the default API base URL.
|
|
8937
|
+
* Always uses production unless explicitly overridden with useLocalApi.
|
|
8780
8938
|
*/
|
|
8781
|
-
const getDefaultApiBase = () => {
|
|
8782
|
-
if (
|
|
8783
|
-
return
|
|
8939
|
+
const getDefaultApiBase = (useLocalApi) => {
|
|
8940
|
+
if (useLocalApi && typeof window !== "undefined") return window.location.origin;
|
|
8941
|
+
return WEBMCP_PRODUCTION_API_BASE;
|
|
8784
8942
|
};
|
|
8785
8943
|
/**
|
|
8786
8944
|
* EmbeddedAgent - Drop-in AI chat widget
|
|
@@ -8797,7 +8955,7 @@ const EmbeddedAgent = (t0) => {
|
|
|
8797
8955
|
const { appId, devMode } = t0;
|
|
8798
8956
|
let apiBase;
|
|
8799
8957
|
if ($[0] !== appId || $[1] !== devMode) {
|
|
8800
|
-
apiBase = getDefaultApiBase();
|
|
8958
|
+
apiBase = getDefaultApiBase(devMode?.useLocalApi);
|
|
8801
8959
|
if (typeof window !== "undefined") console.debug("[WebMCP] Initialized", {
|
|
8802
8960
|
appId,
|
|
8803
8961
|
mode: devMode ? "development" : "production",
|