@copilotkit/react-core 1.70.0 → 1.70.2
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/{copilotkit-CbZGwElm.d.mts → copilotkit--Jyzm6hS.d.mts} +50 -20
- package/dist/copilotkit--Jyzm6hS.d.mts.map +1 -0
- package/dist/{copilotkit-B7aFKfQR.mjs → copilotkit-B1jSvZeb.mjs} +395 -291
- package/dist/copilotkit-B1jSvZeb.mjs.map +1 -0
- package/dist/{copilotkit-BuzP0VeG.d.cts → copilotkit-BLYaCGcz.d.cts} +50 -20
- package/dist/copilotkit-BLYaCGcz.d.cts.map +1 -0
- package/dist/{copilotkit-BE76j111.cjs → copilotkit-DcFo270Y.cjs} +395 -291
- package/dist/copilotkit-DcFo270Y.cjs.map +1 -0
- package/dist/index.cjs +5 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -4
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +198 -207
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/headless.cjs +58 -1
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.mjs +59 -2
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +1 -1
- package/dist/v2/index.d.mts +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +395 -291
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +11 -8
- package/skills/react-core/SKILL.md +1 -1
- package/skills/react-core/references/attachments.md +20 -0
- package/skills/react-core/references/threads.md +1 -1
- package/dist/copilotkit-B7aFKfQR.mjs.map +0 -1
- package/dist/copilotkit-BE76j111.cjs.map +0 -1
- package/dist/copilotkit-BuzP0VeG.d.cts.map +0 -1
- package/dist/copilotkit-CbZGwElm.d.mts.map +0 -1
package/dist/index.umd.js
CHANGED
|
@@ -282,6 +282,62 @@ react_markdown = __toESM(react_markdown);
|
|
|
282
282
|
const useCopilotChatConfiguration = () => {
|
|
283
283
|
return (0, react.useContext)(CopilotChatConfiguration);
|
|
284
284
|
};
|
|
285
|
+
/**
|
|
286
|
+
* Reports modal open/close requests to the host, and — when `open` is
|
|
287
|
+
* supplied — makes the modal state of an already-established chat
|
|
288
|
+
* configuration **controlled** for the subtree it wraps.
|
|
289
|
+
*
|
|
290
|
+
* This is deliberately a scope component rather than another mode inside
|
|
291
|
+
* {@link CopilotChatConfigurationProvider}. The provider resolves modal state
|
|
292
|
+
* across a nested chain (own state, parent sync, drawer mutual-exclusion, the
|
|
293
|
+
* modal-closer registry); a controlled branch inside that resolution would add
|
|
294
|
+
* a fourth interacting mode. Overriding the context for the subtree instead
|
|
295
|
+
* leaves every one of those paths untouched:
|
|
296
|
+
*
|
|
297
|
+
* - `isModalOpen` is replaced with the host's `open`, so the rendered surface
|
|
298
|
+
* follows the prop from the very first frame (no open-then-close flash).
|
|
299
|
+
* - `setModalOpen` still calls the underlying setter, so the existing
|
|
300
|
+
* parent-sync and drawer mutual-exclusion side effects continue to run, and
|
|
301
|
+
* *then* reports the request through `onOpenChange`.
|
|
302
|
+
* - The wrapped setter is registered as the modal closer, so the drawer's
|
|
303
|
+
* mobile mutual-exclusion reaches the host instead of silently flipping
|
|
304
|
+
* state that nothing displays.
|
|
305
|
+
*
|
|
306
|
+
* A host that supplies `open` and ignores `onOpenChange` gets a modal pinned
|
|
307
|
+
* to `open`, which is the standard controlled-component contract. A host that
|
|
308
|
+
* supplies only `onOpenChange` is notified while the modal keeps managing
|
|
309
|
+
* itself.
|
|
310
|
+
*
|
|
311
|
+
* Renders `children` unchanged when no chat configuration is in scope.
|
|
312
|
+
*/
|
|
313
|
+
const ControlledModalOpenScope = ({ children, open, onOpenChange }) => {
|
|
314
|
+
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
315
|
+
const parentSetModalOpen = parentConfig?.setModalOpen;
|
|
316
|
+
const registerModalCloser = parentConfig?.ɵregisterModalCloser;
|
|
317
|
+
const setModalOpen = (0, react.useCallback)((next) => {
|
|
318
|
+
parentSetModalOpen?.(next);
|
|
319
|
+
onOpenChange?.(next);
|
|
320
|
+
}, [parentSetModalOpen, onOpenChange]);
|
|
321
|
+
(0, react.useEffect)(() => {
|
|
322
|
+
if (!registerModalCloser) return;
|
|
323
|
+
return registerModalCloser(setModalOpen);
|
|
324
|
+
}, [registerModalCloser, setModalOpen]);
|
|
325
|
+
const configurationValue = (0, react.useMemo)(() => parentConfig ? {
|
|
326
|
+
...parentConfig,
|
|
327
|
+
isModalOpen: open ?? parentConfig.isModalOpen,
|
|
328
|
+
setModalOpen
|
|
329
|
+
} : null, [
|
|
330
|
+
parentConfig,
|
|
331
|
+
open,
|
|
332
|
+
setModalOpen
|
|
333
|
+
]);
|
|
334
|
+
if (!configurationValue) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
|
|
335
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
|
|
336
|
+
value: configurationValue,
|
|
337
|
+
children
|
|
338
|
+
});
|
|
339
|
+
};
|
|
340
|
+
ControlledModalOpenScope.displayName = "ControlledModalOpenScope";
|
|
285
341
|
|
|
286
342
|
//#endregion
|
|
287
343
|
//#region src/v2/lib/react-core.ts
|
|
@@ -688,7 +744,6 @@ react_markdown = __toESM(react_markdown);
|
|
|
688
744
|
newMessages: []
|
|
689
745
|
};
|
|
690
746
|
}
|
|
691
|
-
const PROTOCOL_VERSION = "2025-06-18";
|
|
692
747
|
function buildSandboxHTML(extraCspDomains) {
|
|
693
748
|
const baseScriptSrc = "'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*";
|
|
694
749
|
const baseFrameSrc = "* blob: data: http://localhost:* https://localhost:*";
|
|
@@ -800,6 +855,13 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
800
855
|
}
|
|
801
856
|
};
|
|
802
857
|
const mcpAppsRequestQueue = new MCPAppsRequestQueue();
|
|
858
|
+
const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([
|
|
859
|
+
"javascript:",
|
|
860
|
+
"data:",
|
|
861
|
+
"vbscript:",
|
|
862
|
+
"blob:",
|
|
863
|
+
"file:"
|
|
864
|
+
]);
|
|
803
865
|
/**
|
|
804
866
|
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType
|
|
805
867
|
*/
|
|
@@ -815,18 +877,32 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
815
877
|
serverId: zod.z.string().optional(),
|
|
816
878
|
toolInput: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
817
879
|
});
|
|
818
|
-
function isRequest(msg) {
|
|
819
|
-
return "id" in msg && "method" in msg;
|
|
820
|
-
}
|
|
821
|
-
function isNotification(msg) {
|
|
822
|
-
return !("id" in msg) && "method" in msg;
|
|
823
|
-
}
|
|
824
880
|
/**
|
|
825
881
|
* MCP Apps Extension Activity Renderer
|
|
826
882
|
*
|
|
827
883
|
* Renders MCP Apps UI in a sandboxed iframe with full protocol support.
|
|
828
884
|
* Fetches resource content on-demand via proxied MCP requests.
|
|
829
885
|
*/
|
|
886
|
+
/**
|
|
887
|
+
* Permissive `ui/message` schema. ext-apps restricts the request to
|
|
888
|
+
* `role: "user"` with no `followUp`, but CopilotKit intentionally extends
|
|
889
|
+
* `ui/message` with `role` ("user" | "assistant") and `followUp` (documented
|
|
890
|
+
* behavior with dedicated tests). We register our own handler (instead of the
|
|
891
|
+
* bridge's strict `onmessage`) so those extensions survive the migration.
|
|
892
|
+
*
|
|
893
|
+
* Going forward, widgets SHOULD pass the extensions under
|
|
894
|
+
* `params._meta.copilotkit`; the top-level `role`/`followUp` fields are the
|
|
895
|
+
* legacy channel, kept for backward compatibility and slated for deprecation.
|
|
896
|
+
*/
|
|
897
|
+
const CopilotKitUiMessageSchema = zod.z.object({
|
|
898
|
+
method: zod.z.literal("ui/message"),
|
|
899
|
+
params: zod.z.object({
|
|
900
|
+
role: zod.z.string().optional(),
|
|
901
|
+
content: zod.z.array(zod.z.any()).optional(),
|
|
902
|
+
followUp: zod.z.boolean().optional(),
|
|
903
|
+
_meta: zod.z.record(zod.z.string(), zod.z.any()).optional()
|
|
904
|
+
}).passthrough()
|
|
905
|
+
});
|
|
830
906
|
const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agent }) {
|
|
831
907
|
const { copilotkit } = useCopilotKit();
|
|
832
908
|
const containerRef = (0, react.useRef)(null);
|
|
@@ -840,41 +916,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
840
916
|
contentRef.current = content;
|
|
841
917
|
const agentRef = (0, react.useRef)(agent);
|
|
842
918
|
agentRef.current = agent;
|
|
919
|
+
const bridgeRef = (0, react.useRef)(null);
|
|
843
920
|
const fetchStateRef = (0, react.useRef)({
|
|
844
921
|
inProgress: false,
|
|
845
922
|
promise: null,
|
|
846
923
|
resourceUri: null
|
|
847
924
|
});
|
|
848
|
-
const sendToIframe = (0, react.useCallback)((msg) => {
|
|
849
|
-
if (iframeRef.current?.contentWindow) {
|
|
850
|
-
console.log("[MCPAppsRenderer] Sending to iframe:", msg);
|
|
851
|
-
iframeRef.current.contentWindow.postMessage(msg, "*");
|
|
852
|
-
}
|
|
853
|
-
}, []);
|
|
854
|
-
const sendResponse = (0, react.useCallback)((id, result) => {
|
|
855
|
-
sendToIframe({
|
|
856
|
-
jsonrpc: "2.0",
|
|
857
|
-
id,
|
|
858
|
-
result
|
|
859
|
-
});
|
|
860
|
-
}, [sendToIframe]);
|
|
861
|
-
const sendErrorResponse = (0, react.useCallback)((id, code, message) => {
|
|
862
|
-
sendToIframe({
|
|
863
|
-
jsonrpc: "2.0",
|
|
864
|
-
id,
|
|
865
|
-
error: {
|
|
866
|
-
code,
|
|
867
|
-
message
|
|
868
|
-
}
|
|
869
|
-
});
|
|
870
|
-
}, [sendToIframe]);
|
|
871
|
-
const sendNotification = (0, react.useCallback)((method, params) => {
|
|
872
|
-
sendToIframe({
|
|
873
|
-
jsonrpc: "2.0",
|
|
874
|
-
method,
|
|
875
|
-
params: params || {}
|
|
876
|
-
});
|
|
877
|
-
}, [sendToIframe]);
|
|
878
925
|
(0, react.useEffect)(() => {
|
|
879
926
|
const { resourceUri, serverHash, serverId } = content;
|
|
880
927
|
if (fetchStateRef.current.inProgress && fetchStateRef.current.resourceUri === resourceUri) {
|
|
@@ -929,11 +976,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
929
976
|
const container = containerRef.current;
|
|
930
977
|
if (!container) return;
|
|
931
978
|
let mounted = true;
|
|
932
|
-
let
|
|
933
|
-
let initialListener = null;
|
|
979
|
+
let bridge = null;
|
|
934
980
|
let createdIframe = null;
|
|
935
981
|
const setup = async () => {
|
|
936
982
|
try {
|
|
983
|
+
const bridgeModule = await import("@modelcontextprotocol/ext-apps/app-bridge").catch((importErr) => {
|
|
984
|
+
throw new Error("MCP Apps require '@modelcontextprotocol/ext-apps' and its peer '@modelcontextprotocol/sdk'. Install them with: npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk", { cause: importErr });
|
|
985
|
+
});
|
|
986
|
+
if (!mounted) return;
|
|
987
|
+
const { AppBridge, PostMessageTransport } = bridgeModule;
|
|
937
988
|
const iframe = document.createElement("iframe");
|
|
938
989
|
createdIframe = iframe;
|
|
939
990
|
iframe.style.width = "100%";
|
|
@@ -944,151 +995,108 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
944
995
|
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
|
|
945
996
|
iframe.setAttribute("data-testid", "mcp-app-iframe");
|
|
946
997
|
iframe.setAttribute("title", "Interactive MCP application");
|
|
947
|
-
const sandboxReady = new Promise((resolve) => {
|
|
948
|
-
initialListener = (event) => {
|
|
949
|
-
if (event.source === iframe.contentWindow) {
|
|
950
|
-
if (event.data?.method === "ui/notifications/sandbox-proxy-ready") {
|
|
951
|
-
if (initialListener) {
|
|
952
|
-
window.removeEventListener("message", initialListener);
|
|
953
|
-
initialListener = null;
|
|
954
|
-
}
|
|
955
|
-
resolve();
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
};
|
|
959
|
-
window.addEventListener("message", initialListener);
|
|
960
|
-
});
|
|
961
|
-
if (!mounted) {
|
|
962
|
-
if (initialListener) {
|
|
963
|
-
window.removeEventListener("message", initialListener);
|
|
964
|
-
initialListener = null;
|
|
965
|
-
}
|
|
966
|
-
return;
|
|
967
|
-
}
|
|
968
998
|
const cspDomains = fetchedResource._meta?.ui?.csp?.resourceDomains;
|
|
969
999
|
iframe.srcdoc = buildSandboxHTML(cspDomains);
|
|
970
1000
|
iframeRef.current = iframe;
|
|
971
1001
|
container.appendChild(iframe);
|
|
972
|
-
|
|
973
|
-
if (!
|
|
974
|
-
console.log("[MCPAppsRenderer] Sandbox proxy ready");
|
|
975
|
-
messageHandler = async (event) => {
|
|
976
|
-
if (event.source !== iframe.contentWindow) return;
|
|
977
|
-
const msg = event.data;
|
|
978
|
-
if (!msg || typeof msg !== "object" || msg.jsonrpc !== "2.0") return;
|
|
979
|
-
console.log("[MCPAppsRenderer] Received from iframe:", msg);
|
|
980
|
-
if (isRequest(msg)) switch (msg.method) {
|
|
981
|
-
case "ui/initialize":
|
|
982
|
-
sendResponse(msg.id, {
|
|
983
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
984
|
-
hostInfo: {
|
|
985
|
-
name: "CopilotKit MCP Apps Host",
|
|
986
|
-
version: "1.0.0"
|
|
987
|
-
},
|
|
988
|
-
hostCapabilities: {
|
|
989
|
-
openLinks: {},
|
|
990
|
-
logging: {}
|
|
991
|
-
},
|
|
992
|
-
hostContext: {
|
|
993
|
-
theme: "light",
|
|
994
|
-
platform: "web"
|
|
995
|
-
}
|
|
996
|
-
});
|
|
997
|
-
break;
|
|
998
|
-
case "ui/message": {
|
|
999
|
-
const currentAgent = agentRef.current;
|
|
1000
|
-
if (!currentAgent) {
|
|
1001
|
-
console.warn("[MCPAppsRenderer] ui/message: No agent available");
|
|
1002
|
-
sendResponse(msg.id, { isError: false });
|
|
1003
|
-
break;
|
|
1004
|
-
}
|
|
1005
|
-
try {
|
|
1006
|
-
const params = msg.params;
|
|
1007
|
-
const role = params.role || "user";
|
|
1008
|
-
const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
|
|
1009
|
-
if (textContent) currentAgent.addMessage({
|
|
1010
|
-
id: crypto.randomUUID(),
|
|
1011
|
-
role,
|
|
1012
|
-
content: textContent
|
|
1013
|
-
});
|
|
1014
|
-
sendResponse(msg.id, { isError: false });
|
|
1015
|
-
if ((params.followUp ?? role === "user") && textContent) {
|
|
1016
|
-
const capturedThreadId = currentAgent.threadId || "default";
|
|
1017
|
-
mcpAppsRequestQueue.enqueue(currentAgent, () => ɵrunMcpFollowUp({
|
|
1018
|
-
host: copilotkit,
|
|
1019
|
-
agent: currentAgent,
|
|
1020
|
-
capturedThreadId
|
|
1021
|
-
})).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
|
|
1022
|
-
}
|
|
1023
|
-
} catch (err) {
|
|
1024
|
-
console.error("[MCPAppsRenderer] ui/message error:", err);
|
|
1025
|
-
sendResponse(msg.id, { isError: true });
|
|
1026
|
-
}
|
|
1027
|
-
break;
|
|
1028
|
-
}
|
|
1029
|
-
case "ui/open-link": {
|
|
1030
|
-
const url = msg.params?.url;
|
|
1031
|
-
if (url) {
|
|
1032
|
-
window.open(url, "_blank", "noopener,noreferrer");
|
|
1033
|
-
sendResponse(msg.id, { isError: false });
|
|
1034
|
-
} else sendErrorResponse(msg.id, -32602, "Missing url parameter");
|
|
1035
|
-
break;
|
|
1036
|
-
}
|
|
1037
|
-
case "tools/call": {
|
|
1038
|
-
const { serverHash, serverId } = contentRef.current;
|
|
1039
|
-
const currentAgent = agentRef.current;
|
|
1040
|
-
if (!serverHash) {
|
|
1041
|
-
sendErrorResponse(msg.id, -32603, "No server hash available for proxying");
|
|
1042
|
-
break;
|
|
1043
|
-
}
|
|
1044
|
-
if (!currentAgent) {
|
|
1045
|
-
sendErrorResponse(msg.id, -32603, "No agent available for proxying");
|
|
1046
|
-
break;
|
|
1047
|
-
}
|
|
1048
|
-
try {
|
|
1049
|
-
const runResult = await mcpAppsRequestQueue.enqueue(currentAgent, () => currentAgent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
1050
|
-
serverHash,
|
|
1051
|
-
serverId,
|
|
1052
|
-
method: "tools/call",
|
|
1053
|
-
params: msg.params
|
|
1054
|
-
} } }));
|
|
1055
|
-
sendResponse(msg.id, runResult.result || {});
|
|
1056
|
-
} catch (err) {
|
|
1057
|
-
console.error("[MCPAppsRenderer] tools/call error:", err);
|
|
1058
|
-
sendErrorResponse(msg.id, -32603, String(err));
|
|
1059
|
-
}
|
|
1060
|
-
break;
|
|
1061
|
-
}
|
|
1062
|
-
default: sendErrorResponse(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
1063
|
-
}
|
|
1064
|
-
if (isNotification(msg)) switch (msg.method) {
|
|
1065
|
-
case "ui/notifications/initialized":
|
|
1066
|
-
console.log("[MCPAppsRenderer] Inner iframe initialized");
|
|
1067
|
-
if (mounted) setIframeReady(true);
|
|
1068
|
-
break;
|
|
1069
|
-
case "ui/notifications/size-changed": {
|
|
1070
|
-
const { width, height } = msg.params || {};
|
|
1071
|
-
console.log("[MCPAppsRenderer] Size change:", {
|
|
1072
|
-
width,
|
|
1073
|
-
height
|
|
1074
|
-
});
|
|
1075
|
-
if (mounted) setIframeSize({
|
|
1076
|
-
width: typeof width === "number" ? width : void 0,
|
|
1077
|
-
height: typeof height === "number" ? height : void 0
|
|
1078
|
-
});
|
|
1079
|
-
break;
|
|
1080
|
-
}
|
|
1081
|
-
case "notifications/message":
|
|
1082
|
-
console.log("[MCPAppsRenderer] App log:", msg.params);
|
|
1083
|
-
break;
|
|
1084
|
-
}
|
|
1085
|
-
};
|
|
1086
|
-
window.addEventListener("message", messageHandler);
|
|
1002
|
+
const win = iframe.contentWindow;
|
|
1003
|
+
if (!win) throw new Error("Sandbox iframe has no contentWindow");
|
|
1087
1004
|
let html;
|
|
1088
1005
|
if (fetchedResource.text) html = fetchedResource.text;
|
|
1089
1006
|
else if (fetchedResource.blob) html = atob(fetchedResource.blob);
|
|
1090
1007
|
else throw new Error("Resource has no text or blob content");
|
|
1091
|
-
|
|
1008
|
+
bridge = new AppBridge(null, {
|
|
1009
|
+
name: "CopilotKit MCP Apps Host",
|
|
1010
|
+
version: "1.0.0"
|
|
1011
|
+
}, {
|
|
1012
|
+
openLinks: {},
|
|
1013
|
+
logging: {},
|
|
1014
|
+
message: { text: {} }
|
|
1015
|
+
}, { hostContext: {
|
|
1016
|
+
theme: "light",
|
|
1017
|
+
platform: "web"
|
|
1018
|
+
} });
|
|
1019
|
+
bridge.onsandboxready = () => {
|
|
1020
|
+
bridge?.sendSandboxResourceReady({ html });
|
|
1021
|
+
};
|
|
1022
|
+
bridge.setRequestHandler(CopilotKitUiMessageSchema, async (req) => {
|
|
1023
|
+
const currentAgent = agentRef.current;
|
|
1024
|
+
if (!currentAgent) {
|
|
1025
|
+
console.warn("[MCPAppsRenderer] ui/message: No agent available");
|
|
1026
|
+
return { isError: false };
|
|
1027
|
+
}
|
|
1028
|
+
try {
|
|
1029
|
+
const params = req.params;
|
|
1030
|
+
const ck = params._meta?.copilotkit ?? {};
|
|
1031
|
+
const role = ck.role || params.role || "user";
|
|
1032
|
+
const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
|
|
1033
|
+
if (textContent) currentAgent.addMessage({
|
|
1034
|
+
id: crypto.randomUUID(),
|
|
1035
|
+
role,
|
|
1036
|
+
content: textContent
|
|
1037
|
+
});
|
|
1038
|
+
if ((ck.followUp ?? params.followUp ?? role === "user") && textContent) {
|
|
1039
|
+
const capturedThreadId = currentAgent.threadId || "default";
|
|
1040
|
+
mcpAppsRequestQueue.enqueue(currentAgent, () => ɵrunMcpFollowUp({
|
|
1041
|
+
host: copilotkit,
|
|
1042
|
+
agent: currentAgent,
|
|
1043
|
+
capturedThreadId
|
|
1044
|
+
})).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
|
|
1045
|
+
}
|
|
1046
|
+
return { isError: false };
|
|
1047
|
+
} catch (err) {
|
|
1048
|
+
console.error("[MCPAppsRenderer] ui/message error:", err);
|
|
1049
|
+
return { isError: true };
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
bridge.onopenlink = async ({ url }) => {
|
|
1053
|
+
let parsed;
|
|
1054
|
+
try {
|
|
1055
|
+
parsed = new URL(url);
|
|
1056
|
+
} catch {
|
|
1057
|
+
console.warn("[MCPAppsRenderer] ui/open-link rejected: unparseable url");
|
|
1058
|
+
return { isError: true };
|
|
1059
|
+
}
|
|
1060
|
+
if (MCP_OPEN_LINK_BLOCKED_SCHEMES.has(parsed.protocol)) {
|
|
1061
|
+
console.warn("[MCPAppsRenderer] ui/open-link rejected: blocked scheme", parsed.protocol);
|
|
1062
|
+
return { isError: true };
|
|
1063
|
+
}
|
|
1064
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1065
|
+
return { isError: false };
|
|
1066
|
+
};
|
|
1067
|
+
bridge.oncalltool = async (params) => {
|
|
1068
|
+
const { serverHash, serverId } = contentRef.current;
|
|
1069
|
+
const currentAgent = agentRef.current;
|
|
1070
|
+
if (!serverHash) throw new Error("No server hash available for proxying");
|
|
1071
|
+
if (!currentAgent) throw new Error("No agent available for proxying");
|
|
1072
|
+
return (await mcpAppsRequestQueue.enqueue(currentAgent, () => currentAgent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
1073
|
+
serverHash,
|
|
1074
|
+
serverId,
|
|
1075
|
+
method: "tools/call",
|
|
1076
|
+
params
|
|
1077
|
+
} } }))).result || { content: [] };
|
|
1078
|
+
};
|
|
1079
|
+
bridge.onsizechange = (p) => {
|
|
1080
|
+
if (!mounted) return;
|
|
1081
|
+
const { width, height } = p || {};
|
|
1082
|
+
setIframeSize({
|
|
1083
|
+
width: typeof width === "number" ? width : void 0,
|
|
1084
|
+
height: typeof height === "number" ? height : void 0
|
|
1085
|
+
});
|
|
1086
|
+
};
|
|
1087
|
+
bridge.oninitialized = () => {
|
|
1088
|
+
if (mounted) setIframeReady(true);
|
|
1089
|
+
};
|
|
1090
|
+
bridge.onloggingmessage = (p) => {
|
|
1091
|
+
console.log("[MCPAppsRenderer] App log:", p);
|
|
1092
|
+
};
|
|
1093
|
+
const transport = new PostMessageTransport(win, win);
|
|
1094
|
+
await bridge.connect(transport);
|
|
1095
|
+
if (!mounted) {
|
|
1096
|
+
await bridge.close();
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
bridgeRef.current = bridge;
|
|
1092
1100
|
} catch (err) {
|
|
1093
1101
|
console.error("[MCPAppsRenderer] Setup error:", err);
|
|
1094
1102
|
if (mounted) setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1097,11 +1105,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
1097
1105
|
setup();
|
|
1098
1106
|
return () => {
|
|
1099
1107
|
mounted = false;
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
initialListener = null;
|
|
1103
|
-
}
|
|
1104
|
-
if (messageHandler) window.removeEventListener("message", messageHandler);
|
|
1108
|
+
bridgeRef.current = null;
|
|
1109
|
+
bridge?.close();
|
|
1105
1110
|
if (createdIframe) {
|
|
1106
1111
|
createdIframe.remove();
|
|
1107
1112
|
createdIframe = null;
|
|
@@ -1111,9 +1116,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
1111
1116
|
}, [
|
|
1112
1117
|
isLoading,
|
|
1113
1118
|
fetchedResource,
|
|
1114
|
-
|
|
1115
|
-
sendResponse,
|
|
1116
|
-
sendErrorResponse
|
|
1119
|
+
copilotkit
|
|
1117
1120
|
]);
|
|
1118
1121
|
(0, react.useEffect)(() => {
|
|
1119
1122
|
if (iframeRef.current) {
|
|
@@ -1125,25 +1128,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
1125
1128
|
}
|
|
1126
1129
|
}, [iframeSize]);
|
|
1127
1130
|
(0, react.useEffect)(() => {
|
|
1128
|
-
if (iframeReady && content.toolInput) {
|
|
1129
|
-
|
|
1130
|
-
sendNotification("ui/notifications/tool-input", { arguments: content.toolInput });
|
|
1131
|
-
}
|
|
1132
|
-
}, [
|
|
1133
|
-
iframeReady,
|
|
1134
|
-
content.toolInput,
|
|
1135
|
-
sendNotification
|
|
1136
|
-
]);
|
|
1131
|
+
if (iframeReady && content.toolInput) bridgeRef.current?.sendToolInput({ arguments: content.toolInput });
|
|
1132
|
+
}, [iframeReady, content.toolInput]);
|
|
1137
1133
|
(0, react.useEffect)(() => {
|
|
1138
|
-
if (iframeReady && content.result)
|
|
1139
|
-
|
|
1140
|
-
sendNotification("ui/notifications/tool-result", content.result);
|
|
1141
|
-
}
|
|
1142
|
-
}, [
|
|
1143
|
-
iframeReady,
|
|
1144
|
-
content.result,
|
|
1145
|
-
sendNotification
|
|
1146
|
-
]);
|
|
1134
|
+
if (iframeReady && content.result) bridgeRef.current?.sendToolResult(content.result);
|
|
1135
|
+
}, [iframeReady, content.result]);
|
|
1147
1136
|
const borderStyle = fetchedResource?._meta?.ui?.prefersBorder === true ? {
|
|
1148
1137
|
borderRadius: "8px",
|
|
1149
1138
|
backgroundColor: "#f9f9f9",
|
|
@@ -2820,7 +2809,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2820
2809
|
tool.name,
|
|
2821
2810
|
tool.available,
|
|
2822
2811
|
copilotkit,
|
|
2823
|
-
JSON.stringify(extraDeps)
|
|
2812
|
+
JSON.stringify(extraDeps),
|
|
2813
|
+
JSON.stringify(tool.webmcp ?? null)
|
|
2824
2814
|
]);
|
|
2825
2815
|
}
|
|
2826
2816
|
|
|
@@ -4537,7 +4527,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
4537
4527
|
switch (error.code) {
|
|
4538
4528
|
case _copilotkit_shared.CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR: return { primary: {
|
|
4539
4529
|
label: "Show me how",
|
|
4540
|
-
onClick: () => window.open("https://docs.copilotkit.ai/
|
|
4530
|
+
onClick: () => window.open("https://docs.copilotkit.ai/intelligence/overview#plans-and-access", "_blank", "noopener,noreferrer")
|
|
4541
4531
|
} };
|
|
4542
4532
|
case _copilotkit_shared.CopilotKitErrorCode.UPGRADE_REQUIRED_ERROR: return { primary: {
|
|
4543
4533
|
label: "Upgrade",
|
|
@@ -6129,7 +6119,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
6129
6119
|
* `useCopilotChatHeadless_c` is for building fully custom UI (headless UI) implementations.
|
|
6130
6120
|
*
|
|
6131
6121
|
* <Callout title="This is a CopilotKit Intelligence feature">
|
|
6132
|
-
* Read more about <a href="/
|
|
6122
|
+
* Read more about <a href="/intelligence/overview">CopilotKit Intelligence</a>.
|
|
6133
6123
|
*
|
|
6134
6124
|
* Usage is generous and **free** to get started.
|
|
6135
6125
|
* </Callout>
|
|
@@ -6360,7 +6350,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
6360
6350
|
* See https://docs.copilotkit.ai/reference/v2/hooks/useFrontendTool
|
|
6361
6351
|
*/
|
|
6362
6352
|
function useFrontendTool(tool, dependencies) {
|
|
6363
|
-
const { name, description, parameters, render, followUp, available } = tool;
|
|
6353
|
+
const { name, description, parameters, render, followUp, available, webmcp } = tool;
|
|
6364
6354
|
const zodParameters = (0, _copilotkit_shared.getZodParameters)(parameters);
|
|
6365
6355
|
const renderRef = (0, react.useRef)(render);
|
|
6366
6356
|
(0, react.useEffect)(() => {
|
|
@@ -6391,7 +6381,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
6391
6381
|
handler: tool.handler ? (args) => handlerRef.current?.(args) : void 0,
|
|
6392
6382
|
followUp,
|
|
6393
6383
|
render: normalizedRender,
|
|
6394
|
-
available: available === void 0 ? void 0 : available !== "disabled"
|
|
6384
|
+
available: available === void 0 ? void 0 : available !== "disabled",
|
|
6385
|
+
webmcp
|
|
6395
6386
|
});
|
|
6396
6387
|
}
|
|
6397
6388
|
|