@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/v2/index.umd.js
CHANGED
|
@@ -283,6 +283,62 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
283
283
|
const useCopilotChatConfiguration = () => {
|
|
284
284
|
return (0, react.useContext)(CopilotChatConfiguration);
|
|
285
285
|
};
|
|
286
|
+
/**
|
|
287
|
+
* Reports modal open/close requests to the host, and — when `open` is
|
|
288
|
+
* supplied — makes the modal state of an already-established chat
|
|
289
|
+
* configuration **controlled** for the subtree it wraps.
|
|
290
|
+
*
|
|
291
|
+
* This is deliberately a scope component rather than another mode inside
|
|
292
|
+
* {@link CopilotChatConfigurationProvider}. The provider resolves modal state
|
|
293
|
+
* across a nested chain (own state, parent sync, drawer mutual-exclusion, the
|
|
294
|
+
* modal-closer registry); a controlled branch inside that resolution would add
|
|
295
|
+
* a fourth interacting mode. Overriding the context for the subtree instead
|
|
296
|
+
* leaves every one of those paths untouched:
|
|
297
|
+
*
|
|
298
|
+
* - `isModalOpen` is replaced with the host's `open`, so the rendered surface
|
|
299
|
+
* follows the prop from the very first frame (no open-then-close flash).
|
|
300
|
+
* - `setModalOpen` still calls the underlying setter, so the existing
|
|
301
|
+
* parent-sync and drawer mutual-exclusion side effects continue to run, and
|
|
302
|
+
* *then* reports the request through `onOpenChange`.
|
|
303
|
+
* - The wrapped setter is registered as the modal closer, so the drawer's
|
|
304
|
+
* mobile mutual-exclusion reaches the host instead of silently flipping
|
|
305
|
+
* state that nothing displays.
|
|
306
|
+
*
|
|
307
|
+
* A host that supplies `open` and ignores `onOpenChange` gets a modal pinned
|
|
308
|
+
* to `open`, which is the standard controlled-component contract. A host that
|
|
309
|
+
* supplies only `onOpenChange` is notified while the modal keeps managing
|
|
310
|
+
* itself.
|
|
311
|
+
*
|
|
312
|
+
* Renders `children` unchanged when no chat configuration is in scope.
|
|
313
|
+
*/
|
|
314
|
+
const ControlledModalOpenScope = ({ children, open, onOpenChange }) => {
|
|
315
|
+
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
316
|
+
const parentSetModalOpen = parentConfig?.setModalOpen;
|
|
317
|
+
const registerModalCloser = parentConfig?.ɵregisterModalCloser;
|
|
318
|
+
const setModalOpen = (0, react.useCallback)((next) => {
|
|
319
|
+
parentSetModalOpen?.(next);
|
|
320
|
+
onOpenChange?.(next);
|
|
321
|
+
}, [parentSetModalOpen, onOpenChange]);
|
|
322
|
+
(0, react.useEffect)(() => {
|
|
323
|
+
if (!registerModalCloser) return;
|
|
324
|
+
return registerModalCloser(setModalOpen);
|
|
325
|
+
}, [registerModalCloser, setModalOpen]);
|
|
326
|
+
const configurationValue = (0, react.useMemo)(() => parentConfig ? {
|
|
327
|
+
...parentConfig,
|
|
328
|
+
isModalOpen: open ?? parentConfig.isModalOpen,
|
|
329
|
+
setModalOpen
|
|
330
|
+
} : null, [
|
|
331
|
+
parentConfig,
|
|
332
|
+
open,
|
|
333
|
+
setModalOpen
|
|
334
|
+
]);
|
|
335
|
+
if (!configurationValue) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
|
|
336
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
|
|
337
|
+
value: configurationValue,
|
|
338
|
+
children
|
|
339
|
+
});
|
|
340
|
+
};
|
|
341
|
+
ControlledModalOpenScope.displayName = "ControlledModalOpenScope";
|
|
286
342
|
|
|
287
343
|
//#endregion
|
|
288
344
|
//#region src/v2/lib/utils.ts
|
|
@@ -1876,7 +1932,6 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1876
1932
|
newMessages: []
|
|
1877
1933
|
};
|
|
1878
1934
|
}
|
|
1879
|
-
const PROTOCOL_VERSION = "2025-06-18";
|
|
1880
1935
|
function buildSandboxHTML(extraCspDomains) {
|
|
1881
1936
|
const baseScriptSrc = "'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*";
|
|
1882
1937
|
const baseFrameSrc = "* blob: data: http://localhost:* https://localhost:*";
|
|
@@ -1988,6 +2043,13 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
1988
2043
|
}
|
|
1989
2044
|
};
|
|
1990
2045
|
const mcpAppsRequestQueue = new MCPAppsRequestQueue();
|
|
2046
|
+
const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([
|
|
2047
|
+
"javascript:",
|
|
2048
|
+
"data:",
|
|
2049
|
+
"vbscript:",
|
|
2050
|
+
"blob:",
|
|
2051
|
+
"file:"
|
|
2052
|
+
]);
|
|
1991
2053
|
/**
|
|
1992
2054
|
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType
|
|
1993
2055
|
*/
|
|
@@ -2003,18 +2065,32 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2003
2065
|
serverId: zod.z.string().optional(),
|
|
2004
2066
|
toolInput: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
2005
2067
|
});
|
|
2006
|
-
function isRequest(msg) {
|
|
2007
|
-
return "id" in msg && "method" in msg;
|
|
2008
|
-
}
|
|
2009
|
-
function isNotification(msg) {
|
|
2010
|
-
return !("id" in msg) && "method" in msg;
|
|
2011
|
-
}
|
|
2012
2068
|
/**
|
|
2013
2069
|
* MCP Apps Extension Activity Renderer
|
|
2014
2070
|
*
|
|
2015
2071
|
* Renders MCP Apps UI in a sandboxed iframe with full protocol support.
|
|
2016
2072
|
* Fetches resource content on-demand via proxied MCP requests.
|
|
2017
2073
|
*/
|
|
2074
|
+
/**
|
|
2075
|
+
* Permissive `ui/message` schema. ext-apps restricts the request to
|
|
2076
|
+
* `role: "user"` with no `followUp`, but CopilotKit intentionally extends
|
|
2077
|
+
* `ui/message` with `role` ("user" | "assistant") and `followUp` (documented
|
|
2078
|
+
* behavior with dedicated tests). We register our own handler (instead of the
|
|
2079
|
+
* bridge's strict `onmessage`) so those extensions survive the migration.
|
|
2080
|
+
*
|
|
2081
|
+
* Going forward, widgets SHOULD pass the extensions under
|
|
2082
|
+
* `params._meta.copilotkit`; the top-level `role`/`followUp` fields are the
|
|
2083
|
+
* legacy channel, kept for backward compatibility and slated for deprecation.
|
|
2084
|
+
*/
|
|
2085
|
+
const CopilotKitUiMessageSchema = zod.z.object({
|
|
2086
|
+
method: zod.z.literal("ui/message"),
|
|
2087
|
+
params: zod.z.object({
|
|
2088
|
+
role: zod.z.string().optional(),
|
|
2089
|
+
content: zod.z.array(zod.z.any()).optional(),
|
|
2090
|
+
followUp: zod.z.boolean().optional(),
|
|
2091
|
+
_meta: zod.z.record(zod.z.string(), zod.z.any()).optional()
|
|
2092
|
+
}).passthrough()
|
|
2093
|
+
});
|
|
2018
2094
|
const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agent }) {
|
|
2019
2095
|
const { copilotkit } = useCopilotKit();
|
|
2020
2096
|
const containerRef = (0, react.useRef)(null);
|
|
@@ -2028,41 +2104,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2028
2104
|
contentRef.current = content;
|
|
2029
2105
|
const agentRef = (0, react.useRef)(agent);
|
|
2030
2106
|
agentRef.current = agent;
|
|
2107
|
+
const bridgeRef = (0, react.useRef)(null);
|
|
2031
2108
|
const fetchStateRef = (0, react.useRef)({
|
|
2032
2109
|
inProgress: false,
|
|
2033
2110
|
promise: null,
|
|
2034
2111
|
resourceUri: null
|
|
2035
2112
|
});
|
|
2036
|
-
const sendToIframe = (0, react.useCallback)((msg) => {
|
|
2037
|
-
if (iframeRef.current?.contentWindow) {
|
|
2038
|
-
console.log("[MCPAppsRenderer] Sending to iframe:", msg);
|
|
2039
|
-
iframeRef.current.contentWindow.postMessage(msg, "*");
|
|
2040
|
-
}
|
|
2041
|
-
}, []);
|
|
2042
|
-
const sendResponse = (0, react.useCallback)((id, result) => {
|
|
2043
|
-
sendToIframe({
|
|
2044
|
-
jsonrpc: "2.0",
|
|
2045
|
-
id,
|
|
2046
|
-
result
|
|
2047
|
-
});
|
|
2048
|
-
}, [sendToIframe]);
|
|
2049
|
-
const sendErrorResponse = (0, react.useCallback)((id, code, message) => {
|
|
2050
|
-
sendToIframe({
|
|
2051
|
-
jsonrpc: "2.0",
|
|
2052
|
-
id,
|
|
2053
|
-
error: {
|
|
2054
|
-
code,
|
|
2055
|
-
message
|
|
2056
|
-
}
|
|
2057
|
-
});
|
|
2058
|
-
}, [sendToIframe]);
|
|
2059
|
-
const sendNotification = (0, react.useCallback)((method, params) => {
|
|
2060
|
-
sendToIframe({
|
|
2061
|
-
jsonrpc: "2.0",
|
|
2062
|
-
method,
|
|
2063
|
-
params: params || {}
|
|
2064
|
-
});
|
|
2065
|
-
}, [sendToIframe]);
|
|
2066
2113
|
(0, react.useEffect)(() => {
|
|
2067
2114
|
const { resourceUri, serverHash, serverId } = content;
|
|
2068
2115
|
if (fetchStateRef.current.inProgress && fetchStateRef.current.resourceUri === resourceUri) {
|
|
@@ -2117,11 +2164,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2117
2164
|
const container = containerRef.current;
|
|
2118
2165
|
if (!container) return;
|
|
2119
2166
|
let mounted = true;
|
|
2120
|
-
let
|
|
2121
|
-
let initialListener = null;
|
|
2167
|
+
let bridge = null;
|
|
2122
2168
|
let createdIframe = null;
|
|
2123
2169
|
const setup = async () => {
|
|
2124
2170
|
try {
|
|
2171
|
+
const bridgeModule = await import("@modelcontextprotocol/ext-apps/app-bridge").catch((importErr) => {
|
|
2172
|
+
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 });
|
|
2173
|
+
});
|
|
2174
|
+
if (!mounted) return;
|
|
2175
|
+
const { AppBridge, PostMessageTransport } = bridgeModule;
|
|
2125
2176
|
const iframe = document.createElement("iframe");
|
|
2126
2177
|
createdIframe = iframe;
|
|
2127
2178
|
iframe.style.width = "100%";
|
|
@@ -2132,151 +2183,108 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2132
2183
|
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
|
|
2133
2184
|
iframe.setAttribute("data-testid", "mcp-app-iframe");
|
|
2134
2185
|
iframe.setAttribute("title", "Interactive MCP application");
|
|
2135
|
-
const sandboxReady = new Promise((resolve) => {
|
|
2136
|
-
initialListener = (event) => {
|
|
2137
|
-
if (event.source === iframe.contentWindow) {
|
|
2138
|
-
if (event.data?.method === "ui/notifications/sandbox-proxy-ready") {
|
|
2139
|
-
if (initialListener) {
|
|
2140
|
-
window.removeEventListener("message", initialListener);
|
|
2141
|
-
initialListener = null;
|
|
2142
|
-
}
|
|
2143
|
-
resolve();
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
};
|
|
2147
|
-
window.addEventListener("message", initialListener);
|
|
2148
|
-
});
|
|
2149
|
-
if (!mounted) {
|
|
2150
|
-
if (initialListener) {
|
|
2151
|
-
window.removeEventListener("message", initialListener);
|
|
2152
|
-
initialListener = null;
|
|
2153
|
-
}
|
|
2154
|
-
return;
|
|
2155
|
-
}
|
|
2156
2186
|
const cspDomains = fetchedResource._meta?.ui?.csp?.resourceDomains;
|
|
2157
2187
|
iframe.srcdoc = buildSandboxHTML(cspDomains);
|
|
2158
2188
|
iframeRef.current = iframe;
|
|
2159
2189
|
container.appendChild(iframe);
|
|
2160
|
-
|
|
2161
|
-
if (!
|
|
2162
|
-
console.log("[MCPAppsRenderer] Sandbox proxy ready");
|
|
2163
|
-
messageHandler = async (event) => {
|
|
2164
|
-
if (event.source !== iframe.contentWindow) return;
|
|
2165
|
-
const msg = event.data;
|
|
2166
|
-
if (!msg || typeof msg !== "object" || msg.jsonrpc !== "2.0") return;
|
|
2167
|
-
console.log("[MCPAppsRenderer] Received from iframe:", msg);
|
|
2168
|
-
if (isRequest(msg)) switch (msg.method) {
|
|
2169
|
-
case "ui/initialize":
|
|
2170
|
-
sendResponse(msg.id, {
|
|
2171
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
2172
|
-
hostInfo: {
|
|
2173
|
-
name: "CopilotKit MCP Apps Host",
|
|
2174
|
-
version: "1.0.0"
|
|
2175
|
-
},
|
|
2176
|
-
hostCapabilities: {
|
|
2177
|
-
openLinks: {},
|
|
2178
|
-
logging: {}
|
|
2179
|
-
},
|
|
2180
|
-
hostContext: {
|
|
2181
|
-
theme: "light",
|
|
2182
|
-
platform: "web"
|
|
2183
|
-
}
|
|
2184
|
-
});
|
|
2185
|
-
break;
|
|
2186
|
-
case "ui/message": {
|
|
2187
|
-
const currentAgent = agentRef.current;
|
|
2188
|
-
if (!currentAgent) {
|
|
2189
|
-
console.warn("[MCPAppsRenderer] ui/message: No agent available");
|
|
2190
|
-
sendResponse(msg.id, { isError: false });
|
|
2191
|
-
break;
|
|
2192
|
-
}
|
|
2193
|
-
try {
|
|
2194
|
-
const params = msg.params;
|
|
2195
|
-
const role = params.role || "user";
|
|
2196
|
-
const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
|
|
2197
|
-
if (textContent) currentAgent.addMessage({
|
|
2198
|
-
id: crypto.randomUUID(),
|
|
2199
|
-
role,
|
|
2200
|
-
content: textContent
|
|
2201
|
-
});
|
|
2202
|
-
sendResponse(msg.id, { isError: false });
|
|
2203
|
-
if ((params.followUp ?? role === "user") && textContent) {
|
|
2204
|
-
const capturedThreadId = currentAgent.threadId || "default";
|
|
2205
|
-
mcpAppsRequestQueue.enqueue(currentAgent, () => ɵrunMcpFollowUp({
|
|
2206
|
-
host: copilotkit,
|
|
2207
|
-
agent: currentAgent,
|
|
2208
|
-
capturedThreadId
|
|
2209
|
-
})).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
|
|
2210
|
-
}
|
|
2211
|
-
} catch (err) {
|
|
2212
|
-
console.error("[MCPAppsRenderer] ui/message error:", err);
|
|
2213
|
-
sendResponse(msg.id, { isError: true });
|
|
2214
|
-
}
|
|
2215
|
-
break;
|
|
2216
|
-
}
|
|
2217
|
-
case "ui/open-link": {
|
|
2218
|
-
const url = msg.params?.url;
|
|
2219
|
-
if (url) {
|
|
2220
|
-
window.open(url, "_blank", "noopener,noreferrer");
|
|
2221
|
-
sendResponse(msg.id, { isError: false });
|
|
2222
|
-
} else sendErrorResponse(msg.id, -32602, "Missing url parameter");
|
|
2223
|
-
break;
|
|
2224
|
-
}
|
|
2225
|
-
case "tools/call": {
|
|
2226
|
-
const { serverHash, serverId } = contentRef.current;
|
|
2227
|
-
const currentAgent = agentRef.current;
|
|
2228
|
-
if (!serverHash) {
|
|
2229
|
-
sendErrorResponse(msg.id, -32603, "No server hash available for proxying");
|
|
2230
|
-
break;
|
|
2231
|
-
}
|
|
2232
|
-
if (!currentAgent) {
|
|
2233
|
-
sendErrorResponse(msg.id, -32603, "No agent available for proxying");
|
|
2234
|
-
break;
|
|
2235
|
-
}
|
|
2236
|
-
try {
|
|
2237
|
-
const runResult = await mcpAppsRequestQueue.enqueue(currentAgent, () => currentAgent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
2238
|
-
serverHash,
|
|
2239
|
-
serverId,
|
|
2240
|
-
method: "tools/call",
|
|
2241
|
-
params: msg.params
|
|
2242
|
-
} } }));
|
|
2243
|
-
sendResponse(msg.id, runResult.result || {});
|
|
2244
|
-
} catch (err) {
|
|
2245
|
-
console.error("[MCPAppsRenderer] tools/call error:", err);
|
|
2246
|
-
sendErrorResponse(msg.id, -32603, String(err));
|
|
2247
|
-
}
|
|
2248
|
-
break;
|
|
2249
|
-
}
|
|
2250
|
-
default: sendErrorResponse(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
2251
|
-
}
|
|
2252
|
-
if (isNotification(msg)) switch (msg.method) {
|
|
2253
|
-
case "ui/notifications/initialized":
|
|
2254
|
-
console.log("[MCPAppsRenderer] Inner iframe initialized");
|
|
2255
|
-
if (mounted) setIframeReady(true);
|
|
2256
|
-
break;
|
|
2257
|
-
case "ui/notifications/size-changed": {
|
|
2258
|
-
const { width, height } = msg.params || {};
|
|
2259
|
-
console.log("[MCPAppsRenderer] Size change:", {
|
|
2260
|
-
width,
|
|
2261
|
-
height
|
|
2262
|
-
});
|
|
2263
|
-
if (mounted) setIframeSize({
|
|
2264
|
-
width: typeof width === "number" ? width : void 0,
|
|
2265
|
-
height: typeof height === "number" ? height : void 0
|
|
2266
|
-
});
|
|
2267
|
-
break;
|
|
2268
|
-
}
|
|
2269
|
-
case "notifications/message":
|
|
2270
|
-
console.log("[MCPAppsRenderer] App log:", msg.params);
|
|
2271
|
-
break;
|
|
2272
|
-
}
|
|
2273
|
-
};
|
|
2274
|
-
window.addEventListener("message", messageHandler);
|
|
2190
|
+
const win = iframe.contentWindow;
|
|
2191
|
+
if (!win) throw new Error("Sandbox iframe has no contentWindow");
|
|
2275
2192
|
let html;
|
|
2276
2193
|
if (fetchedResource.text) html = fetchedResource.text;
|
|
2277
2194
|
else if (fetchedResource.blob) html = atob(fetchedResource.blob);
|
|
2278
2195
|
else throw new Error("Resource has no text or blob content");
|
|
2279
|
-
|
|
2196
|
+
bridge = new AppBridge(null, {
|
|
2197
|
+
name: "CopilotKit MCP Apps Host",
|
|
2198
|
+
version: "1.0.0"
|
|
2199
|
+
}, {
|
|
2200
|
+
openLinks: {},
|
|
2201
|
+
logging: {},
|
|
2202
|
+
message: { text: {} }
|
|
2203
|
+
}, { hostContext: {
|
|
2204
|
+
theme: "light",
|
|
2205
|
+
platform: "web"
|
|
2206
|
+
} });
|
|
2207
|
+
bridge.onsandboxready = () => {
|
|
2208
|
+
bridge?.sendSandboxResourceReady({ html });
|
|
2209
|
+
};
|
|
2210
|
+
bridge.setRequestHandler(CopilotKitUiMessageSchema, async (req) => {
|
|
2211
|
+
const currentAgent = agentRef.current;
|
|
2212
|
+
if (!currentAgent) {
|
|
2213
|
+
console.warn("[MCPAppsRenderer] ui/message: No agent available");
|
|
2214
|
+
return { isError: false };
|
|
2215
|
+
}
|
|
2216
|
+
try {
|
|
2217
|
+
const params = req.params;
|
|
2218
|
+
const ck = params._meta?.copilotkit ?? {};
|
|
2219
|
+
const role = ck.role || params.role || "user";
|
|
2220
|
+
const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
|
|
2221
|
+
if (textContent) currentAgent.addMessage({
|
|
2222
|
+
id: crypto.randomUUID(),
|
|
2223
|
+
role,
|
|
2224
|
+
content: textContent
|
|
2225
|
+
});
|
|
2226
|
+
if ((ck.followUp ?? params.followUp ?? role === "user") && textContent) {
|
|
2227
|
+
const capturedThreadId = currentAgent.threadId || "default";
|
|
2228
|
+
mcpAppsRequestQueue.enqueue(currentAgent, () => ɵrunMcpFollowUp({
|
|
2229
|
+
host: copilotkit,
|
|
2230
|
+
agent: currentAgent,
|
|
2231
|
+
capturedThreadId
|
|
2232
|
+
})).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
|
|
2233
|
+
}
|
|
2234
|
+
return { isError: false };
|
|
2235
|
+
} catch (err) {
|
|
2236
|
+
console.error("[MCPAppsRenderer] ui/message error:", err);
|
|
2237
|
+
return { isError: true };
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2240
|
+
bridge.onopenlink = async ({ url }) => {
|
|
2241
|
+
let parsed;
|
|
2242
|
+
try {
|
|
2243
|
+
parsed = new URL(url);
|
|
2244
|
+
} catch {
|
|
2245
|
+
console.warn("[MCPAppsRenderer] ui/open-link rejected: unparseable url");
|
|
2246
|
+
return { isError: true };
|
|
2247
|
+
}
|
|
2248
|
+
if (MCP_OPEN_LINK_BLOCKED_SCHEMES.has(parsed.protocol)) {
|
|
2249
|
+
console.warn("[MCPAppsRenderer] ui/open-link rejected: blocked scheme", parsed.protocol);
|
|
2250
|
+
return { isError: true };
|
|
2251
|
+
}
|
|
2252
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
2253
|
+
return { isError: false };
|
|
2254
|
+
};
|
|
2255
|
+
bridge.oncalltool = async (params) => {
|
|
2256
|
+
const { serverHash, serverId } = contentRef.current;
|
|
2257
|
+
const currentAgent = agentRef.current;
|
|
2258
|
+
if (!serverHash) throw new Error("No server hash available for proxying");
|
|
2259
|
+
if (!currentAgent) throw new Error("No agent available for proxying");
|
|
2260
|
+
return (await mcpAppsRequestQueue.enqueue(currentAgent, () => currentAgent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
2261
|
+
serverHash,
|
|
2262
|
+
serverId,
|
|
2263
|
+
method: "tools/call",
|
|
2264
|
+
params
|
|
2265
|
+
} } }))).result || { content: [] };
|
|
2266
|
+
};
|
|
2267
|
+
bridge.onsizechange = (p) => {
|
|
2268
|
+
if (!mounted) return;
|
|
2269
|
+
const { width, height } = p || {};
|
|
2270
|
+
setIframeSize({
|
|
2271
|
+
width: typeof width === "number" ? width : void 0,
|
|
2272
|
+
height: typeof height === "number" ? height : void 0
|
|
2273
|
+
});
|
|
2274
|
+
};
|
|
2275
|
+
bridge.oninitialized = () => {
|
|
2276
|
+
if (mounted) setIframeReady(true);
|
|
2277
|
+
};
|
|
2278
|
+
bridge.onloggingmessage = (p) => {
|
|
2279
|
+
console.log("[MCPAppsRenderer] App log:", p);
|
|
2280
|
+
};
|
|
2281
|
+
const transport = new PostMessageTransport(win, win);
|
|
2282
|
+
await bridge.connect(transport);
|
|
2283
|
+
if (!mounted) {
|
|
2284
|
+
await bridge.close();
|
|
2285
|
+
return;
|
|
2286
|
+
}
|
|
2287
|
+
bridgeRef.current = bridge;
|
|
2280
2288
|
} catch (err) {
|
|
2281
2289
|
console.error("[MCPAppsRenderer] Setup error:", err);
|
|
2282
2290
|
if (mounted) setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -2285,11 +2293,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2285
2293
|
setup();
|
|
2286
2294
|
return () => {
|
|
2287
2295
|
mounted = false;
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
initialListener = null;
|
|
2291
|
-
}
|
|
2292
|
-
if (messageHandler) window.removeEventListener("message", messageHandler);
|
|
2296
|
+
bridgeRef.current = null;
|
|
2297
|
+
bridge?.close();
|
|
2293
2298
|
if (createdIframe) {
|
|
2294
2299
|
createdIframe.remove();
|
|
2295
2300
|
createdIframe = null;
|
|
@@ -2299,9 +2304,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2299
2304
|
}, [
|
|
2300
2305
|
isLoading,
|
|
2301
2306
|
fetchedResource,
|
|
2302
|
-
|
|
2303
|
-
sendResponse,
|
|
2304
|
-
sendErrorResponse
|
|
2307
|
+
copilotkit
|
|
2305
2308
|
]);
|
|
2306
2309
|
(0, react.useEffect)(() => {
|
|
2307
2310
|
if (iframeRef.current) {
|
|
@@ -2313,25 +2316,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2313
2316
|
}
|
|
2314
2317
|
}, [iframeSize]);
|
|
2315
2318
|
(0, react.useEffect)(() => {
|
|
2316
|
-
if (iframeReady && content.toolInput) {
|
|
2317
|
-
|
|
2318
|
-
sendNotification("ui/notifications/tool-input", { arguments: content.toolInput });
|
|
2319
|
-
}
|
|
2320
|
-
}, [
|
|
2321
|
-
iframeReady,
|
|
2322
|
-
content.toolInput,
|
|
2323
|
-
sendNotification
|
|
2324
|
-
]);
|
|
2319
|
+
if (iframeReady && content.toolInput) bridgeRef.current?.sendToolInput({ arguments: content.toolInput });
|
|
2320
|
+
}, [iframeReady, content.toolInput]);
|
|
2325
2321
|
(0, react.useEffect)(() => {
|
|
2326
|
-
if (iframeReady && content.result)
|
|
2327
|
-
|
|
2328
|
-
sendNotification("ui/notifications/tool-result", content.result);
|
|
2329
|
-
}
|
|
2330
|
-
}, [
|
|
2331
|
-
iframeReady,
|
|
2332
|
-
content.result,
|
|
2333
|
-
sendNotification
|
|
2334
|
-
]);
|
|
2322
|
+
if (iframeReady && content.result) bridgeRef.current?.sendToolResult(content.result);
|
|
2323
|
+
}, [iframeReady, content.result]);
|
|
2335
2324
|
const borderStyle = fetchedResource?._meta?.ui?.prefersBorder === true ? {
|
|
2336
2325
|
borderRadius: "8px",
|
|
2337
2326
|
backgroundColor: "#f9f9f9",
|
|
@@ -4050,7 +4039,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
4050
4039
|
tool.name,
|
|
4051
4040
|
tool.available,
|
|
4052
4041
|
copilotkit,
|
|
4053
|
-
JSON.stringify(extraDeps)
|
|
4042
|
+
JSON.stringify(extraDeps),
|
|
4043
|
+
JSON.stringify(tool.webmcp ?? null)
|
|
4054
4044
|
]);
|
|
4055
4045
|
}
|
|
4056
4046
|
|
|
@@ -5505,7 +5495,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5505
5495
|
* at the call site.
|
|
5506
5496
|
*/
|
|
5507
5497
|
async function recordAnnotation(args) {
|
|
5508
|
-
const { runtimeUrl, headers, type, payload, threadId, occurredAt } = args;
|
|
5498
|
+
const { runtimeUrl, headers, type, payload, threadId, occurredAt, fetch: fetchImplementation = globalThis.fetch } = args;
|
|
5509
5499
|
const body = {
|
|
5510
5500
|
type,
|
|
5511
5501
|
threadId,
|
|
@@ -5513,7 +5503,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5513
5503
|
...payload !== void 0 ? { payload } : {},
|
|
5514
5504
|
...occurredAt !== void 0 ? { occurredAt } : {}
|
|
5515
5505
|
};
|
|
5516
|
-
const response = await
|
|
5506
|
+
const response = await fetchImplementation(`${runtimeUrl}/annotate`, {
|
|
5517
5507
|
method: "POST",
|
|
5518
5508
|
headers: {
|
|
5519
5509
|
"Content-Type": "application/json",
|
|
@@ -5582,6 +5572,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5582
5572
|
...input.data !== void 0 ? { data: input.data } : {}
|
|
5583
5573
|
};
|
|
5584
5574
|
return recordAnnotation({
|
|
5575
|
+
fetch: copilotkit.ɵruntimeFetch,
|
|
5585
5576
|
runtimeUrl,
|
|
5586
5577
|
headers: copilotkit.headers ?? {},
|
|
5587
5578
|
type: "user_action",
|
|
@@ -5651,7 +5642,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5651
5642
|
|
|
5652
5643
|
//#endregion
|
|
5653
5644
|
//#region src/v2/hooks/use-attachments.tsx
|
|
5654
|
-
|
|
5645
|
+
const DEFAULT_MAX_SIZE = 20 * 1024 * 1024;
|
|
5646
|
+
/**
|
|
5647
|
+
* How many uploads run at once when `maxConcurrentUploads` is unset. One, because
|
|
5648
|
+
* `onUpload` is a public callback an app may have written expecting the previous
|
|
5649
|
+
* file to have finished — concurrency is something the app asks for.
|
|
5650
|
+
*/
|
|
5651
|
+
const DEFAULT_MAX_CONCURRENT_UPLOADS = 1;
|
|
5652
|
+
/**
|
|
5653
|
+
* At least one upload at a time, whole files only; `NaN` or a non-number falls back to the
|
|
5654
|
+
* default, and `Infinity` means "no limit" — bounded in practice by how many files are queued.
|
|
5655
|
+
*/
|
|
5656
|
+
function resolveMaxConcurrentUploads(configured) {
|
|
5657
|
+
if (typeof configured !== "number" || Number.isNaN(configured)) return DEFAULT_MAX_CONCURRENT_UPLOADS;
|
|
5658
|
+
return Math.max(1, Math.floor(configured));
|
|
5659
|
+
}
|
|
5660
|
+
/**
|
|
5655
5661
|
* Hook that manages file attachment state — uploads, drag-and-drop, paste,
|
|
5656
5662
|
* and lifecycle. All returned callbacks are referentially stable across
|
|
5657
5663
|
* renders (via useCallback) to avoid destabilizing downstream memoization.
|
|
@@ -5666,10 +5672,62 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5666
5672
|
configRef.current = config;
|
|
5667
5673
|
const attachmentsRef = (0, react.useRef)([]);
|
|
5668
5674
|
attachmentsRef.current = attachments;
|
|
5675
|
+
const uploadQueueRef = (0, react.useRef)([]);
|
|
5676
|
+
const activeWorkersRef = (0, react.useRef)(0);
|
|
5677
|
+
const uploadFile = (0, react.useCallback)(async (file, placeholder, cfg) => {
|
|
5678
|
+
try {
|
|
5679
|
+
let source;
|
|
5680
|
+
let uploadMetadata;
|
|
5681
|
+
if (cfg?.onUpload) {
|
|
5682
|
+
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
5683
|
+
source = uploadSource;
|
|
5684
|
+
uploadMetadata = meta;
|
|
5685
|
+
} else source = {
|
|
5686
|
+
type: "data",
|
|
5687
|
+
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
5688
|
+
mimeType: file.type
|
|
5689
|
+
};
|
|
5690
|
+
let thumbnail;
|
|
5691
|
+
if (placeholder.type === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
5692
|
+
setAttachments((prev) => prev.map((att) => att.id === placeholder.id ? {
|
|
5693
|
+
...att,
|
|
5694
|
+
source,
|
|
5695
|
+
status: "ready",
|
|
5696
|
+
thumbnail,
|
|
5697
|
+
metadata: uploadMetadata
|
|
5698
|
+
} : att));
|
|
5699
|
+
} catch (error) {
|
|
5700
|
+
setAttachments((prev) => prev.filter((att) => att.id !== placeholder.id));
|
|
5701
|
+
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
5702
|
+
cfg?.onUploadFailed?.({
|
|
5703
|
+
reason: "upload-failed",
|
|
5704
|
+
file,
|
|
5705
|
+
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
5706
|
+
});
|
|
5707
|
+
}
|
|
5708
|
+
}, []);
|
|
5709
|
+
const drainUploadQueue = (0, react.useCallback)(async () => {
|
|
5710
|
+
activeWorkersRef.current++;
|
|
5711
|
+
try {
|
|
5712
|
+
for (;;) {
|
|
5713
|
+
const item = uploadQueueRef.current.shift();
|
|
5714
|
+
if (!item) return;
|
|
5715
|
+
try {
|
|
5716
|
+
await uploadFile(item.file, item.placeholder, item.cfg);
|
|
5717
|
+
} catch (error) {
|
|
5718
|
+
console.error("[CopilotKit] Upload worker error:", error);
|
|
5719
|
+
} finally {
|
|
5720
|
+
item.settle();
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
} finally {
|
|
5724
|
+
activeWorkersRef.current--;
|
|
5725
|
+
}
|
|
5726
|
+
}, [uploadFile]);
|
|
5669
5727
|
const processFiles = (0, react.useCallback)(async (files) => {
|
|
5670
5728
|
const cfg = configRef.current;
|
|
5671
5729
|
const accept = cfg?.accept ?? "*/*";
|
|
5672
|
-
const maxSize = cfg?.maxSize ??
|
|
5730
|
+
const maxSize = cfg?.maxSize ?? DEFAULT_MAX_SIZE;
|
|
5673
5731
|
const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
5674
5732
|
for (const file of rejectedFiles) cfg?.onUploadFailed?.({
|
|
5675
5733
|
reason: "invalid-type",
|
|
@@ -5677,6 +5735,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5677
5735
|
message: `File "${file.name}" is not accepted. Supported types: ${accept}`
|
|
5678
5736
|
});
|
|
5679
5737
|
const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
5738
|
+
const queued = [];
|
|
5680
5739
|
for (const file of validFiles) {
|
|
5681
5740
|
if ((0, _copilotkit_shared.exceedsMaxSize)(file, maxSize)) {
|
|
5682
5741
|
cfg?.onUploadFailed?.({
|
|
@@ -5686,53 +5745,37 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5686
5745
|
});
|
|
5687
5746
|
continue;
|
|
5688
5747
|
}
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
try {
|
|
5705
|
-
let source;
|
|
5706
|
-
let uploadMetadata;
|
|
5707
|
-
if (cfg?.onUpload) {
|
|
5708
|
-
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
5709
|
-
source = uploadSource;
|
|
5710
|
-
uploadMetadata = meta;
|
|
5711
|
-
} else source = {
|
|
5712
|
-
type: "data",
|
|
5713
|
-
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
5714
|
-
mimeType: file.type
|
|
5715
|
-
};
|
|
5716
|
-
let thumbnail;
|
|
5717
|
-
if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
5718
|
-
setAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
|
|
5719
|
-
...att,
|
|
5720
|
-
source,
|
|
5721
|
-
status: "ready",
|
|
5722
|
-
thumbnail,
|
|
5723
|
-
metadata: uploadMetadata
|
|
5724
|
-
} : att));
|
|
5725
|
-
} catch (error) {
|
|
5726
|
-
setAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
|
|
5727
|
-
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
5728
|
-
cfg?.onUploadFailed?.({
|
|
5729
|
-
reason: "upload-failed",
|
|
5730
|
-
file,
|
|
5731
|
-
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
5732
|
-
});
|
|
5733
|
-
}
|
|
5748
|
+
queued.push({
|
|
5749
|
+
file,
|
|
5750
|
+
placeholder: {
|
|
5751
|
+
id: (0, _copilotkit_shared.randomUUID)(),
|
|
5752
|
+
type: (0, _copilotkit_shared.getModalityFromMimeType)(file.type),
|
|
5753
|
+
source: {
|
|
5754
|
+
type: "data",
|
|
5755
|
+
value: "",
|
|
5756
|
+
mimeType: file.type
|
|
5757
|
+
},
|
|
5758
|
+
filename: file.name,
|
|
5759
|
+
size: file.size,
|
|
5760
|
+
status: "uploading"
|
|
5761
|
+
}
|
|
5762
|
+
});
|
|
5734
5763
|
}
|
|
5735
|
-
|
|
5764
|
+
if (queued.length === 0) return;
|
|
5765
|
+
setAttachments((prev) => [...prev, ...queued.map((q) => q.placeholder)]);
|
|
5766
|
+
const settled = queued.map(({ file, placeholder }) => new Promise((resolve) => {
|
|
5767
|
+
uploadQueueRef.current.push({
|
|
5768
|
+
file,
|
|
5769
|
+
placeholder,
|
|
5770
|
+
cfg,
|
|
5771
|
+
settle: resolve
|
|
5772
|
+
});
|
|
5773
|
+
}));
|
|
5774
|
+
const limit = resolveMaxConcurrentUploads(cfg?.maxConcurrentUploads);
|
|
5775
|
+
const toSpawn = Math.min(uploadQueueRef.current.length, Math.max(0, limit - activeWorkersRef.current));
|
|
5776
|
+
for (let i = 0; i < toSpawn; i++) drainUploadQueue();
|
|
5777
|
+
await Promise.all(settled);
|
|
5778
|
+
}, [drainUploadQueue]);
|
|
5736
5779
|
const handleFileUpload = (0, react.useCallback)(async (e) => {
|
|
5737
5780
|
if (!e.target.files?.length) return;
|
|
5738
5781
|
try {
|
|
@@ -5844,9 +5887,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5844
5887
|
* }
|
|
5845
5888
|
* ```
|
|
5846
5889
|
*
|
|
5847
|
-
* @deprecated
|
|
5848
|
-
*
|
|
5849
|
-
*
|
|
5890
|
+
* @deprecated This hook supports only the legacy plural-container annotation.
|
|
5891
|
+
* Configure `getLearningContainerId` on `CopilotKitIntelligence` for new
|
|
5892
|
+
* Intelligence runtimes.
|
|
5850
5893
|
*/
|
|
5851
5894
|
function useLearningContainers({ threadId, learningContainers }) {
|
|
5852
5895
|
const { copilotkit } = useCopilotKit();
|
|
@@ -5860,8 +5903,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5860
5903
|
const warnedMissingUrlRef = (0, react.useRef)(false);
|
|
5861
5904
|
const runtimeUrlRef = (0, react.useRef)(copilotkit.runtimeUrl);
|
|
5862
5905
|
const headersRef = (0, react.useRef)(copilotkit.headers ?? {});
|
|
5906
|
+
const runtimeFetchRef = (0, react.useRef)(copilotkit.ɵruntimeFetch);
|
|
5863
5907
|
runtimeUrlRef.current = copilotkit.runtimeUrl;
|
|
5864
5908
|
headersRef.current = copilotkit.headers ?? {};
|
|
5909
|
+
runtimeFetchRef.current = copilotkit.ɵruntimeFetch;
|
|
5865
5910
|
const key = JSON.stringify(learningContainers);
|
|
5866
5911
|
const defaultKey = JSON.stringify(DEFAULT_CONTAINERS);
|
|
5867
5912
|
(0, react.useEffect)(() => {
|
|
@@ -5881,6 +5926,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5881
5926
|
return;
|
|
5882
5927
|
}
|
|
5883
5928
|
recordAnnotation({
|
|
5929
|
+
fetch: copilotkit.ɵruntimeFetch,
|
|
5884
5930
|
runtimeUrl,
|
|
5885
5931
|
headers,
|
|
5886
5932
|
type: "set_learning_containers",
|
|
@@ -5908,6 +5954,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5908
5954
|
const capturedRuntimeUrl = runtimeUrlRef.current;
|
|
5909
5955
|
const capturedHeaders = headersRef.current;
|
|
5910
5956
|
if (capturedRuntimeUrl) recordAnnotation({
|
|
5957
|
+
fetch: runtimeFetchRef.current,
|
|
5911
5958
|
runtimeUrl: capturedRuntimeUrl,
|
|
5912
5959
|
headers: capturedHeaders,
|
|
5913
5960
|
type: "set_learning_containers",
|
|
@@ -5950,9 +5997,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5950
5997
|
* }
|
|
5951
5998
|
* ```
|
|
5952
5999
|
*
|
|
5953
|
-
* @deprecated
|
|
5954
|
-
*
|
|
5955
|
-
*
|
|
6000
|
+
* @deprecated This hook supports only the legacy plural-container annotation.
|
|
6001
|
+
* Configure `getLearningContainerId` on `CopilotKitIntelligence` for new
|
|
6002
|
+
* Intelligence runtimes.
|
|
5956
6003
|
*/
|
|
5957
6004
|
function useLearningContainersInCurrentThread({ learningContainers }) {
|
|
5958
6005
|
const threadId = useCopilotChatConfiguration()?.threadId;
|
|
@@ -9170,6 +9217,41 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9170
9217
|
});
|
|
9171
9218
|
CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
|
|
9172
9219
|
|
|
9220
|
+
//#endregion
|
|
9221
|
+
//#region src/v2/components/chat/modal-open-control.tsx
|
|
9222
|
+
const ModalOpenControlContext = (0, react.createContext)({});
|
|
9223
|
+
/**
|
|
9224
|
+
* Carries `open` / `onOpenChange` from a prebuilt surface down to the view that
|
|
9225
|
+
* owns the modal state.
|
|
9226
|
+
*
|
|
9227
|
+
* A context is required rather than plain props because `<CopilotSidebar>`
|
|
9228
|
+
* hands its view to `<CopilotChat>` as a `chatView` **component**. Threading a
|
|
9229
|
+
* value that changes (like `open`) through that component's identity would mint
|
|
9230
|
+
* a new element type on every toggle, and React unmounts and remounts the whole
|
|
9231
|
+
* chat subtree when the element type changes. That is the remount class of bug
|
|
9232
|
+
* already fixed for `<CopilotPopup>` on resize. Context keeps the override
|
|
9233
|
+
* identity stable while still re-rendering the view when `open` changes.
|
|
9234
|
+
*/
|
|
9235
|
+
function ModalOpenControlProvider({ open, onOpenChange, children }) {
|
|
9236
|
+
const value = (0, react.useMemo)(() => ({
|
|
9237
|
+
open,
|
|
9238
|
+
onOpenChange
|
|
9239
|
+
}), [open, onOpenChange]);
|
|
9240
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlContext.Provider, {
|
|
9241
|
+
value,
|
|
9242
|
+
children
|
|
9243
|
+
});
|
|
9244
|
+
}
|
|
9245
|
+
/**
|
|
9246
|
+
* Reads the controlled open state supplied by the surrounding prebuilt
|
|
9247
|
+
* surface. Returns an empty control (uncontrolled) when there is none.
|
|
9248
|
+
*
|
|
9249
|
+
* @returns The host's `open` / `onOpenChange` pair.
|
|
9250
|
+
*/
|
|
9251
|
+
function useModalOpenControl() {
|
|
9252
|
+
return (0, react.useContext)(ModalOpenControlContext);
|
|
9253
|
+
}
|
|
9254
|
+
|
|
9173
9255
|
//#endregion
|
|
9174
9256
|
//#region src/v2/components/chat/CopilotModalHeader.tsx
|
|
9175
9257
|
/**
|
|
@@ -9279,15 +9361,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9279
9361
|
const DEFAULT_SIDEBAR_WIDTH = 480;
|
|
9280
9362
|
const SIDEBAR_TRANSITION_MS = 260;
|
|
9281
9363
|
function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, position = "right", ...props }) {
|
|
9364
|
+
const { open, onOpenChange } = useModalOpenControl();
|
|
9365
|
+
const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
|
|
9366
|
+
const internal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotSidebarViewInternal, {
|
|
9367
|
+
header,
|
|
9368
|
+
toggleButton,
|
|
9369
|
+
width,
|
|
9370
|
+
position,
|
|
9371
|
+
...props
|
|
9372
|
+
});
|
|
9282
9373
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
9283
|
-
isModalDefaultOpen: defaultOpen,
|
|
9284
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
...props
|
|
9290
|
-
})
|
|
9374
|
+
isModalDefaultOpen: open ?? defaultOpen,
|
|
9375
|
+
children: hasOpenControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlledModalOpenScope, {
|
|
9376
|
+
open,
|
|
9377
|
+
onOpenChange,
|
|
9378
|
+
children: internal
|
|
9379
|
+
}) : internal
|
|
9291
9380
|
});
|
|
9292
9381
|
}
|
|
9293
9382
|
function CopilotSidebarViewInternal({ header, toggleButton, width, position = "right", ...props }) {
|
|
@@ -9351,7 +9440,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9351
9440
|
"data-position": position,
|
|
9352
9441
|
className: cn("copilotKitSidebar copilotKitWindow", "cpk:fixed cpk:top-0 cpk:z-[1200] cpk:flex", position === "left" ? "cpk:left-0" : "cpk:right-0", "cpk:h-[100vh] cpk:h-[100dvh] cpk:max-h-screen", "cpk:w-full", position === "left" ? "cpk:border-r" : "cpk:border-l", "cpk:border-border cpk:bg-background cpk:text-foreground cpk:shadow-xl", "cpk:transition-transform cpk:duration-300 cpk:ease-out", isSidebarOpen ? "cpk:translate-x-0" : position === "left" ? "cpk:-translate-x-full cpk:pointer-events-none" : "cpk:translate-x-full cpk:pointer-events-none"),
|
|
9353
9442
|
style: {
|
|
9354
|
-
|
|
9443
|
+
"--sidebar-width": widthToCss(sidebarWidth),
|
|
9355
9444
|
paddingTop: "env(safe-area-inset-top)",
|
|
9356
9445
|
paddingBottom: "env(safe-area-inset-bottom)"
|
|
9357
9446
|
},
|
|
@@ -9413,17 +9502,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9413
9502
|
return `${fallback}px`;
|
|
9414
9503
|
};
|
|
9415
9504
|
function CopilotPopupView({ header, toggleButton, width, height, clickOutsideToClose, defaultOpen = true, className, ...restProps }) {
|
|
9505
|
+
const { open, onOpenChange } = useModalOpenControl();
|
|
9506
|
+
const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
|
|
9507
|
+
const internal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotPopupViewInternal, {
|
|
9508
|
+
header,
|
|
9509
|
+
toggleButton,
|
|
9510
|
+
width,
|
|
9511
|
+
height,
|
|
9512
|
+
clickOutsideToClose,
|
|
9513
|
+
className,
|
|
9514
|
+
...restProps
|
|
9515
|
+
});
|
|
9416
9516
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
9417
|
-
isModalDefaultOpen: defaultOpen,
|
|
9418
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
clickOutsideToClose,
|
|
9424
|
-
className,
|
|
9425
|
-
...restProps
|
|
9426
|
-
})
|
|
9517
|
+
isModalDefaultOpen: open ?? defaultOpen,
|
|
9518
|
+
children: hasOpenControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlledModalOpenScope, {
|
|
9519
|
+
open,
|
|
9520
|
+
onOpenChange,
|
|
9521
|
+
children: internal
|
|
9522
|
+
}) : internal
|
|
9427
9523
|
});
|
|
9428
9524
|
}
|
|
9429
9525
|
function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOutsideToClose, className, ...restProps }) {
|
|
@@ -9556,7 +9652,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9556
9652
|
|
|
9557
9653
|
//#endregion
|
|
9558
9654
|
//#region src/v2/components/chat/CopilotSidebar.tsx
|
|
9559
|
-
function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ...chatProps }) {
|
|
9655
|
+
function CopilotSidebar({ header, toggleButton, defaultOpen, open, onOpenChange, width, position, ...chatProps }) {
|
|
9560
9656
|
const { checkFeature } = useLicenseContext();
|
|
9561
9657
|
const isSidebarLicensed = checkFeature("sidebar");
|
|
9562
9658
|
(0, react.useEffect)(() => {
|
|
@@ -9582,11 +9678,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9582
9678
|
defaultOpen,
|
|
9583
9679
|
position
|
|
9584
9680
|
]);
|
|
9585
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!isSidebarLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9681
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!isSidebarLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlProvider, {
|
|
9682
|
+
open,
|
|
9683
|
+
onOpenChange,
|
|
9684
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
|
|
9685
|
+
welcomeScreen: CopilotSidebarView.WelcomeScreen,
|
|
9686
|
+
...chatProps,
|
|
9687
|
+
isModalDefaultOpen: defaultOpen,
|
|
9688
|
+
chatView: SidebarViewOverride
|
|
9689
|
+
})
|
|
9590
9690
|
})] });
|
|
9591
9691
|
}
|
|
9592
9692
|
CopilotSidebar.displayName = "CopilotSidebar";
|
|
@@ -9608,7 +9708,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9608
9708
|
});
|
|
9609
9709
|
};
|
|
9610
9710
|
const PopupViewOverrideWithStatics = Object.assign(PopupViewOverride, CopilotChatView_default);
|
|
9611
|
-
function CopilotPopup({ header, toggleButton, defaultOpen, width, height, clickOutsideToClose, ...chatProps }) {
|
|
9711
|
+
function CopilotPopup({ header, toggleButton, defaultOpen, open, onOpenChange, width, height, clickOutsideToClose, ...chatProps }) {
|
|
9612
9712
|
const { checkFeature } = useLicenseContext();
|
|
9613
9713
|
const isPopupLicensed = checkFeature("popup");
|
|
9614
9714
|
(0, react.useEffect)(() => {
|
|
@@ -9631,11 +9731,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9631
9731
|
]);
|
|
9632
9732
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!isPopupLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Popup" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PopupShellPropsContext.Provider, {
|
|
9633
9733
|
value: shellProps,
|
|
9634
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9734
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlProvider, {
|
|
9735
|
+
open,
|
|
9736
|
+
onOpenChange,
|
|
9737
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
|
|
9738
|
+
welcomeScreen: CopilotPopupView_default.WelcomeScreen,
|
|
9739
|
+
...chatProps,
|
|
9740
|
+
isModalDefaultOpen: defaultOpen,
|
|
9741
|
+
chatView: PopupViewOverrideWithStatics
|
|
9742
|
+
})
|
|
9639
9743
|
})
|
|
9640
9744
|
})] });
|
|
9641
9745
|
}
|
|
@@ -10952,7 +11056,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
10952
11056
|
switch (error.code) {
|
|
10953
11057
|
case _copilotkit_shared.CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR: return { primary: {
|
|
10954
11058
|
label: "Show me how",
|
|
10955
|
-
onClick: () => window.open("https://docs.copilotkit.ai/
|
|
11059
|
+
onClick: () => window.open("https://docs.copilotkit.ai/intelligence/overview#plans-and-access", "_blank", "noopener,noreferrer")
|
|
10956
11060
|
} };
|
|
10957
11061
|
case _copilotkit_shared.CopilotKitErrorCode.UPGRADE_REQUIRED_ERROR: return { primary: {
|
|
10958
11062
|
label: "Upgrade",
|