@copilotkit/react-core 1.57.0-canary.1778229181 → 1.57.1-canary.1778272612
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-N0YiBG5S.mjs → copilotkit-3XTEoVQO.mjs} +1917 -1754
- package/dist/copilotkit-3XTEoVQO.mjs.map +1 -0
- package/dist/{copilotkit-BYnbIBN5.d.mts → copilotkit-BCJ2yvV6.d.mts} +64 -6
- package/dist/copilotkit-BCJ2yvV6.d.mts.map +1 -0
- package/dist/{copilotkit-vx_R9p-O.d.cts → copilotkit-CBbSvze0.d.cts} +64 -6
- package/dist/copilotkit-CBbSvze0.d.cts.map +1 -0
- package/dist/{copilotkit-BLlkMAjx.cjs → copilotkit-Dnj9pi4m.cjs} +1705 -1536
- package/dist/copilotkit-Dnj9pi4m.cjs.map +1 -0
- package/dist/index.cjs +2 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -5
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +310 -194
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/headless.cjs +6 -48
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts +0 -2
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts +0 -2
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +6 -48
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +2 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +1101 -926
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +5 -6
- package/src/hooks/use-copilot-chat_internal.ts +0 -1
- package/src/v2/components/MCPAppsActivityRenderer.tsx +3 -9
- package/src/v2/components/chat/CopilotChat.tsx +2 -1
- package/src/v2/components/chat/CopilotChatMessageView.tsx +24 -9
- package/src/v2/components/chat/CopilotChatView.tsx +2 -2
- package/src/v2/components/chat/CopilotSidebar.tsx +5 -1
- package/src/v2/components/chat/CopilotSidebarView.tsx +24 -10
- package/src/v2/components/chat/__tests__/CopilotChat.welcomeGate.test.tsx +1 -3
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +29 -25
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.tsx +159 -0
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +0 -102
- package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.tsx +5 -60
- package/src/v2/components/index.ts +1 -0
- package/src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx +286 -0
- package/src/v2/components/intelligence-indicator/__tests__/IntelligenceIndicator.e2e.test.tsx +464 -0
- package/src/v2/components/intelligence-indicator/index.ts +2 -0
- package/src/v2/hooks/use-agent.tsx +7 -116
- package/src/v2/hooks/use-default-render-tool.tsx +18 -1
- package/src/v2/hooks/use-render-activity-message.tsx +3 -11
- package/src/v2/hooks/use-render-custom-messages.tsx +1 -6
- package/src/v2/hooks/use-render-tool-call.tsx +35 -5
- package/src/v2/styles/globals.css +118 -0
- package/dist/copilotkit-BLlkMAjx.cjs.map +0 -1
- package/dist/copilotkit-BYnbIBN5.d.mts.map +0 -1
- package/dist/copilotkit-N0YiBG5S.mjs.map +0 -1
- package/dist/copilotkit-vx_R9p-O.d.cts.map +0 -1
- package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +0 -333
|
@@ -1416,1167 +1416,1462 @@ const LicenseContext = createContext({
|
|
|
1416
1416
|
const useLicenseContext = () => useContext(LicenseContext);
|
|
1417
1417
|
|
|
1418
1418
|
//#endregion
|
|
1419
|
-
//#region src/v2/
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
result: toolMessage.content
|
|
1434
|
-
});
|
|
1435
|
-
else if (isExecuting) return /* @__PURE__ */ jsx(RenderComponent, {
|
|
1436
|
-
name: toolName,
|
|
1437
|
-
toolCallId: toolCall.id,
|
|
1438
|
-
args,
|
|
1439
|
-
status: ToolCallStatus.Executing,
|
|
1440
|
-
result: void 0
|
|
1441
|
-
});
|
|
1442
|
-
else return /* @__PURE__ */ jsx(RenderComponent, {
|
|
1443
|
-
name: toolName,
|
|
1444
|
-
toolCallId: toolCall.id,
|
|
1445
|
-
args,
|
|
1446
|
-
status: ToolCallStatus.InProgress,
|
|
1447
|
-
result: void 0
|
|
1448
|
-
});
|
|
1449
|
-
}, (prevProps, nextProps) => {
|
|
1450
|
-
if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
|
|
1451
|
-
if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
|
|
1452
|
-
if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
|
|
1453
|
-
if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
|
|
1454
|
-
if (prevProps.isExecuting !== nextProps.isExecuting) return false;
|
|
1455
|
-
if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
|
|
1456
|
-
return true;
|
|
1457
|
-
});
|
|
1419
|
+
//#region src/v2/types/defineToolCallRenderer.ts
|
|
1420
|
+
function defineToolCallRenderer(def) {
|
|
1421
|
+
const argsSchema = def.name === "*" && !def.args ? z.any() : def.args;
|
|
1422
|
+
return {
|
|
1423
|
+
name: def.name,
|
|
1424
|
+
args: argsSchema,
|
|
1425
|
+
render: def.render,
|
|
1426
|
+
...def.agentId ? { agentId: def.agentId } : {}
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/v2/hooks/use-render-tool.tsx
|
|
1432
|
+
const EMPTY_DEPS$1 = [];
|
|
1458
1433
|
/**
|
|
1459
|
-
*
|
|
1460
|
-
* defined in CopilotKitProvider.
|
|
1434
|
+
* Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
|
|
1461
1435
|
*
|
|
1462
|
-
*
|
|
1436
|
+
* Key behavior:
|
|
1437
|
+
* - deduplicates by `agentId:name` (latest registration wins),
|
|
1438
|
+
* - keeps renderer entries on cleanup so historical chat tool calls can still render,
|
|
1439
|
+
* - refreshes registration when `deps` change.
|
|
1440
|
+
*
|
|
1441
|
+
* @typeParam S - Schema type describing tool call parameters.
|
|
1442
|
+
* @param config - Renderer config for wildcard or named tools.
|
|
1443
|
+
* @param deps - Optional dependencies to refresh registration.
|
|
1444
|
+
*
|
|
1445
|
+
* @example
|
|
1446
|
+
* ```tsx
|
|
1447
|
+
* useRenderTool(
|
|
1448
|
+
* {
|
|
1449
|
+
* name: "searchDocs",
|
|
1450
|
+
* parameters: z.object({ query: z.string() }),
|
|
1451
|
+
* render: ({ status, parameters, result }) => {
|
|
1452
|
+
* if (status === "executing") return <div>Searching {parameters.query}</div>;
|
|
1453
|
+
* if (status === "complete") return <div>{result}</div>;
|
|
1454
|
+
* return <div>Preparing...</div>;
|
|
1455
|
+
* },
|
|
1456
|
+
* },
|
|
1457
|
+
* [],
|
|
1458
|
+
* );
|
|
1459
|
+
* ```
|
|
1460
|
+
*
|
|
1461
|
+
* @example
|
|
1462
|
+
* ```tsx
|
|
1463
|
+
* useRenderTool(
|
|
1464
|
+
* {
|
|
1465
|
+
* name: "summarize",
|
|
1466
|
+
* parameters: z.object({ text: z.string() }),
|
|
1467
|
+
* agentId: "research-agent",
|
|
1468
|
+
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
1469
|
+
* },
|
|
1470
|
+
* [selectedAgentId],
|
|
1471
|
+
* );
|
|
1472
|
+
* ```
|
|
1463
1473
|
*/
|
|
1464
|
-
function
|
|
1465
|
-
const { copilotkit
|
|
1466
|
-
const
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1474
|
+
function useRenderTool(config, deps) {
|
|
1475
|
+
const { copilotkit } = useCopilotKit();
|
|
1476
|
+
const extraDeps = deps ?? EMPTY_DEPS$1;
|
|
1477
|
+
useEffect(() => {
|
|
1478
|
+
const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
|
|
1479
|
+
name: "*",
|
|
1480
|
+
render: (props) => config.render({
|
|
1481
|
+
...props,
|
|
1482
|
+
parameters: props.args
|
|
1483
|
+
}),
|
|
1484
|
+
...config.agentId ? { agentId: config.agentId } : {}
|
|
1485
|
+
}) : defineToolCallRenderer({
|
|
1486
|
+
name: config.name,
|
|
1487
|
+
args: config.parameters,
|
|
1488
|
+
render: (props) => config.render({
|
|
1489
|
+
...props,
|
|
1490
|
+
parameters: props.args
|
|
1491
|
+
}),
|
|
1492
|
+
...config.agentId ? { agentId: config.agentId } : {}
|
|
1493
|
+
});
|
|
1494
|
+
copilotkit.addHookRenderToolCall(renderer);
|
|
1481
1495
|
}, [
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1496
|
+
config.name,
|
|
1497
|
+
copilotkit,
|
|
1498
|
+
JSON.stringify(extraDeps)
|
|
1485
1499
|
]);
|
|
1486
1500
|
}
|
|
1487
1501
|
|
|
1488
1502
|
//#endregion
|
|
1489
|
-
//#region src/v2/
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
fontSize: "13px",
|
|
1532
|
-
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
1533
|
-
borderRadius: "6px",
|
|
1534
|
-
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)"
|
|
1535
|
-
},
|
|
1536
|
-
info: {
|
|
1537
|
-
backgroundColor: "#eff6ff",
|
|
1538
|
-
border: "1px solid #93c5fd",
|
|
1539
|
-
color: "#1e40af"
|
|
1540
|
-
},
|
|
1541
|
-
warning: {
|
|
1542
|
-
backgroundColor: "#fffbeb",
|
|
1543
|
-
border: "1px solid #fbbf24",
|
|
1544
|
-
color: "#92400e"
|
|
1545
|
-
},
|
|
1546
|
-
critical: {
|
|
1547
|
-
backgroundColor: "#fef2f2",
|
|
1548
|
-
border: "1px solid #fca5a5",
|
|
1549
|
-
color: "#991b1b"
|
|
1550
|
-
}
|
|
1551
|
-
};
|
|
1552
|
-
function getSeverityStyle(severity) {
|
|
1553
|
-
switch (severity) {
|
|
1554
|
-
case "warning": return BANNER_STYLES.warning;
|
|
1555
|
-
case "critical": return BANNER_STYLES.critical;
|
|
1556
|
-
default: return BANNER_STYLES.info;
|
|
1557
|
-
}
|
|
1503
|
+
//#region src/v2/hooks/use-default-render-tool.tsx
|
|
1504
|
+
/**
|
|
1505
|
+
* Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
|
|
1506
|
+
*
|
|
1507
|
+
* - Call with no config to use CopilotKit's built-in default tool-call card.
|
|
1508
|
+
* - Pass `config.render` to replace the default UI with your own fallback renderer.
|
|
1509
|
+
*
|
|
1510
|
+
* This is useful when you want a generic renderer for tools that do not have a
|
|
1511
|
+
* dedicated `useRenderTool({ name: "..." })` registration.
|
|
1512
|
+
*
|
|
1513
|
+
* @param config - Optional custom wildcard render function.
|
|
1514
|
+
* @param deps - Optional dependencies to refresh registration.
|
|
1515
|
+
*
|
|
1516
|
+
* @example
|
|
1517
|
+
* ```tsx
|
|
1518
|
+
* useDefaultRenderTool();
|
|
1519
|
+
* ```
|
|
1520
|
+
*
|
|
1521
|
+
* @example
|
|
1522
|
+
* ```tsx
|
|
1523
|
+
* useDefaultRenderTool({
|
|
1524
|
+
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
1525
|
+
* });
|
|
1526
|
+
* ```
|
|
1527
|
+
*
|
|
1528
|
+
* @example
|
|
1529
|
+
* ```tsx
|
|
1530
|
+
* useDefaultRenderTool(
|
|
1531
|
+
* {
|
|
1532
|
+
* render: ({ name, result }) => (
|
|
1533
|
+
* <ToolEventRow title={name} payload={result} compact={compactMode} />
|
|
1534
|
+
* ),
|
|
1535
|
+
* },
|
|
1536
|
+
* [compactMode],
|
|
1537
|
+
* );
|
|
1538
|
+
* ```
|
|
1539
|
+
*/
|
|
1540
|
+
function useDefaultRenderTool(config, deps) {
|
|
1541
|
+
useRenderTool({
|
|
1542
|
+
name: "*",
|
|
1543
|
+
render: config?.render ?? DefaultToolCallRenderer
|
|
1544
|
+
}, deps);
|
|
1558
1545
|
}
|
|
1559
|
-
function
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
return /* @__PURE__ */
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1546
|
+
function DefaultToolCallRenderer({ name, parameters, status, result }) {
|
|
1547
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
1548
|
+
const statusString = String(status);
|
|
1549
|
+
const isActive = statusString === "inProgress" || statusString === "executing";
|
|
1550
|
+
const isComplete = statusString === "complete";
|
|
1551
|
+
const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
|
|
1552
|
+
const dotColor = isActive ? "#f59e0b" : isComplete ? "#10b981" : "#a1a1aa";
|
|
1553
|
+
const badgeBg = isActive ? "#fef3c7" : isComplete ? "#d1fae5" : "#f4f4f5";
|
|
1554
|
+
const badgeColor = isActive ? "#92400e" : isComplete ? "#065f46" : "#3f3f46";
|
|
1555
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1556
|
+
"data-testid": "copilot-tool-render",
|
|
1557
|
+
"data-tool-name": name,
|
|
1558
|
+
"data-status": statusString,
|
|
1559
|
+
"data-args": safeStringifyForAttr(parameters),
|
|
1560
|
+
"data-result": safeStringifyForAttr(result),
|
|
1561
|
+
style: {
|
|
1562
|
+
marginTop: "8px",
|
|
1563
|
+
paddingBottom: "8px"
|
|
1572
1564
|
},
|
|
1573
|
-
children:
|
|
1565
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1574
1566
|
style: {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1567
|
+
borderRadius: "12px",
|
|
1568
|
+
border: "1px solid #e4e4e7",
|
|
1569
|
+
backgroundColor: "#fafafa",
|
|
1570
|
+
padding: "14px 16px"
|
|
1578
1571
|
},
|
|
1579
|
-
children: [/* @__PURE__ */
|
|
1580
|
-
|
|
1581
|
-
target: "_blank",
|
|
1582
|
-
rel: "noopener noreferrer",
|
|
1572
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1573
|
+
onClick: () => setIsExpanded(!isExpanded),
|
|
1583
1574
|
style: {
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1575
|
+
display: "flex",
|
|
1576
|
+
alignItems: "center",
|
|
1577
|
+
justifyContent: "space-between",
|
|
1578
|
+
gap: "10px",
|
|
1579
|
+
cursor: "pointer",
|
|
1580
|
+
userSelect: "none"
|
|
1587
1581
|
},
|
|
1588
|
-
children:
|
|
1589
|
-
|
|
1590
|
-
|
|
1582
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1583
|
+
style: {
|
|
1584
|
+
display: "flex",
|
|
1585
|
+
alignItems: "center",
|
|
1586
|
+
gap: "8px",
|
|
1587
|
+
minWidth: 0
|
|
1588
|
+
},
|
|
1589
|
+
children: [
|
|
1590
|
+
/* @__PURE__ */ jsx("svg", {
|
|
1591
|
+
style: {
|
|
1592
|
+
height: "14px",
|
|
1593
|
+
width: "14px",
|
|
1594
|
+
color: "#71717a",
|
|
1595
|
+
transition: "transform 0.15s",
|
|
1596
|
+
transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
|
|
1597
|
+
flexShrink: 0
|
|
1598
|
+
},
|
|
1599
|
+
fill: "none",
|
|
1600
|
+
viewBox: "0 0 24 24",
|
|
1601
|
+
strokeWidth: 2,
|
|
1602
|
+
stroke: "currentColor",
|
|
1603
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
1604
|
+
strokeLinecap: "round",
|
|
1605
|
+
strokeLinejoin: "round",
|
|
1606
|
+
d: "M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
1607
|
+
})
|
|
1608
|
+
}),
|
|
1609
|
+
/* @__PURE__ */ jsx("span", { style: {
|
|
1610
|
+
display: "inline-block",
|
|
1611
|
+
height: "8px",
|
|
1612
|
+
width: "8px",
|
|
1613
|
+
borderRadius: "50%",
|
|
1614
|
+
backgroundColor: dotColor,
|
|
1615
|
+
flexShrink: 0
|
|
1616
|
+
} }),
|
|
1617
|
+
/* @__PURE__ */ jsx("span", {
|
|
1618
|
+
"data-testid": "copilot-tool-render-name",
|
|
1619
|
+
style: {
|
|
1620
|
+
fontSize: "13px",
|
|
1621
|
+
fontWeight: 600,
|
|
1622
|
+
color: "#18181b",
|
|
1623
|
+
overflow: "hidden",
|
|
1624
|
+
textOverflow: "ellipsis",
|
|
1625
|
+
whiteSpace: "nowrap"
|
|
1626
|
+
},
|
|
1627
|
+
children: name
|
|
1628
|
+
})
|
|
1629
|
+
]
|
|
1630
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1631
|
+
"data-testid": "copilot-tool-render-status",
|
|
1632
|
+
style: {
|
|
1633
|
+
display: "inline-flex",
|
|
1634
|
+
alignItems: "center",
|
|
1635
|
+
borderRadius: "9999px",
|
|
1636
|
+
padding: "2px 8px",
|
|
1637
|
+
fontSize: "11px",
|
|
1638
|
+
fontWeight: 500,
|
|
1639
|
+
backgroundColor: badgeBg,
|
|
1640
|
+
color: badgeColor,
|
|
1641
|
+
flexShrink: 0
|
|
1642
|
+
},
|
|
1643
|
+
children: statusLabel
|
|
1644
|
+
})]
|
|
1645
|
+
}), isExpanded && /* @__PURE__ */ jsxs("div", {
|
|
1591
1646
|
style: {
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
color: "inherit",
|
|
1596
|
-
fontSize: "16px"
|
|
1647
|
+
marginTop: "12px",
|
|
1648
|
+
display: "grid",
|
|
1649
|
+
gap: "12px"
|
|
1597
1650
|
},
|
|
1598
|
-
children: "
|
|
1651
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
1652
|
+
style: {
|
|
1653
|
+
fontSize: "10px",
|
|
1654
|
+
textTransform: "uppercase",
|
|
1655
|
+
letterSpacing: "0.05em",
|
|
1656
|
+
color: "#71717a"
|
|
1657
|
+
},
|
|
1658
|
+
children: "Arguments"
|
|
1659
|
+
}), /* @__PURE__ */ jsx("pre", {
|
|
1660
|
+
style: {
|
|
1661
|
+
marginTop: "6px",
|
|
1662
|
+
maxHeight: "200px",
|
|
1663
|
+
overflow: "auto",
|
|
1664
|
+
borderRadius: "6px",
|
|
1665
|
+
backgroundColor: "#f4f4f5",
|
|
1666
|
+
padding: "10px",
|
|
1667
|
+
fontSize: "11px",
|
|
1668
|
+
lineHeight: 1.6,
|
|
1669
|
+
color: "#27272a",
|
|
1670
|
+
whiteSpace: "pre-wrap",
|
|
1671
|
+
wordBreak: "break-word"
|
|
1672
|
+
},
|
|
1673
|
+
children: JSON.stringify(parameters ?? {}, null, 2)
|
|
1674
|
+
})] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
1675
|
+
style: {
|
|
1676
|
+
fontSize: "10px",
|
|
1677
|
+
textTransform: "uppercase",
|
|
1678
|
+
letterSpacing: "0.05em",
|
|
1679
|
+
color: "#71717a"
|
|
1680
|
+
},
|
|
1681
|
+
children: "Result"
|
|
1682
|
+
}), /* @__PURE__ */ jsx("pre", {
|
|
1683
|
+
style: {
|
|
1684
|
+
marginTop: "6px",
|
|
1685
|
+
maxHeight: "200px",
|
|
1686
|
+
overflow: "auto",
|
|
1687
|
+
borderRadius: "6px",
|
|
1688
|
+
backgroundColor: "#f4f4f5",
|
|
1689
|
+
padding: "10px",
|
|
1690
|
+
fontSize: "11px",
|
|
1691
|
+
lineHeight: 1.6,
|
|
1692
|
+
color: "#27272a",
|
|
1693
|
+
whiteSpace: "pre-wrap",
|
|
1694
|
+
wordBreak: "break-word"
|
|
1695
|
+
},
|
|
1696
|
+
children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
1697
|
+
})] })]
|
|
1599
1698
|
})]
|
|
1600
|
-
})
|
|
1699
|
+
})
|
|
1601
1700
|
});
|
|
1602
1701
|
}
|
|
1603
|
-
function
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
onDismiss
|
|
1611
|
-
});
|
|
1612
|
-
case "feature_unlicensed": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1613
|
-
severity: "warning",
|
|
1614
|
-
message: `⚠ The "${featureName}" feature requires a CopilotKit license.`,
|
|
1615
|
-
actionLabel: "Get a license",
|
|
1616
|
-
actionUrl: "https://copilotkit.ai/pricing",
|
|
1617
|
-
onDismiss
|
|
1618
|
-
});
|
|
1619
|
-
case "expiring": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1620
|
-
severity: "warning",
|
|
1621
|
-
message: `Your CopilotKit license expires in ${graceRemaining} day${graceRemaining !== 1 ? "s" : ""}. Please renew.`,
|
|
1622
|
-
actionLabel: "Renew",
|
|
1623
|
-
actionUrl: "https://cloud.copilotkit.ai",
|
|
1624
|
-
onDismiss
|
|
1625
|
-
});
|
|
1626
|
-
case "expired": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1627
|
-
severity: "critical",
|
|
1628
|
-
message: `Your CopilotKit license expired${expiryDate ? ` on ${expiryDate}` : ""}. Please renew at copilotkit.ai/pricing`,
|
|
1629
|
-
actionLabel: "Renew now",
|
|
1630
|
-
actionUrl: "https://copilotkit.ai/pricing",
|
|
1631
|
-
onDismiss
|
|
1632
|
-
});
|
|
1633
|
-
case "invalid": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1634
|
-
severity: "critical",
|
|
1635
|
-
message: "Invalid CopilotKit license token. Please check your configuration.",
|
|
1636
|
-
actionLabel: "Get a license",
|
|
1637
|
-
actionUrl: "https://copilotkit.ai/pricing",
|
|
1638
|
-
onDismiss
|
|
1639
|
-
});
|
|
1640
|
-
default: return null;
|
|
1702
|
+
function safeStringifyForAttr(value) {
|
|
1703
|
+
if (value === void 0 || value === null) return "";
|
|
1704
|
+
if (typeof value === "string") return value;
|
|
1705
|
+
try {
|
|
1706
|
+
return JSON.stringify(value);
|
|
1707
|
+
} catch {
|
|
1708
|
+
return String(value);
|
|
1641
1709
|
}
|
|
1642
1710
|
}
|
|
1643
|
-
function InlineFeatureWarning({ featureName }) {
|
|
1644
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1645
|
-
style: {
|
|
1646
|
-
padding: "8px 12px",
|
|
1647
|
-
backgroundColor: "#fffbeb",
|
|
1648
|
-
border: "1px solid #fbbf24",
|
|
1649
|
-
borderRadius: "6px",
|
|
1650
|
-
fontSize: "13px",
|
|
1651
|
-
color: "#92400e",
|
|
1652
|
-
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif"
|
|
1653
|
-
},
|
|
1654
|
-
children: [
|
|
1655
|
-
"⚠ The \"",
|
|
1656
|
-
featureName,
|
|
1657
|
-
"\" feature requires a CopilotKit license.",
|
|
1658
|
-
" ",
|
|
1659
|
-
/* @__PURE__ */ jsx("a", {
|
|
1660
|
-
href: "https://copilotkit.ai/pricing",
|
|
1661
|
-
target: "_blank",
|
|
1662
|
-
rel: "noopener noreferrer",
|
|
1663
|
-
style: {
|
|
1664
|
-
color: "#b45309",
|
|
1665
|
-
textDecoration: "underline"
|
|
1666
|
-
},
|
|
1667
|
-
children: "Get one at copilotkit.ai/pricing"
|
|
1668
|
-
})
|
|
1669
|
-
]
|
|
1670
|
-
});
|
|
1671
|
-
}
|
|
1672
1711
|
|
|
1673
1712
|
//#endregion
|
|
1674
|
-
//#region src/v2/
|
|
1675
|
-
const PROTOCOL_VERSION = "2025-06-18";
|
|
1676
|
-
function buildSandboxHTML(extraCspDomains) {
|
|
1677
|
-
const baseScriptSrc = "'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*";
|
|
1678
|
-
const baseFrameSrc = "* blob: data: http://localhost:* https://localhost:*";
|
|
1679
|
-
const extra = extraCspDomains?.length ? " " + extraCspDomains.join(" ") : "";
|
|
1680
|
-
return `<!doctype html>
|
|
1681
|
-
<html>
|
|
1682
|
-
<head>
|
|
1683
|
-
<meta charset="utf-8" />
|
|
1684
|
-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data: blob: 'unsafe-inline'; media-src * blob: data:; font-src * blob: data:; script-src ${baseScriptSrc + extra}; style-src * blob: data: 'unsafe-inline'; connect-src *; frame-src ${baseFrameSrc + extra}; base-uri 'self';" />
|
|
1685
|
-
<style>html,body{margin:0;padding:0;height:100%;width:100%;overflow:hidden}*{box-sizing:border-box}iframe{background-color:transparent;border:none;padding:0;overflow:hidden;width:100%;height:100%}</style>
|
|
1686
|
-
</head>
|
|
1687
|
-
<body>
|
|
1688
|
-
<script>
|
|
1689
|
-
if(window.self===window.top){throw new Error("This file must be used in an iframe.")}
|
|
1690
|
-
const inner=document.createElement("iframe");
|
|
1691
|
-
inner.style="width:100%;height:100%;border:none;";
|
|
1692
|
-
inner.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms");
|
|
1693
|
-
document.body.appendChild(inner);
|
|
1694
|
-
window.addEventListener("message",async(event)=>{
|
|
1695
|
-
if(event.source===window.parent){
|
|
1696
|
-
if(event.data&&event.data.method==="ui/notifications/sandbox-resource-ready"){
|
|
1697
|
-
const{html,sandbox}=event.data.params;
|
|
1698
|
-
if(typeof sandbox==="string")inner.setAttribute("sandbox",sandbox);
|
|
1699
|
-
if(typeof html==="string")inner.srcdoc=html;
|
|
1700
|
-
}else if(inner&&inner.contentWindow){
|
|
1701
|
-
inner.contentWindow.postMessage(event.data,"*");
|
|
1702
|
-
}
|
|
1703
|
-
}else if(event.source===inner.contentWindow){
|
|
1704
|
-
window.parent.postMessage(event.data,"*");
|
|
1705
|
-
}
|
|
1706
|
-
});
|
|
1707
|
-
window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-ready",params:{}},"*");
|
|
1708
|
-
<\/script>
|
|
1709
|
-
</body>
|
|
1710
|
-
</html>`;
|
|
1711
|
-
}
|
|
1712
|
-
/**
|
|
1713
|
-
* Queue for serializing MCP app requests to an agent.
|
|
1714
|
-
* Ensures requests wait for the agent to stop running and are processed one at a time.
|
|
1715
|
-
*/
|
|
1716
|
-
var MCPAppsRequestQueue = class {
|
|
1717
|
-
constructor() {
|
|
1718
|
-
this.queues = /* @__PURE__ */ new Map();
|
|
1719
|
-
this.processing = /* @__PURE__ */ new Map();
|
|
1720
|
-
}
|
|
1721
|
-
/**
|
|
1722
|
-
* Add a request to the queue for a specific agent thread.
|
|
1723
|
-
* Returns a promise that resolves when the request completes.
|
|
1724
|
-
*/
|
|
1725
|
-
async enqueue(agent, request) {
|
|
1726
|
-
const threadId = agent.threadId || "default";
|
|
1727
|
-
return new Promise((resolve, reject) => {
|
|
1728
|
-
let queue = this.queues.get(threadId);
|
|
1729
|
-
if (!queue) {
|
|
1730
|
-
queue = [];
|
|
1731
|
-
this.queues.set(threadId, queue);
|
|
1732
|
-
}
|
|
1733
|
-
queue.push({
|
|
1734
|
-
execute: request,
|
|
1735
|
-
resolve,
|
|
1736
|
-
reject
|
|
1737
|
-
});
|
|
1738
|
-
this.processQueue(threadId, agent);
|
|
1739
|
-
});
|
|
1740
|
-
}
|
|
1741
|
-
async processQueue(threadId, agent) {
|
|
1742
|
-
if (this.processing.get(threadId)) return;
|
|
1743
|
-
this.processing.set(threadId, true);
|
|
1744
|
-
try {
|
|
1745
|
-
const queue = this.queues.get(threadId);
|
|
1746
|
-
if (!queue) return;
|
|
1747
|
-
while (queue.length > 0) {
|
|
1748
|
-
const item = queue[0];
|
|
1749
|
-
try {
|
|
1750
|
-
await this.waitForAgentIdle(agent);
|
|
1751
|
-
const result = await item.execute();
|
|
1752
|
-
item.resolve(result);
|
|
1753
|
-
} catch (error) {
|
|
1754
|
-
item.reject(error instanceof Error ? error : new Error(String(error)));
|
|
1755
|
-
}
|
|
1756
|
-
queue.shift();
|
|
1757
|
-
}
|
|
1758
|
-
} finally {
|
|
1759
|
-
this.processing.set(threadId, false);
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
waitForAgentIdle(agent) {
|
|
1763
|
-
return new Promise((resolve) => {
|
|
1764
|
-
if (!agent.isRunning) {
|
|
1765
|
-
resolve();
|
|
1766
|
-
return;
|
|
1767
|
-
}
|
|
1768
|
-
let done = false;
|
|
1769
|
-
const finish = () => {
|
|
1770
|
-
if (done) return;
|
|
1771
|
-
done = true;
|
|
1772
|
-
clearInterval(checkInterval);
|
|
1773
|
-
sub.unsubscribe();
|
|
1774
|
-
resolve();
|
|
1775
|
-
};
|
|
1776
|
-
const sub = agent.subscribe({
|
|
1777
|
-
onRunFinalized: finish,
|
|
1778
|
-
onRunFailed: finish
|
|
1779
|
-
});
|
|
1780
|
-
const checkInterval = setInterval(() => {
|
|
1781
|
-
if (!agent.isRunning) finish();
|
|
1782
|
-
}, 500);
|
|
1783
|
-
});
|
|
1784
|
-
}
|
|
1785
|
-
};
|
|
1786
|
-
const mcpAppsRequestQueue = new MCPAppsRequestQueue();
|
|
1713
|
+
//#region src/v2/hooks/use-render-tool-call.tsx
|
|
1787
1714
|
/**
|
|
1788
|
-
*
|
|
1715
|
+
* Memoized component that renders a single tool call.
|
|
1716
|
+
* This prevents unnecessary re-renders when parent components update
|
|
1717
|
+
* but the tool call data hasn't changed.
|
|
1789
1718
|
*/
|
|
1790
|
-
const
|
|
1791
|
-
const
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1719
|
+
const ToolCallRenderer = React.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
|
|
1720
|
+
const args = useMemo(() => partialJSONParse(toolCall.function.arguments), [toolCall.function.arguments]);
|
|
1721
|
+
const toolName = toolCall.function.name;
|
|
1722
|
+
if (toolMessage) return /* @__PURE__ */ jsx(RenderComponent, {
|
|
1723
|
+
name: toolName,
|
|
1724
|
+
toolCallId: toolCall.id,
|
|
1725
|
+
args,
|
|
1726
|
+
status: ToolCallStatus.Complete,
|
|
1727
|
+
result: toolMessage.content
|
|
1728
|
+
});
|
|
1729
|
+
else if (isExecuting) return /* @__PURE__ */ jsx(RenderComponent, {
|
|
1730
|
+
name: toolName,
|
|
1731
|
+
toolCallId: toolCall.id,
|
|
1732
|
+
args,
|
|
1733
|
+
status: ToolCallStatus.Executing,
|
|
1734
|
+
result: void 0
|
|
1735
|
+
});
|
|
1736
|
+
else return /* @__PURE__ */ jsx(RenderComponent, {
|
|
1737
|
+
name: toolName,
|
|
1738
|
+
toolCallId: toolCall.id,
|
|
1739
|
+
args,
|
|
1740
|
+
status: ToolCallStatus.InProgress,
|
|
1741
|
+
result: void 0
|
|
1742
|
+
});
|
|
1743
|
+
}, (prevProps, nextProps) => {
|
|
1744
|
+
if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
|
|
1745
|
+
if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
|
|
1746
|
+
if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
|
|
1747
|
+
if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
|
|
1748
|
+
if (prevProps.isExecuting !== nextProps.isExecuting) return false;
|
|
1749
|
+
if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
|
|
1750
|
+
return true;
|
|
1801
1751
|
});
|
|
1802
|
-
function isRequest(msg) {
|
|
1803
|
-
return "id" in msg && "method" in msg;
|
|
1804
|
-
}
|
|
1805
|
-
function isNotification(msg) {
|
|
1806
|
-
return !("id" in msg) && "method" in msg;
|
|
1807
|
-
}
|
|
1808
1752
|
/**
|
|
1809
|
-
*
|
|
1753
|
+
* Hook that returns a function to render tool calls based on the render functions
|
|
1754
|
+
* defined in CopilotKitProvider.
|
|
1810
1755
|
*
|
|
1811
|
-
*
|
|
1812
|
-
* Fetches resource content on-demand via proxied MCP requests.
|
|
1756
|
+
* @returns A function that takes a tool call and optional tool message and returns the rendered component
|
|
1813
1757
|
*/
|
|
1814
|
-
|
|
1815
|
-
const { copilotkit } = useCopilotKit();
|
|
1816
|
-
const
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
inProgress: false,
|
|
1829
|
-
promise: null,
|
|
1830
|
-
resourceUri: null
|
|
1831
|
-
});
|
|
1832
|
-
const { resourceUri, serverHash, serverId } = content;
|
|
1833
|
-
const sendToIframe = useCallback((msg) => {
|
|
1834
|
-
if (iframeRef.current?.contentWindow) {
|
|
1835
|
-
console.log("[MCPAppsRenderer] Sending to iframe:", msg);
|
|
1836
|
-
iframeRef.current.contentWindow.postMessage(msg, "*");
|
|
1837
|
-
}
|
|
1838
|
-
}, []);
|
|
1839
|
-
const sendResponse = useCallback((id, result) => {
|
|
1840
|
-
sendToIframe({
|
|
1841
|
-
jsonrpc: "2.0",
|
|
1842
|
-
id,
|
|
1843
|
-
result
|
|
1844
|
-
});
|
|
1845
|
-
}, [sendToIframe]);
|
|
1846
|
-
const sendErrorResponse = useCallback((id, code, message) => {
|
|
1847
|
-
sendToIframe({
|
|
1848
|
-
jsonrpc: "2.0",
|
|
1849
|
-
id,
|
|
1850
|
-
error: {
|
|
1851
|
-
code,
|
|
1852
|
-
message
|
|
1853
|
-
}
|
|
1854
|
-
});
|
|
1855
|
-
}, [sendToIframe]);
|
|
1856
|
-
const sendNotification = useCallback((method, params) => {
|
|
1857
|
-
sendToIframe({
|
|
1858
|
-
jsonrpc: "2.0",
|
|
1859
|
-
method,
|
|
1860
|
-
params: params || {}
|
|
1861
|
-
});
|
|
1862
|
-
}, [sendToIframe]);
|
|
1863
|
-
useEffect(() => {
|
|
1864
|
-
if (fetchStateRef.current.inProgress && fetchStateRef.current.resourceUri === resourceUri) {
|
|
1865
|
-
fetchStateRef.current.promise?.then((resource) => {
|
|
1866
|
-
if (resource) {
|
|
1867
|
-
setFetchedResource(resource);
|
|
1868
|
-
setIsLoading(false);
|
|
1869
|
-
}
|
|
1870
|
-
}).catch((err) => {
|
|
1871
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1872
|
-
setIsLoading(false);
|
|
1873
|
-
});
|
|
1874
|
-
return;
|
|
1875
|
-
}
|
|
1876
|
-
if (!agent) {
|
|
1877
|
-
setError(/* @__PURE__ */ new Error("No agent available to fetch resource"));
|
|
1878
|
-
setIsLoading(false);
|
|
1879
|
-
return;
|
|
1880
|
-
}
|
|
1881
|
-
fetchStateRef.current.inProgress = true;
|
|
1882
|
-
fetchStateRef.current.resourceUri = resourceUri;
|
|
1883
|
-
const fetchPromise = (async () => {
|
|
1884
|
-
try {
|
|
1885
|
-
const resource = (await mcpAppsRequestQueue.enqueue(agent, () => agent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
1886
|
-
serverHash,
|
|
1887
|
-
serverId,
|
|
1888
|
-
method: "resources/read",
|
|
1889
|
-
params: { uri: resourceUri }
|
|
1890
|
-
} } }))).result?.contents?.[0];
|
|
1891
|
-
if (!resource) throw new Error("No resource content in response");
|
|
1892
|
-
return resource;
|
|
1893
|
-
} catch (err) {
|
|
1894
|
-
console.error("[MCPAppsRenderer] Failed to fetch resource:", err);
|
|
1895
|
-
throw err;
|
|
1896
|
-
} finally {
|
|
1897
|
-
fetchStateRef.current.inProgress = false;
|
|
1898
|
-
}
|
|
1899
|
-
})();
|
|
1900
|
-
fetchStateRef.current.promise = fetchPromise;
|
|
1901
|
-
fetchPromise.then((resource) => {
|
|
1902
|
-
if (resource) {
|
|
1903
|
-
setFetchedResource(resource);
|
|
1904
|
-
setIsLoading(false);
|
|
1905
|
-
}
|
|
1906
|
-
}).catch((err) => {
|
|
1907
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1908
|
-
setIsLoading(false);
|
|
1909
|
-
});
|
|
1758
|
+
function useRenderToolCall() {
|
|
1759
|
+
const { copilotkit, executingToolCallIds } = useCopilotKit();
|
|
1760
|
+
const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
|
|
1761
|
+
const renderToolCalls = useSyncExternalStore((callback) => {
|
|
1762
|
+
return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
|
|
1763
|
+
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1764
|
+
return useCallback(({ toolCall, toolMessage }) => {
|
|
1765
|
+
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
1766
|
+
return /* @__PURE__ */ jsx(ToolCallRenderer, {
|
|
1767
|
+
toolCall,
|
|
1768
|
+
toolMessage,
|
|
1769
|
+
RenderComponent: (exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*"))?.render ?? defaultToolCallRenderAdapter,
|
|
1770
|
+
isExecuting: executingToolCallIds.has(toolCall.id)
|
|
1771
|
+
}, toolCall.id);
|
|
1910
1772
|
}, [
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
serverId
|
|
1773
|
+
renderToolCalls,
|
|
1774
|
+
executingToolCallIds,
|
|
1775
|
+
agentId
|
|
1915
1776
|
]);
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1777
|
+
}
|
|
1778
|
+
function defaultToolCallRenderAdapter(props) {
|
|
1779
|
+
const status = props.status === ToolCallStatus.Complete ? "complete" : props.status === ToolCallStatus.Executing ? "executing" : "inProgress";
|
|
1780
|
+
return /* @__PURE__ */ jsx(DefaultToolCallRenderer, {
|
|
1781
|
+
name: props.name,
|
|
1782
|
+
parameters: props.args,
|
|
1783
|
+
status,
|
|
1784
|
+
result: props.result
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
//#endregion
|
|
1789
|
+
//#region src/v2/components/CopilotKitInspector.tsx
|
|
1790
|
+
const CopilotKitInspector = ({ core, ...rest }) => {
|
|
1791
|
+
const [InspectorComponent, setInspectorComponent] = React$1.useState(null);
|
|
1792
|
+
React$1.useEffect(() => {
|
|
1920
1793
|
let mounted = true;
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
iframe.style.border = "none";
|
|
1931
|
-
iframe.style.backgroundColor = "transparent";
|
|
1932
|
-
iframe.style.display = "block";
|
|
1933
|
-
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
|
|
1934
|
-
const sandboxReady = new Promise((resolve) => {
|
|
1935
|
-
initialListener = (event) => {
|
|
1936
|
-
if (event.source === iframe.contentWindow) {
|
|
1937
|
-
if (event.data?.method === "ui/notifications/sandbox-proxy-ready") {
|
|
1938
|
-
if (initialListener) {
|
|
1939
|
-
window.removeEventListener("message", initialListener);
|
|
1940
|
-
initialListener = null;
|
|
1941
|
-
}
|
|
1942
|
-
resolve();
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
};
|
|
1946
|
-
window.addEventListener("message", initialListener);
|
|
1947
|
-
});
|
|
1948
|
-
if (!mounted) {
|
|
1949
|
-
if (initialListener) {
|
|
1950
|
-
window.removeEventListener("message", initialListener);
|
|
1951
|
-
initialListener = null;
|
|
1952
|
-
}
|
|
1953
|
-
return;
|
|
1954
|
-
}
|
|
1955
|
-
const cspDomains = fetchedResource._meta?.ui?.csp?.resourceDomains;
|
|
1956
|
-
iframe.srcdoc = buildSandboxHTML(cspDomains);
|
|
1957
|
-
iframeRef.current = iframe;
|
|
1958
|
-
container.appendChild(iframe);
|
|
1959
|
-
await sandboxReady;
|
|
1960
|
-
if (!mounted) return;
|
|
1961
|
-
console.log("[MCPAppsRenderer] Sandbox proxy ready");
|
|
1962
|
-
messageHandler = async (event) => {
|
|
1963
|
-
if (event.source !== iframe.contentWindow) return;
|
|
1964
|
-
const msg = event.data;
|
|
1965
|
-
if (!msg || typeof msg !== "object" || msg.jsonrpc !== "2.0") return;
|
|
1966
|
-
console.log("[MCPAppsRenderer] Received from iframe:", msg);
|
|
1967
|
-
if (isRequest(msg)) switch (msg.method) {
|
|
1968
|
-
case "ui/initialize":
|
|
1969
|
-
sendResponse(msg.id, {
|
|
1970
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
1971
|
-
hostInfo: {
|
|
1972
|
-
name: "CopilotKit MCP Apps Host",
|
|
1973
|
-
version: "1.0.0"
|
|
1974
|
-
},
|
|
1975
|
-
hostCapabilities: {
|
|
1976
|
-
openLinks: {},
|
|
1977
|
-
logging: {}
|
|
1978
|
-
},
|
|
1979
|
-
hostContext: {
|
|
1980
|
-
theme: "light",
|
|
1981
|
-
platform: "web"
|
|
1982
|
-
}
|
|
1983
|
-
});
|
|
1984
|
-
break;
|
|
1985
|
-
case "ui/message": {
|
|
1986
|
-
const currentAgent = agentRef.current;
|
|
1987
|
-
if (!currentAgent) {
|
|
1988
|
-
console.warn("[MCPAppsRenderer] ui/message: No agent available");
|
|
1989
|
-
sendResponse(msg.id, { isError: false });
|
|
1990
|
-
break;
|
|
1991
|
-
}
|
|
1992
|
-
try {
|
|
1993
|
-
const params = msg.params;
|
|
1994
|
-
const role = params.role || "user";
|
|
1995
|
-
const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
|
|
1996
|
-
if (textContent) currentAgent.addMessage({
|
|
1997
|
-
id: crypto.randomUUID(),
|
|
1998
|
-
role,
|
|
1999
|
-
content: textContent
|
|
2000
|
-
});
|
|
2001
|
-
sendResponse(msg.id, { isError: false });
|
|
2002
|
-
if ((params.followUp ?? role === "user") && textContent) mcpAppsRequestQueue.enqueue(currentAgent, () => copilotkit.runAgent({ agent: currentAgent })).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
|
|
2003
|
-
} catch (err) {
|
|
2004
|
-
console.error("[MCPAppsRenderer] ui/message error:", err);
|
|
2005
|
-
sendResponse(msg.id, { isError: true });
|
|
2006
|
-
}
|
|
2007
|
-
break;
|
|
2008
|
-
}
|
|
2009
|
-
case "ui/open-link": {
|
|
2010
|
-
const url = msg.params?.url;
|
|
2011
|
-
if (url) {
|
|
2012
|
-
window.open(url, "_blank", "noopener,noreferrer");
|
|
2013
|
-
sendResponse(msg.id, { isError: false });
|
|
2014
|
-
} else sendErrorResponse(msg.id, -32602, "Missing url parameter");
|
|
2015
|
-
break;
|
|
2016
|
-
}
|
|
2017
|
-
case "tools/call": {
|
|
2018
|
-
const { serverHash, serverId } = contentRef.current;
|
|
2019
|
-
const currentAgent = agentRef.current;
|
|
2020
|
-
if (!serverHash) {
|
|
2021
|
-
sendErrorResponse(msg.id, -32603, "No server hash available for proxying");
|
|
2022
|
-
break;
|
|
2023
|
-
}
|
|
2024
|
-
if (!currentAgent) {
|
|
2025
|
-
sendErrorResponse(msg.id, -32603, "No agent available for proxying");
|
|
2026
|
-
break;
|
|
2027
|
-
}
|
|
2028
|
-
try {
|
|
2029
|
-
const runResult = await mcpAppsRequestQueue.enqueue(currentAgent, () => currentAgent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
2030
|
-
serverHash,
|
|
2031
|
-
serverId,
|
|
2032
|
-
method: "tools/call",
|
|
2033
|
-
params: msg.params
|
|
2034
|
-
} } }));
|
|
2035
|
-
sendResponse(msg.id, runResult.result || {});
|
|
2036
|
-
} catch (err) {
|
|
2037
|
-
console.error("[MCPAppsRenderer] tools/call error:", err);
|
|
2038
|
-
sendErrorResponse(msg.id, -32603, String(err));
|
|
2039
|
-
}
|
|
2040
|
-
break;
|
|
2041
|
-
}
|
|
2042
|
-
default: sendErrorResponse(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
2043
|
-
}
|
|
2044
|
-
if (isNotification(msg)) switch (msg.method) {
|
|
2045
|
-
case "ui/notifications/initialized":
|
|
2046
|
-
console.log("[MCPAppsRenderer] Inner iframe initialized");
|
|
2047
|
-
if (mounted) setIframeReady(true);
|
|
2048
|
-
break;
|
|
2049
|
-
case "ui/notifications/size-changed": {
|
|
2050
|
-
const { width, height } = msg.params || {};
|
|
2051
|
-
console.log("[MCPAppsRenderer] Size change:", {
|
|
2052
|
-
width,
|
|
2053
|
-
height
|
|
2054
|
-
});
|
|
2055
|
-
if (mounted) setIframeSize({
|
|
2056
|
-
width: typeof width === "number" ? width : void 0,
|
|
2057
|
-
height: typeof height === "number" ? height : void 0
|
|
2058
|
-
});
|
|
2059
|
-
break;
|
|
2060
|
-
}
|
|
2061
|
-
case "notifications/message":
|
|
2062
|
-
console.log("[MCPAppsRenderer] App log:", msg.params);
|
|
2063
|
-
break;
|
|
2064
|
-
}
|
|
2065
|
-
};
|
|
2066
|
-
window.addEventListener("message", messageHandler);
|
|
2067
|
-
let html;
|
|
2068
|
-
if (fetchedResource.text) html = fetchedResource.text;
|
|
2069
|
-
else if (fetchedResource.blob) html = atob(fetchedResource.blob);
|
|
2070
|
-
else throw new Error("Resource has no text or blob content");
|
|
2071
|
-
sendNotification("ui/notifications/sandbox-resource-ready", { html });
|
|
2072
|
-
} catch (err) {
|
|
2073
|
-
console.error("[MCPAppsRenderer] Setup error:", err);
|
|
2074
|
-
if (mounted) setError(err instanceof Error ? err : new Error(String(err)));
|
|
2075
|
-
}
|
|
2076
|
-
};
|
|
2077
|
-
setup();
|
|
1794
|
+
import("@copilotkit/web-inspector").then((mod) => {
|
|
1795
|
+
mod.defineWebInspector?.();
|
|
1796
|
+
const Component = createComponent({
|
|
1797
|
+
tagName: mod.WEB_INSPECTOR_TAG,
|
|
1798
|
+
elementClass: mod.WebInspectorElement,
|
|
1799
|
+
react: React$1
|
|
1800
|
+
});
|
|
1801
|
+
if (mounted) setInspectorComponent(() => Component);
|
|
1802
|
+
});
|
|
2078
1803
|
return () => {
|
|
2079
1804
|
mounted = false;
|
|
2080
|
-
if (initialListener) {
|
|
2081
|
-
window.removeEventListener("message", initialListener);
|
|
2082
|
-
initialListener = null;
|
|
2083
|
-
}
|
|
2084
|
-
if (messageHandler) window.removeEventListener("message", messageHandler);
|
|
2085
|
-
if (createdIframe) {
|
|
2086
|
-
createdIframe.remove();
|
|
2087
|
-
createdIframe = null;
|
|
2088
|
-
}
|
|
2089
|
-
iframeRef.current = null;
|
|
2090
1805
|
};
|
|
2091
|
-
}, [
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
sendErrorResponse
|
|
2097
|
-
]);
|
|
2098
|
-
useEffect(() => {
|
|
2099
|
-
if (iframeRef.current) {
|
|
2100
|
-
if (iframeSize.width !== void 0) {
|
|
2101
|
-
iframeRef.current.style.minWidth = `min(${iframeSize.width}px, 100%)`;
|
|
2102
|
-
iframeRef.current.style.width = "100%";
|
|
2103
|
-
}
|
|
2104
|
-
if (iframeSize.height !== void 0) iframeRef.current.style.height = `${iframeSize.height}px`;
|
|
2105
|
-
}
|
|
2106
|
-
}, [iframeSize]);
|
|
2107
|
-
useEffect(() => {
|
|
2108
|
-
if (iframeReady && content.toolInput) {
|
|
2109
|
-
console.log("[MCPAppsRenderer] Sending tool input:", content.toolInput);
|
|
2110
|
-
sendNotification("ui/notifications/tool-input", { arguments: content.toolInput });
|
|
2111
|
-
}
|
|
2112
|
-
}, [
|
|
2113
|
-
iframeReady,
|
|
2114
|
-
content.toolInput,
|
|
2115
|
-
sendNotification
|
|
2116
|
-
]);
|
|
2117
|
-
useEffect(() => {
|
|
2118
|
-
if (iframeReady && content.result) {
|
|
2119
|
-
console.log("[MCPAppsRenderer] Sending tool result:", content.result);
|
|
2120
|
-
sendNotification("ui/notifications/tool-result", content.result);
|
|
2121
|
-
}
|
|
2122
|
-
}, [
|
|
2123
|
-
iframeReady,
|
|
2124
|
-
content.result,
|
|
2125
|
-
sendNotification
|
|
2126
|
-
]);
|
|
2127
|
-
const borderStyle = fetchedResource?._meta?.ui?.prefersBorder === true ? {
|
|
2128
|
-
borderRadius: "8px",
|
|
2129
|
-
backgroundColor: "#f9f9f9",
|
|
2130
|
-
border: "1px solid #e0e0e0"
|
|
2131
|
-
} : {};
|
|
2132
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2133
|
-
ref: containerRef,
|
|
2134
|
-
style: {
|
|
2135
|
-
width: "100%",
|
|
2136
|
-
height: iframeSize.height ? `${iframeSize.height}px` : "auto",
|
|
2137
|
-
minHeight: "100px",
|
|
2138
|
-
overflow: "hidden",
|
|
2139
|
-
position: "relative",
|
|
2140
|
-
...borderStyle
|
|
2141
|
-
},
|
|
2142
|
-
children: [isLoading && /* @__PURE__ */ jsx("div", {
|
|
2143
|
-
style: {
|
|
2144
|
-
padding: "1rem",
|
|
2145
|
-
color: "#666"
|
|
2146
|
-
},
|
|
2147
|
-
children: "Loading..."
|
|
2148
|
-
}), error && /* @__PURE__ */ jsxs("div", {
|
|
2149
|
-
style: {
|
|
2150
|
-
color: "red",
|
|
2151
|
-
padding: "1rem"
|
|
2152
|
-
},
|
|
2153
|
-
children: ["Error: ", error.message]
|
|
2154
|
-
})]
|
|
1806
|
+
}, []);
|
|
1807
|
+
if (!InspectorComponent) return null;
|
|
1808
|
+
return /* @__PURE__ */ jsx(InspectorComponent, {
|
|
1809
|
+
...rest,
|
|
1810
|
+
core: core ?? null
|
|
2155
1811
|
});
|
|
2156
1812
|
};
|
|
1813
|
+
CopilotKitInspector.displayName = "CopilotKitInspector";
|
|
2157
1814
|
|
|
2158
1815
|
//#endregion
|
|
2159
|
-
//#region src/v2/
|
|
2160
|
-
const
|
|
2161
|
-
|
|
2162
|
-
|
|
1816
|
+
//#region src/v2/components/license-warning-banner.tsx
|
|
1817
|
+
const LICENSE_BANNER_OFFSET_PX = 52;
|
|
1818
|
+
const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
|
|
1819
|
+
const BANNER_STYLES = {
|
|
1820
|
+
base: {
|
|
1821
|
+
position: "fixed",
|
|
1822
|
+
bottom: "8px",
|
|
1823
|
+
left: "50%",
|
|
1824
|
+
transform: "translateX(-50%)",
|
|
1825
|
+
zIndex: 99999,
|
|
1826
|
+
display: "inline-flex",
|
|
1827
|
+
alignItems: "center",
|
|
1828
|
+
gap: "12px",
|
|
1829
|
+
whiteSpace: "nowrap",
|
|
1830
|
+
padding: "8px 16px",
|
|
1831
|
+
fontSize: "13px",
|
|
1832
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
1833
|
+
borderRadius: "6px",
|
|
1834
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)"
|
|
1835
|
+
},
|
|
1836
|
+
info: {
|
|
1837
|
+
backgroundColor: "#eff6ff",
|
|
1838
|
+
border: "1px solid #93c5fd",
|
|
1839
|
+
color: "#1e40af"
|
|
1840
|
+
},
|
|
1841
|
+
warning: {
|
|
1842
|
+
backgroundColor: "#fffbeb",
|
|
1843
|
+
border: "1px solid #fbbf24",
|
|
1844
|
+
color: "#92400e"
|
|
1845
|
+
},
|
|
1846
|
+
critical: {
|
|
1847
|
+
backgroundColor: "#fef2f2",
|
|
1848
|
+
border: "1px solid #fca5a5",
|
|
1849
|
+
color: "#991b1b"
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
function getSeverityStyle(severity) {
|
|
1853
|
+
switch (severity) {
|
|
1854
|
+
case "warning": return BANNER_STYLES.warning;
|
|
1855
|
+
case "critical": return BANNER_STYLES.critical;
|
|
1856
|
+
default: return BANNER_STYLES.info;
|
|
1857
|
+
}
|
|
2163
1858
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
return
|
|
1859
|
+
function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
|
|
1860
|
+
useEffect(() => {
|
|
1861
|
+
if (typeof document === "undefined") return;
|
|
1862
|
+
const root = document.documentElement;
|
|
1863
|
+
root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
|
|
1864
|
+
return () => {
|
|
1865
|
+
root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
|
|
1866
|
+
};
|
|
1867
|
+
}, []);
|
|
1868
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1869
|
+
style: {
|
|
1870
|
+
...BANNER_STYLES.base,
|
|
1871
|
+
...getSeverityStyle(severity)
|
|
1872
|
+
},
|
|
1873
|
+
children: [/* @__PURE__ */ jsx("span", { children: message }), /* @__PURE__ */ jsxs("div", {
|
|
1874
|
+
style: {
|
|
1875
|
+
display: "flex",
|
|
1876
|
+
gap: "8px",
|
|
1877
|
+
alignItems: "center"
|
|
1878
|
+
},
|
|
1879
|
+
children: [/* @__PURE__ */ jsx("a", {
|
|
1880
|
+
href: actionUrl,
|
|
1881
|
+
target: "_blank",
|
|
1882
|
+
rel: "noopener noreferrer",
|
|
1883
|
+
style: {
|
|
1884
|
+
fontWeight: 600,
|
|
1885
|
+
textDecoration: "underline",
|
|
1886
|
+
color: "inherit"
|
|
1887
|
+
},
|
|
1888
|
+
children: actionLabel
|
|
1889
|
+
}), onDismiss && /* @__PURE__ */ jsx("button", {
|
|
1890
|
+
onClick: onDismiss,
|
|
1891
|
+
style: {
|
|
1892
|
+
background: "none",
|
|
1893
|
+
border: "none",
|
|
1894
|
+
cursor: "pointer",
|
|
1895
|
+
color: "inherit",
|
|
1896
|
+
fontSize: "16px"
|
|
1897
|
+
},
|
|
1898
|
+
children: "×"
|
|
1899
|
+
})]
|
|
1900
|
+
})]
|
|
1901
|
+
});
|
|
2174
1902
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
1903
|
+
function LicenseWarningBanner({ type, featureName, expiryDate, graceRemaining, onDismiss }) {
|
|
1904
|
+
switch (type) {
|
|
1905
|
+
case "no_license": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1906
|
+
severity: "info",
|
|
1907
|
+
message: "Powered by CopilotKit",
|
|
1908
|
+
actionLabel: "Get a license",
|
|
1909
|
+
actionUrl: "https://copilotkit.ai/pricing",
|
|
1910
|
+
onDismiss
|
|
1911
|
+
});
|
|
1912
|
+
case "feature_unlicensed": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1913
|
+
severity: "warning",
|
|
1914
|
+
message: `⚠ The "${featureName}" feature requires a CopilotKit license.`,
|
|
1915
|
+
actionLabel: "Get a license",
|
|
1916
|
+
actionUrl: "https://copilotkit.ai/pricing",
|
|
1917
|
+
onDismiss
|
|
1918
|
+
});
|
|
1919
|
+
case "expiring": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1920
|
+
severity: "warning",
|
|
1921
|
+
message: `Your CopilotKit license expires in ${graceRemaining} day${graceRemaining !== 1 ? "s" : ""}. Please renew.`,
|
|
1922
|
+
actionLabel: "Renew",
|
|
1923
|
+
actionUrl: "https://cloud.copilotkit.ai",
|
|
1924
|
+
onDismiss
|
|
1925
|
+
});
|
|
1926
|
+
case "expired": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1927
|
+
severity: "critical",
|
|
1928
|
+
message: `Your CopilotKit license expired${expiryDate ? ` on ${expiryDate}` : ""}. Please renew at copilotkit.ai/pricing`,
|
|
1929
|
+
actionLabel: "Renew now",
|
|
1930
|
+
actionUrl: "https://copilotkit.ai/pricing",
|
|
1931
|
+
onDismiss
|
|
1932
|
+
});
|
|
1933
|
+
case "invalid": return /* @__PURE__ */ jsx(BannerShell, {
|
|
1934
|
+
severity: "critical",
|
|
1935
|
+
message: "Invalid CopilotKit license token. Please check your configuration.",
|
|
1936
|
+
actionLabel: "Get a license",
|
|
1937
|
+
actionUrl: "https://copilotkit.ai/pricing",
|
|
1938
|
+
onDismiss
|
|
1939
|
+
});
|
|
1940
|
+
default: return null;
|
|
2196
1941
|
}
|
|
2197
|
-
|
|
1942
|
+
}
|
|
1943
|
+
function InlineFeatureWarning({ featureName }) {
|
|
1944
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1945
|
+
style: {
|
|
1946
|
+
padding: "8px 12px",
|
|
1947
|
+
backgroundColor: "#fffbeb",
|
|
1948
|
+
border: "1px solid #fbbf24",
|
|
1949
|
+
borderRadius: "6px",
|
|
1950
|
+
fontSize: "13px",
|
|
1951
|
+
color: "#92400e",
|
|
1952
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif"
|
|
1953
|
+
},
|
|
1954
|
+
children: [
|
|
1955
|
+
"⚠ The \"",
|
|
1956
|
+
featureName,
|
|
1957
|
+
"\" feature requires a CopilotKit license.",
|
|
1958
|
+
" ",
|
|
1959
|
+
/* @__PURE__ */ jsx("a", {
|
|
1960
|
+
href: "https://copilotkit.ai/pricing",
|
|
1961
|
+
target: "_blank",
|
|
1962
|
+
rel: "noopener noreferrer",
|
|
1963
|
+
style: {
|
|
1964
|
+
color: "#b45309",
|
|
1965
|
+
textDecoration: "underline"
|
|
1966
|
+
},
|
|
1967
|
+
children: "Get one at copilotkit.ai/pricing"
|
|
1968
|
+
})
|
|
1969
|
+
]
|
|
1970
|
+
});
|
|
2198
1971
|
}
|
|
2199
1972
|
|
|
2200
1973
|
//#endregion
|
|
2201
|
-
//#region src/v2/components/
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
1974
|
+
//#region src/v2/components/MCPAppsActivityRenderer.tsx
|
|
1975
|
+
const PROTOCOL_VERSION = "2025-06-18";
|
|
1976
|
+
function buildSandboxHTML(extraCspDomains) {
|
|
1977
|
+
const baseScriptSrc = "'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*";
|
|
1978
|
+
const baseFrameSrc = "* blob: data: http://localhost:* https://localhost:*";
|
|
1979
|
+
const extra = extraCspDomains?.length ? " " + extraCspDomains.join(" ") : "";
|
|
1980
|
+
return `<!doctype html>
|
|
1981
|
+
<html>
|
|
1982
|
+
<head>
|
|
1983
|
+
<meta charset="utf-8" />
|
|
1984
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data: blob: 'unsafe-inline'; media-src * blob: data:; font-src * blob: data:; script-src ${baseScriptSrc + extra}; style-src * blob: data: 'unsafe-inline'; connect-src *; frame-src ${baseFrameSrc + extra}; base-uri 'self';" />
|
|
1985
|
+
<style>html,body{margin:0;padding:0;height:100%;width:100%;overflow:hidden}*{box-sizing:border-box}iframe{background-color:transparent;border:none;padding:0;overflow:hidden;width:100%;height:100%}</style>
|
|
1986
|
+
</head>
|
|
1987
|
+
<body>
|
|
1988
|
+
<script>
|
|
1989
|
+
if(window.self===window.top){throw new Error("This file must be used in an iframe.")}
|
|
1990
|
+
const inner=document.createElement("iframe");
|
|
1991
|
+
inner.style="width:100%;height:100%;border:none;";
|
|
1992
|
+
inner.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms");
|
|
1993
|
+
document.body.appendChild(inner);
|
|
1994
|
+
window.addEventListener("message",async(event)=>{
|
|
1995
|
+
if(event.source===window.parent){
|
|
1996
|
+
if(event.data&&event.data.method==="ui/notifications/sandbox-resource-ready"){
|
|
1997
|
+
const{html,sandbox}=event.data.params;
|
|
1998
|
+
if(typeof sandbox==="string")inner.setAttribute("sandbox",sandbox);
|
|
1999
|
+
if(typeof html==="string")inner.srcdoc=html;
|
|
2000
|
+
}else if(inner&&inner.contentWindow){
|
|
2001
|
+
inner.contentWindow.postMessage(event.data,"*");
|
|
2002
|
+
}
|
|
2003
|
+
}else if(event.source===inner.contentWindow){
|
|
2004
|
+
window.parent.postMessage(event.data,"*");
|
|
2005
|
+
}
|
|
2226
2006
|
});
|
|
2227
|
-
|
|
2007
|
+
window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-ready",params:{}},"*");
|
|
2008
|
+
<\/script>
|
|
2009
|
+
</body>
|
|
2010
|
+
</html>`;
|
|
2011
|
+
}
|
|
2228
2012
|
/**
|
|
2229
|
-
*
|
|
2230
|
-
*
|
|
2013
|
+
* Queue for serializing MCP app requests to an agent.
|
|
2014
|
+
* Ensures requests wait for the agent to stop running and are processed one at a time.
|
|
2231
2015
|
*/
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
const [throttledContent, setThrottledContent] = useState(content);
|
|
2249
|
-
const throttledContentRef = useRef(throttledContent);
|
|
2250
|
-
const timerRef = useRef(null);
|
|
2251
|
-
if (throttledContentRef.current !== content) {
|
|
2252
|
-
if (shouldFlushImmediately(throttledContentRef.current, content)) {
|
|
2253
|
-
if (timerRef.current !== null) {
|
|
2254
|
-
clearTimeout(timerRef.current);
|
|
2255
|
-
timerRef.current = null;
|
|
2016
|
+
var MCPAppsRequestQueue = class {
|
|
2017
|
+
constructor() {
|
|
2018
|
+
this.queues = /* @__PURE__ */ new Map();
|
|
2019
|
+
this.processing = /* @__PURE__ */ new Map();
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* Add a request to the queue for a specific agent thread.
|
|
2023
|
+
* Returns a promise that resolves when the request completes.
|
|
2024
|
+
*/
|
|
2025
|
+
async enqueue(agent, request) {
|
|
2026
|
+
const threadId = agent.threadId || "default";
|
|
2027
|
+
return new Promise((resolve, reject) => {
|
|
2028
|
+
let queue = this.queues.get(threadId);
|
|
2029
|
+
if (!queue) {
|
|
2030
|
+
queue = [];
|
|
2031
|
+
this.queues.set(threadId, queue);
|
|
2256
2032
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2033
|
+
queue.push({
|
|
2034
|
+
execute: request,
|
|
2035
|
+
resolve,
|
|
2036
|
+
reject
|
|
2037
|
+
});
|
|
2038
|
+
this.processQueue(threadId, agent);
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
async processQueue(threadId, agent) {
|
|
2042
|
+
if (this.processing.get(threadId)) return;
|
|
2043
|
+
this.processing.set(threadId, true);
|
|
2044
|
+
try {
|
|
2045
|
+
const queue = this.queues.get(threadId);
|
|
2046
|
+
if (!queue) return;
|
|
2047
|
+
while (queue.length > 0) {
|
|
2048
|
+
const item = queue[0];
|
|
2049
|
+
try {
|
|
2050
|
+
await this.waitForAgentIdle(agent);
|
|
2051
|
+
const result = await item.execute();
|
|
2052
|
+
item.resolve(result);
|
|
2053
|
+
} catch (error) {
|
|
2054
|
+
item.reject(error instanceof Error ? error : new Error(String(error)));
|
|
2055
|
+
}
|
|
2056
|
+
queue.shift();
|
|
2057
|
+
}
|
|
2058
|
+
} finally {
|
|
2059
|
+
this.processing.set(threadId, false);
|
|
2259
2060
|
}
|
|
2260
2061
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2062
|
+
waitForAgentIdle(agent) {
|
|
2063
|
+
return new Promise((resolve) => {
|
|
2064
|
+
if (!agent.isRunning) {
|
|
2065
|
+
resolve();
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
let done = false;
|
|
2069
|
+
const finish = () => {
|
|
2070
|
+
if (done) return;
|
|
2071
|
+
done = true;
|
|
2072
|
+
clearInterval(checkInterval);
|
|
2073
|
+
sub.unsubscribe();
|
|
2074
|
+
resolve();
|
|
2075
|
+
};
|
|
2076
|
+
const sub = agent.subscribe({
|
|
2077
|
+
onRunFinalized: finish,
|
|
2078
|
+
onRunFailed: finish
|
|
2079
|
+
});
|
|
2080
|
+
const checkInterval = setInterval(() => {
|
|
2081
|
+
if (!agent.isRunning) finish();
|
|
2082
|
+
}, 500);
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2277
2085
|
};
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2086
|
+
const mcpAppsRequestQueue = new MCPAppsRequestQueue();
|
|
2087
|
+
/**
|
|
2088
|
+
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType
|
|
2089
|
+
*/
|
|
2090
|
+
const MCPAppsActivityType = "mcp-apps";
|
|
2091
|
+
const MCPAppsActivityContentSchema = z.object({
|
|
2092
|
+
result: z.object({
|
|
2093
|
+
content: z.array(z.any()).optional(),
|
|
2094
|
+
structuredContent: z.any().optional(),
|
|
2095
|
+
isError: z.boolean().optional()
|
|
2096
|
+
}),
|
|
2097
|
+
resourceUri: z.string(),
|
|
2098
|
+
serverHash: z.string(),
|
|
2099
|
+
serverId: z.string().optional(),
|
|
2100
|
+
toolInput: z.record(z.unknown()).optional()
|
|
2101
|
+
});
|
|
2102
|
+
function isRequest(msg) {
|
|
2103
|
+
return "id" in msg && "method" in msg;
|
|
2281
2104
|
}
|
|
2282
|
-
function
|
|
2283
|
-
|
|
2284
|
-
if (headCloseIdx !== -1) return html.slice(0, headCloseIdx) + `<style>${css}</style>` + html.slice(headCloseIdx);
|
|
2285
|
-
return `<head><style>${css}</style></head>${html}`;
|
|
2105
|
+
function isNotification(msg) {
|
|
2106
|
+
return !("id" in msg) && "method" in msg;
|
|
2286
2107
|
}
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
}, [sandboxFunctions]);
|
|
2296
|
-
const fullHtml = content.htmlComplete && content.html?.length ? content.html.join("") : void 0;
|
|
2297
|
-
const css = content.cssComplete ? content.css : void 0;
|
|
2298
|
-
const cssReady = !!content.cssComplete;
|
|
2299
|
-
const partialHtml = !content.htmlComplete && content.html?.length ? content.html.join("") : void 0;
|
|
2300
|
-
const previewBody = partialHtml ? processPartialHtml(partialHtml) : void 0;
|
|
2301
|
-
const previewStyles = partialHtml ? extractCompleteStyles(partialHtml) : "";
|
|
2302
|
-
const hasPreview = cssReady && !!previewBody?.trim();
|
|
2303
|
-
const hasVisibleSandbox = !!fullHtml || hasPreview;
|
|
2108
|
+
/**
|
|
2109
|
+
* MCP Apps Extension Activity Renderer
|
|
2110
|
+
*
|
|
2111
|
+
* Renders MCP Apps UI in a sandboxed iframe with full protocol support.
|
|
2112
|
+
* Fetches resource content on-demand via proxied MCP requests.
|
|
2113
|
+
*/
|
|
2114
|
+
const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agent }) {
|
|
2115
|
+
const { copilotkit } = useCopilotKit();
|
|
2304
2116
|
const containerRef = useRef(null);
|
|
2305
|
-
const
|
|
2306
|
-
const
|
|
2307
|
-
const
|
|
2308
|
-
const
|
|
2309
|
-
const
|
|
2310
|
-
const
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
sandbox.run(`
|
|
2332
|
-
var s = document.createElement('style');
|
|
2333
|
-
s.textContent = 'html, body { overflow: hidden !important; }';
|
|
2334
|
-
document.head.appendChild(s);
|
|
2335
|
-
`);
|
|
2336
|
-
const headParts = [];
|
|
2337
|
-
if (css) headParts.push(`<style>${css}</style>`);
|
|
2338
|
-
if (previewStyles) headParts.push(previewStyles);
|
|
2339
|
-
if (headParts.length) sandbox.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
|
|
2340
|
-
if (previewBody) sandbox.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
|
|
2341
|
-
});
|
|
2342
|
-
}).catch((err) => {
|
|
2343
|
-
console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
|
|
2117
|
+
const iframeRef = useRef(null);
|
|
2118
|
+
const [iframeReady, setIframeReady] = useState(false);
|
|
2119
|
+
const [error, setError] = useState(null);
|
|
2120
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
2121
|
+
const [iframeSize, setIframeSize] = useState({});
|
|
2122
|
+
const [fetchedResource, setFetchedResource] = useState(null);
|
|
2123
|
+
const contentRef = useRef(content);
|
|
2124
|
+
contentRef.current = content;
|
|
2125
|
+
const agentRef = useRef(agent);
|
|
2126
|
+
agentRef.current = agent;
|
|
2127
|
+
const fetchStateRef = useRef({
|
|
2128
|
+
inProgress: false,
|
|
2129
|
+
promise: null,
|
|
2130
|
+
resourceUri: null
|
|
2131
|
+
});
|
|
2132
|
+
const sendToIframe = useCallback((msg) => {
|
|
2133
|
+
if (iframeRef.current?.contentWindow) {
|
|
2134
|
+
console.log("[MCPAppsRenderer] Sending to iframe:", msg);
|
|
2135
|
+
iframeRef.current.contentWindow.postMessage(msg, "*");
|
|
2136
|
+
}
|
|
2137
|
+
}, []);
|
|
2138
|
+
const sendResponse = useCallback((id, result) => {
|
|
2139
|
+
sendToIframe({
|
|
2140
|
+
jsonrpc: "2.0",
|
|
2141
|
+
id,
|
|
2142
|
+
result
|
|
2344
2143
|
});
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2144
|
+
}, [sendToIframe]);
|
|
2145
|
+
const sendErrorResponse = useCallback((id, code, message) => {
|
|
2146
|
+
sendToIframe({
|
|
2147
|
+
jsonrpc: "2.0",
|
|
2148
|
+
id,
|
|
2149
|
+
error: {
|
|
2150
|
+
code,
|
|
2151
|
+
message
|
|
2152
|
+
}
|
|
2153
|
+
});
|
|
2154
|
+
}, [sendToIframe]);
|
|
2155
|
+
const sendNotification = useCallback((method, params) => {
|
|
2156
|
+
sendToIframe({
|
|
2157
|
+
jsonrpc: "2.0",
|
|
2158
|
+
method,
|
|
2159
|
+
params: params || {}
|
|
2160
|
+
});
|
|
2161
|
+
}, [sendToIframe]);
|
|
2349
2162
|
useEffect(() => {
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
css
|
|
2361
|
-
]);
|
|
2362
|
-
useEffect(() => {
|
|
2363
|
-
const container = containerRef.current;
|
|
2364
|
-
if (!container || !fullHtml) return;
|
|
2365
|
-
if (previewSandboxRef.current) {
|
|
2366
|
-
previewSandboxRef.current.destroy();
|
|
2367
|
-
previewSandboxRef.current = null;
|
|
2368
|
-
previewReadyRef.current = false;
|
|
2369
|
-
}
|
|
2370
|
-
let cancelled = false;
|
|
2371
|
-
executedIndexRef.current = 0;
|
|
2372
|
-
jsFunctionsInjectedRef.current = false;
|
|
2373
|
-
sandboxReadyRef.current = false;
|
|
2374
|
-
pendingQueueRef.current = [];
|
|
2375
|
-
const htmlContent = css ? injectCssIntoHtml(fullHtml, css) : fullHtml;
|
|
2376
|
-
import("@jetbrains/websandbox").then((mod) => {
|
|
2377
|
-
if (cancelled) return;
|
|
2378
|
-
const sandbox = (mod.default?.default ?? mod.default).create(localApi, {
|
|
2379
|
-
frameContainer: container,
|
|
2380
|
-
frameContent: ensureHead(htmlContent),
|
|
2381
|
-
allowAdditionalAttributes: ""
|
|
2382
|
-
});
|
|
2383
|
-
sandboxRef.current = sandbox;
|
|
2384
|
-
sandbox.iframe.style.width = "100%";
|
|
2385
|
-
sandbox.iframe.style.height = "100%";
|
|
2386
|
-
sandbox.iframe.style.border = "none";
|
|
2387
|
-
sandbox.iframe.style.backgroundColor = "transparent";
|
|
2388
|
-
sandbox.promise.then(() => {
|
|
2389
|
-
if (cancelled) return;
|
|
2390
|
-
sandboxReadyRef.current = true;
|
|
2391
|
-
sandbox.run(`
|
|
2392
|
-
var s = document.createElement('style');
|
|
2393
|
-
s.textContent = 'html, body { overflow: hidden !important; }';
|
|
2394
|
-
document.head.appendChild(s);
|
|
2395
|
-
`);
|
|
2396
|
-
const queue = pendingQueueRef.current;
|
|
2397
|
-
pendingQueueRef.current = [];
|
|
2398
|
-
for (const code of queue) sandbox.run(code);
|
|
2163
|
+
const { resourceUri, serverHash, serverId } = content;
|
|
2164
|
+
if (fetchStateRef.current.inProgress && fetchStateRef.current.resourceUri === resourceUri) {
|
|
2165
|
+
fetchStateRef.current.promise?.then((resource) => {
|
|
2166
|
+
if (resource) {
|
|
2167
|
+
setFetchedResource(resource);
|
|
2168
|
+
setIsLoading(false);
|
|
2169
|
+
}
|
|
2170
|
+
}).catch((err) => {
|
|
2171
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2172
|
+
setIsLoading(false);
|
|
2399
2173
|
});
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
if (!agent) {
|
|
2177
|
+
setError(/* @__PURE__ */ new Error("No agent available to fetch resource"));
|
|
2178
|
+
setIsLoading(false);
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
fetchStateRef.current.inProgress = true;
|
|
2182
|
+
fetchStateRef.current.resourceUri = resourceUri;
|
|
2183
|
+
const fetchPromise = (async () => {
|
|
2184
|
+
try {
|
|
2185
|
+
const resource = (await mcpAppsRequestQueue.enqueue(agent, () => agent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
2186
|
+
serverHash,
|
|
2187
|
+
serverId,
|
|
2188
|
+
method: "resources/read",
|
|
2189
|
+
params: { uri: resourceUri }
|
|
2190
|
+
} } }))).result?.contents?.[0];
|
|
2191
|
+
if (!resource) throw new Error("No resource content in response");
|
|
2192
|
+
return resource;
|
|
2193
|
+
} catch (err) {
|
|
2194
|
+
console.error("[MCPAppsRenderer] Failed to fetch resource:", err);
|
|
2195
|
+
throw err;
|
|
2196
|
+
} finally {
|
|
2197
|
+
fetchStateRef.current.inProgress = false;
|
|
2413
2198
|
}
|
|
2414
|
-
sandboxReadyRef.current = false;
|
|
2415
|
-
setAutoHeight(null);
|
|
2416
|
-
};
|
|
2417
|
-
}, [
|
|
2418
|
-
fullHtml,
|
|
2419
|
-
css,
|
|
2420
|
-
localApi
|
|
2421
|
-
]);
|
|
2422
|
-
useEffect(() => {
|
|
2423
|
-
if (!content.jsFunctions || jsFunctionsInjectedRef.current) return;
|
|
2424
|
-
jsFunctionsInjectedRef.current = true;
|
|
2425
|
-
const sandbox = sandboxRef.current;
|
|
2426
|
-
if (sandboxReadyRef.current && sandbox) sandbox.run(content.jsFunctions);
|
|
2427
|
-
else pendingQueueRef.current.push(content.jsFunctions);
|
|
2428
|
-
}, [content.jsFunctions]);
|
|
2429
|
-
useEffect(() => {
|
|
2430
|
-
const expressions = content.jsExpressions;
|
|
2431
|
-
if (!expressions || expressions.length === 0) return;
|
|
2432
|
-
const startIndex = executedIndexRef.current;
|
|
2433
|
-
if (startIndex >= expressions.length) return;
|
|
2434
|
-
const newExprs = expressions.slice(startIndex);
|
|
2435
|
-
executedIndexRef.current = expressions.length;
|
|
2436
|
-
const sandbox = sandboxRef.current;
|
|
2437
|
-
if (sandboxReadyRef.current && sandbox) (async () => {
|
|
2438
|
-
for (const expr of newExprs) await sandbox.run(expr);
|
|
2439
2199
|
})();
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
if (!generationDone || !sandbox) return;
|
|
2446
|
-
let handled = false;
|
|
2447
|
-
const onMessage = (e) => {
|
|
2448
|
-
if (handled) return;
|
|
2449
|
-
if (e.source === sandbox.iframe.contentWindow && e.data?.type === "__ck_resize") {
|
|
2450
|
-
handled = true;
|
|
2451
|
-
setAutoHeight(e.data.height);
|
|
2452
|
-
window.removeEventListener("message", onMessage);
|
|
2200
|
+
fetchStateRef.current.promise = fetchPromise;
|
|
2201
|
+
fetchPromise.then((resource) => {
|
|
2202
|
+
if (resource) {
|
|
2203
|
+
setFetchedResource(resource);
|
|
2204
|
+
setIsLoading(false);
|
|
2453
2205
|
}
|
|
2454
|
-
}
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
s.textContent = 'body { height: auto !important; min-height: 0 !important; }';
|
|
2460
|
-
document.head.appendChild(s);
|
|
2461
|
-
var h = document.body.scrollHeight;
|
|
2462
|
-
var cs = getComputedStyle(document.body);
|
|
2463
|
-
h += parseFloat(cs.marginTop) || 0;
|
|
2464
|
-
h += parseFloat(cs.marginBottom) || 0;
|
|
2465
|
-
s.remove();
|
|
2466
|
-
parent.postMessage({ type: "__ck_resize", height: Math.ceil(h) }, "*");
|
|
2467
|
-
})();
|
|
2468
|
-
`;
|
|
2469
|
-
if (sandboxReadyRef.current) sandbox.run(measureOnce);
|
|
2470
|
-
else pendingQueueRef.current.push(measureOnce);
|
|
2471
|
-
return () => {
|
|
2472
|
-
window.removeEventListener("message", onMessage);
|
|
2473
|
-
};
|
|
2474
|
-
}, [generationDone]);
|
|
2475
|
-
const height = autoHeight ?? initialHeight;
|
|
2476
|
-
const isGenerating = content.generating !== false;
|
|
2477
|
-
return /* @__PURE__ */ jsx("div", {
|
|
2478
|
-
ref: containerRef,
|
|
2479
|
-
style: {
|
|
2480
|
-
position: "relative",
|
|
2481
|
-
width: "100%",
|
|
2482
|
-
height: `${height}px`,
|
|
2483
|
-
borderRadius: "8px",
|
|
2484
|
-
backgroundColor: hasVisibleSandbox ? "transparent" : "#f5f5f5",
|
|
2485
|
-
border: hasVisibleSandbox ? "none" : "1px solid #e0e0e0",
|
|
2486
|
-
display: hasVisibleSandbox ? "block" : "flex",
|
|
2487
|
-
alignItems: hasVisibleSandbox ? void 0 : "center",
|
|
2488
|
-
justifyContent: hasVisibleSandbox ? void 0 : "center",
|
|
2489
|
-
overflow: "hidden"
|
|
2490
|
-
},
|
|
2491
|
-
children: isGenerating && /* @__PURE__ */ jsxs("div", {
|
|
2492
|
-
style: {
|
|
2493
|
-
position: "absolute",
|
|
2494
|
-
inset: 0,
|
|
2495
|
-
zIndex: 10,
|
|
2496
|
-
pointerEvents: "all",
|
|
2497
|
-
backgroundColor: "rgba(255, 255, 255, 0.5)",
|
|
2498
|
-
display: "flex",
|
|
2499
|
-
alignItems: "center",
|
|
2500
|
-
justifyContent: "center"
|
|
2501
|
-
},
|
|
2502
|
-
children: [/* @__PURE__ */ jsxs("svg", {
|
|
2503
|
-
width: "48",
|
|
2504
|
-
height: "48",
|
|
2505
|
-
viewBox: "0 0 24 24",
|
|
2506
|
-
fill: "none",
|
|
2507
|
-
style: { animation: "ck-spin 1s linear infinite" },
|
|
2508
|
-
children: [/* @__PURE__ */ jsx("circle", {
|
|
2509
|
-
cx: "12",
|
|
2510
|
-
cy: "12",
|
|
2511
|
-
r: "10",
|
|
2512
|
-
stroke: "#e0e0e0",
|
|
2513
|
-
strokeWidth: "3"
|
|
2514
|
-
}), /* @__PURE__ */ jsx("path", {
|
|
2515
|
-
d: "M12 2a10 10 0 0 1 10 10",
|
|
2516
|
-
stroke: "#999",
|
|
2517
|
-
strokeWidth: "3",
|
|
2518
|
-
strokeLinecap: "round"
|
|
2519
|
-
})]
|
|
2520
|
-
}), /* @__PURE__ */ jsx("style", { children: `@keyframes ck-spin { to { transform: rotate(360deg) } }` })]
|
|
2521
|
-
})
|
|
2522
|
-
});
|
|
2523
|
-
}, (prev, next) => prev.content === next.content);
|
|
2524
|
-
/**
|
|
2525
|
-
* Frontend tool renderer for generateSandboxedUi.
|
|
2526
|
-
* Displays placeholder messages while the UI is being generated.
|
|
2527
|
-
*/
|
|
2528
|
-
const OpenGenerativeUIToolRenderer = function OpenGenerativeUIToolRenderer(props) {
|
|
2529
|
-
const [visibleMessageIndex, setVisibleMessageIndex] = useState(0);
|
|
2530
|
-
const prevMessageCountRef = useRef(0);
|
|
2531
|
-
const messages = props.args.placeholderMessages;
|
|
2206
|
+
}).catch((err) => {
|
|
2207
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2208
|
+
setIsLoading(false);
|
|
2209
|
+
});
|
|
2210
|
+
}, [agent, content]);
|
|
2532
2211
|
useEffect(() => {
|
|
2533
|
-
if (
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
}
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2212
|
+
if (isLoading || !fetchedResource) return;
|
|
2213
|
+
const container = containerRef.current;
|
|
2214
|
+
if (!container) return;
|
|
2215
|
+
let mounted = true;
|
|
2216
|
+
let messageHandler = null;
|
|
2217
|
+
let initialListener = null;
|
|
2218
|
+
let createdIframe = null;
|
|
2219
|
+
const setup = async () => {
|
|
2220
|
+
try {
|
|
2221
|
+
const iframe = document.createElement("iframe");
|
|
2222
|
+
createdIframe = iframe;
|
|
2223
|
+
iframe.style.width = "100%";
|
|
2224
|
+
iframe.style.height = "100px";
|
|
2225
|
+
iframe.style.border = "none";
|
|
2226
|
+
iframe.style.backgroundColor = "transparent";
|
|
2227
|
+
iframe.style.display = "block";
|
|
2228
|
+
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
|
|
2229
|
+
const sandboxReady = new Promise((resolve) => {
|
|
2230
|
+
initialListener = (event) => {
|
|
2231
|
+
if (event.source === iframe.contentWindow) {
|
|
2232
|
+
if (event.data?.method === "ui/notifications/sandbox-proxy-ready") {
|
|
2233
|
+
if (initialListener) {
|
|
2234
|
+
window.removeEventListener("message", initialListener);
|
|
2235
|
+
initialListener = null;
|
|
2236
|
+
}
|
|
2237
|
+
resolve();
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
};
|
|
2241
|
+
window.addEventListener("message", initialListener);
|
|
2242
|
+
});
|
|
2243
|
+
if (!mounted) {
|
|
2244
|
+
if (initialListener) {
|
|
2245
|
+
window.removeEventListener("message", initialListener);
|
|
2246
|
+
initialListener = null;
|
|
2247
|
+
}
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
const cspDomains = fetchedResource._meta?.ui?.csp?.resourceDomains;
|
|
2251
|
+
iframe.srcdoc = buildSandboxHTML(cspDomains);
|
|
2252
|
+
iframeRef.current = iframe;
|
|
2253
|
+
container.appendChild(iframe);
|
|
2254
|
+
await sandboxReady;
|
|
2255
|
+
if (!mounted) return;
|
|
2256
|
+
console.log("[MCPAppsRenderer] Sandbox proxy ready");
|
|
2257
|
+
messageHandler = async (event) => {
|
|
2258
|
+
if (event.source !== iframe.contentWindow) return;
|
|
2259
|
+
const msg = event.data;
|
|
2260
|
+
if (!msg || typeof msg !== "object" || msg.jsonrpc !== "2.0") return;
|
|
2261
|
+
console.log("[MCPAppsRenderer] Received from iframe:", msg);
|
|
2262
|
+
if (isRequest(msg)) switch (msg.method) {
|
|
2263
|
+
case "ui/initialize":
|
|
2264
|
+
sendResponse(msg.id, {
|
|
2265
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
2266
|
+
hostInfo: {
|
|
2267
|
+
name: "CopilotKit MCP Apps Host",
|
|
2268
|
+
version: "1.0.0"
|
|
2269
|
+
},
|
|
2270
|
+
hostCapabilities: {
|
|
2271
|
+
openLinks: {},
|
|
2272
|
+
logging: {}
|
|
2273
|
+
},
|
|
2274
|
+
hostContext: {
|
|
2275
|
+
theme: "light",
|
|
2276
|
+
platform: "web"
|
|
2277
|
+
}
|
|
2278
|
+
});
|
|
2279
|
+
break;
|
|
2280
|
+
case "ui/message": {
|
|
2281
|
+
const currentAgent = agentRef.current;
|
|
2282
|
+
if (!currentAgent) {
|
|
2283
|
+
console.warn("[MCPAppsRenderer] ui/message: No agent available");
|
|
2284
|
+
sendResponse(msg.id, { isError: false });
|
|
2285
|
+
break;
|
|
2286
|
+
}
|
|
2287
|
+
try {
|
|
2288
|
+
const params = msg.params;
|
|
2289
|
+
const role = params.role || "user";
|
|
2290
|
+
const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
|
|
2291
|
+
if (textContent) currentAgent.addMessage({
|
|
2292
|
+
id: crypto.randomUUID(),
|
|
2293
|
+
role,
|
|
2294
|
+
content: textContent
|
|
2295
|
+
});
|
|
2296
|
+
sendResponse(msg.id, { isError: false });
|
|
2297
|
+
if ((params.followUp ?? role === "user") && textContent) mcpAppsRequestQueue.enqueue(currentAgent, () => copilotkit.runAgent({ agent: currentAgent })).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
|
|
2298
|
+
} catch (err) {
|
|
2299
|
+
console.error("[MCPAppsRenderer] ui/message error:", err);
|
|
2300
|
+
sendResponse(msg.id, { isError: true });
|
|
2301
|
+
}
|
|
2302
|
+
break;
|
|
2303
|
+
}
|
|
2304
|
+
case "ui/open-link": {
|
|
2305
|
+
const url = msg.params?.url;
|
|
2306
|
+
if (url) {
|
|
2307
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
2308
|
+
sendResponse(msg.id, { isError: false });
|
|
2309
|
+
} else sendErrorResponse(msg.id, -32602, "Missing url parameter");
|
|
2310
|
+
break;
|
|
2311
|
+
}
|
|
2312
|
+
case "tools/call": {
|
|
2313
|
+
const { serverHash, serverId } = contentRef.current;
|
|
2314
|
+
const currentAgent = agentRef.current;
|
|
2315
|
+
if (!serverHash) {
|
|
2316
|
+
sendErrorResponse(msg.id, -32603, "No server hash available for proxying");
|
|
2317
|
+
break;
|
|
2318
|
+
}
|
|
2319
|
+
if (!currentAgent) {
|
|
2320
|
+
sendErrorResponse(msg.id, -32603, "No agent available for proxying");
|
|
2321
|
+
break;
|
|
2322
|
+
}
|
|
2323
|
+
try {
|
|
2324
|
+
const runResult = await mcpAppsRequestQueue.enqueue(currentAgent, () => currentAgent.runAgent({ forwardedProps: { __proxiedMCPRequest: {
|
|
2325
|
+
serverHash,
|
|
2326
|
+
serverId,
|
|
2327
|
+
method: "tools/call",
|
|
2328
|
+
params: msg.params
|
|
2329
|
+
} } }));
|
|
2330
|
+
sendResponse(msg.id, runResult.result || {});
|
|
2331
|
+
} catch (err) {
|
|
2332
|
+
console.error("[MCPAppsRenderer] tools/call error:", err);
|
|
2333
|
+
sendErrorResponse(msg.id, -32603, String(err));
|
|
2334
|
+
}
|
|
2335
|
+
break;
|
|
2336
|
+
}
|
|
2337
|
+
default: sendErrorResponse(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
2338
|
+
}
|
|
2339
|
+
if (isNotification(msg)) switch (msg.method) {
|
|
2340
|
+
case "ui/notifications/initialized":
|
|
2341
|
+
console.log("[MCPAppsRenderer] Inner iframe initialized");
|
|
2342
|
+
if (mounted) setIframeReady(true);
|
|
2343
|
+
break;
|
|
2344
|
+
case "ui/notifications/size-changed": {
|
|
2345
|
+
const { width, height } = msg.params || {};
|
|
2346
|
+
console.log("[MCPAppsRenderer] Size change:", {
|
|
2347
|
+
width,
|
|
2348
|
+
height
|
|
2349
|
+
});
|
|
2350
|
+
if (mounted) setIframeSize({
|
|
2351
|
+
width: typeof width === "number" ? width : void 0,
|
|
2352
|
+
height: typeof height === "number" ? height : void 0
|
|
2353
|
+
});
|
|
2354
|
+
break;
|
|
2355
|
+
}
|
|
2356
|
+
case "notifications/message":
|
|
2357
|
+
console.log("[MCPAppsRenderer] App log:", msg.params);
|
|
2358
|
+
break;
|
|
2359
|
+
}
|
|
2360
|
+
};
|
|
2361
|
+
window.addEventListener("message", messageHandler);
|
|
2362
|
+
let html;
|
|
2363
|
+
if (fetchedResource.text) html = fetchedResource.text;
|
|
2364
|
+
else if (fetchedResource.blob) html = atob(fetchedResource.blob);
|
|
2365
|
+
else throw new Error("Resource has no text or blob content");
|
|
2366
|
+
sendNotification("ui/notifications/sandbox-resource-ready", { html });
|
|
2367
|
+
} catch (err) {
|
|
2368
|
+
console.error("[MCPAppsRenderer] Setup error:", err);
|
|
2369
|
+
if (mounted) setError(err instanceof Error ? err : new Error(String(err)));
|
|
2370
|
+
}
|
|
2371
|
+
};
|
|
2372
|
+
setup();
|
|
2373
|
+
return () => {
|
|
2374
|
+
mounted = false;
|
|
2375
|
+
if (initialListener) {
|
|
2376
|
+
window.removeEventListener("message", initialListener);
|
|
2377
|
+
initialListener = null;
|
|
2378
|
+
}
|
|
2379
|
+
if (messageHandler) window.removeEventListener("message", messageHandler);
|
|
2380
|
+
if (createdIframe) {
|
|
2381
|
+
createdIframe.remove();
|
|
2382
|
+
createdIframe = null;
|
|
2383
|
+
}
|
|
2384
|
+
iframeRef.current = null;
|
|
2385
|
+
};
|
|
2386
|
+
}, [
|
|
2387
|
+
isLoading,
|
|
2388
|
+
fetchedResource,
|
|
2389
|
+
sendNotification,
|
|
2390
|
+
sendResponse,
|
|
2391
|
+
sendErrorResponse
|
|
2392
|
+
]);
|
|
2393
|
+
useEffect(() => {
|
|
2394
|
+
if (iframeRef.current) {
|
|
2395
|
+
if (iframeSize.width !== void 0) {
|
|
2396
|
+
iframeRef.current.style.minWidth = `min(${iframeSize.width}px, 100%)`;
|
|
2397
|
+
iframeRef.current.style.width = "100%";
|
|
2398
|
+
}
|
|
2399
|
+
if (iframeSize.height !== void 0) iframeRef.current.style.height = `${iframeSize.height}px`;
|
|
2400
|
+
}
|
|
2401
|
+
}, [iframeSize]);
|
|
2402
|
+
useEffect(() => {
|
|
2403
|
+
if (iframeReady && content.toolInput) {
|
|
2404
|
+
console.log("[MCPAppsRenderer] Sending tool input:", content.toolInput);
|
|
2405
|
+
sendNotification("ui/notifications/tool-input", { arguments: content.toolInput });
|
|
2406
|
+
}
|
|
2407
|
+
}, [
|
|
2408
|
+
iframeReady,
|
|
2409
|
+
content.toolInput,
|
|
2410
|
+
sendNotification
|
|
2411
|
+
]);
|
|
2412
|
+
useEffect(() => {
|
|
2413
|
+
if (iframeReady && content.result) {
|
|
2414
|
+
console.log("[MCPAppsRenderer] Sending tool result:", content.result);
|
|
2415
|
+
sendNotification("ui/notifications/tool-result", content.result);
|
|
2416
|
+
}
|
|
2417
|
+
}, [
|
|
2418
|
+
iframeReady,
|
|
2419
|
+
content.result,
|
|
2420
|
+
sendNotification
|
|
2421
|
+
]);
|
|
2422
|
+
const borderStyle = fetchedResource?._meta?.ui?.prefersBorder === true ? {
|
|
2423
|
+
borderRadius: "8px",
|
|
2424
|
+
backgroundColor: "#f9f9f9",
|
|
2425
|
+
border: "1px solid #e0e0e0"
|
|
2426
|
+
} : {};
|
|
2427
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2428
|
+
ref: containerRef,
|
|
2429
|
+
style: {
|
|
2430
|
+
width: "100%",
|
|
2431
|
+
height: iframeSize.height ? `${iframeSize.height}px` : "auto",
|
|
2432
|
+
minHeight: "100px",
|
|
2433
|
+
overflow: "hidden",
|
|
2434
|
+
position: "relative",
|
|
2435
|
+
...borderStyle
|
|
2436
|
+
},
|
|
2437
|
+
children: [isLoading && /* @__PURE__ */ jsx("div", {
|
|
2438
|
+
style: {
|
|
2439
|
+
padding: "1rem",
|
|
2440
|
+
color: "#666"
|
|
2441
|
+
},
|
|
2442
|
+
children: "Loading..."
|
|
2443
|
+
}), error && /* @__PURE__ */ jsxs("div", {
|
|
2444
|
+
style: {
|
|
2445
|
+
color: "red",
|
|
2446
|
+
padding: "1rem"
|
|
2447
|
+
},
|
|
2448
|
+
children: ["Error: ", error.message]
|
|
2449
|
+
})]
|
|
2450
|
+
});
|
|
2451
|
+
};
|
|
2452
|
+
|
|
2453
|
+
//#endregion
|
|
2454
|
+
//#region src/v2/providers/SandboxFunctionsContext.ts
|
|
2455
|
+
const SandboxFunctionsContext = createContext([]);
|
|
2456
|
+
function useSandboxFunctions() {
|
|
2457
|
+
return useContext(SandboxFunctionsContext);
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
//#endregion
|
|
2461
|
+
//#region src/v2/lib/processPartialHtml.ts
|
|
2462
|
+
/**
|
|
2463
|
+
* Extracts all complete `<style>` blocks from the raw HTML.
|
|
2464
|
+
* Returns the concatenated style tags, suitable for injection into `<head>`.
|
|
2465
|
+
*/
|
|
2466
|
+
function extractCompleteStyles(html) {
|
|
2467
|
+
const matches = html.match(/<style\b[^>]*>[\s\S]*?<\/style>/gi);
|
|
2468
|
+
return matches ? matches.join("") : "";
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* Processes raw accumulated HTML for safe preview via innerHTML injection.
|
|
2472
|
+
* Pure function, no DOM dependencies.
|
|
2473
|
+
*
|
|
2474
|
+
* Pipeline (order matters):
|
|
2475
|
+
* 1. Strip incomplete tag at end
|
|
2476
|
+
* 2. Strip complete <style>, <script>, and <head> blocks
|
|
2477
|
+
* 3. Strip incomplete <style>/<script>/<head> blocks
|
|
2478
|
+
* 4. Strip incomplete HTML entities
|
|
2479
|
+
* 5. Extract body content (or use full string if no <body>)
|
|
2480
|
+
*/
|
|
2481
|
+
function processPartialHtml(html) {
|
|
2482
|
+
let result = html;
|
|
2483
|
+
result = result.replace(/<[^>]*$/, "");
|
|
2484
|
+
result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*?<\/\1>/gi, "");
|
|
2485
|
+
result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*$/gi, "");
|
|
2486
|
+
result = result.replace(/&[a-zA-Z0-9#]*$/, "");
|
|
2487
|
+
const bodyMatch = result.match(/<body[^>]*>([\s\S]*)/i);
|
|
2488
|
+
if (bodyMatch) {
|
|
2489
|
+
result = bodyMatch[1];
|
|
2490
|
+
result = result.replace(/<\/body>[\s\S]*/i, "");
|
|
2491
|
+
}
|
|
2492
|
+
return result;
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
//#endregion
|
|
2496
|
+
//#region src/v2/components/OpenGenerativeUIRenderer.tsx
|
|
2497
|
+
const OpenGenerativeUIActivityType = "open-generative-ui";
|
|
2498
|
+
const OpenGenerativeUIContentSchema = z.object({
|
|
2499
|
+
initialHeight: z.number().optional(),
|
|
2500
|
+
generating: z.boolean().optional(),
|
|
2501
|
+
css: z.string().optional(),
|
|
2502
|
+
cssComplete: z.boolean().optional(),
|
|
2503
|
+
html: z.array(z.string()).optional(),
|
|
2504
|
+
htmlComplete: z.boolean().optional(),
|
|
2505
|
+
jsFunctions: z.string().optional(),
|
|
2506
|
+
jsFunctionsComplete: z.boolean().optional(),
|
|
2507
|
+
jsExpressions: z.array(z.string()).optional(),
|
|
2508
|
+
jsExpressionsComplete: z.boolean().optional()
|
|
2509
|
+
});
|
|
2510
|
+
/**
|
|
2511
|
+
* Schema for the generateSandboxedUi tool call arguments.
|
|
2512
|
+
* Used by the frontend tool renderer to display placeholder messages.
|
|
2513
|
+
*/
|
|
2514
|
+
const GenerateSandboxedUiArgsSchema = z.object({
|
|
2515
|
+
initialHeight: z.number().optional(),
|
|
2516
|
+
placeholderMessages: z.array(z.string()).optional(),
|
|
2517
|
+
css: z.string().optional(),
|
|
2518
|
+
html: z.string().optional(),
|
|
2519
|
+
jsFunctions: z.string().optional(),
|
|
2520
|
+
jsExpressions: z.array(z.string()).optional()
|
|
2521
|
+
});
|
|
2522
|
+
const THROTTLE_MS = 1e3;
|
|
2523
|
+
/**
|
|
2524
|
+
* Returns true when the inner component should re-render immediately
|
|
2525
|
+
* (no throttle delay).
|
|
2526
|
+
*/
|
|
2527
|
+
function shouldFlushImmediately(prev, next) {
|
|
2528
|
+
if (next.cssComplete && (!prev || !prev.cssComplete)) return true;
|
|
2529
|
+
if (next.htmlComplete) return true;
|
|
2530
|
+
if (next.generating === false) return true;
|
|
2531
|
+
if (next.jsFunctions && (!prev || !prev.jsFunctions)) return true;
|
|
2532
|
+
if ((next.jsExpressions?.length ?? 0) > (prev?.jsExpressions?.length ?? 0)) return true;
|
|
2533
|
+
if (next.html?.length && (!prev || !prev.html?.length)) return true;
|
|
2534
|
+
return false;
|
|
2535
|
+
}
|
|
2536
|
+
/**
|
|
2537
|
+
* Outer wrapper — absorbs every parent re-render but only forwards
|
|
2538
|
+
* throttled content snapshots to the memoized inner component.
|
|
2539
|
+
*/
|
|
2540
|
+
const OpenGenerativeUIActivityRenderer = function OpenGenerativeUIActivityRenderer({ content }) {
|
|
2541
|
+
const latestContentRef = useRef(content);
|
|
2542
|
+
latestContentRef.current = content;
|
|
2543
|
+
const [throttledContent, setThrottledContent] = useState(content);
|
|
2544
|
+
const throttledContentRef = useRef(throttledContent);
|
|
2545
|
+
const timerRef = useRef(null);
|
|
2546
|
+
if (throttledContentRef.current !== content) {
|
|
2547
|
+
if (shouldFlushImmediately(throttledContentRef.current, content)) {
|
|
2548
|
+
if (timerRef.current !== null) {
|
|
2549
|
+
clearTimeout(timerRef.current);
|
|
2550
|
+
timerRef.current = null;
|
|
2551
|
+
}
|
|
2552
|
+
throttledContentRef.current = content;
|
|
2553
|
+
setThrottledContent(content);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
const flush = useCallback(() => {
|
|
2557
|
+
timerRef.current = null;
|
|
2558
|
+
const latest = latestContentRef.current;
|
|
2559
|
+
throttledContentRef.current = latest;
|
|
2560
|
+
setThrottledContent(latest);
|
|
2561
|
+
}, []);
|
|
2562
|
+
useEffect(() => {
|
|
2563
|
+
if (throttledContentRef.current === content) return;
|
|
2564
|
+
if (timerRef.current === null) timerRef.current = setTimeout(flush, THROTTLE_MS);
|
|
2565
|
+
}, [content, flush]);
|
|
2566
|
+
useEffect(() => {
|
|
2567
|
+
return () => {
|
|
2568
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2569
|
+
};
|
|
2570
|
+
}, []);
|
|
2571
|
+
return /* @__PURE__ */ jsx(OpenGenerativeUIActivityRendererInner, { content: throttledContent });
|
|
2572
|
+
};
|
|
2573
|
+
function ensureHead(html) {
|
|
2574
|
+
if (/<head[\s>]/i.test(html)) return html;
|
|
2575
|
+
return `<head></head>${html}`;
|
|
2576
|
+
}
|
|
2577
|
+
function injectCssIntoHtml(html, css) {
|
|
2578
|
+
const headCloseIdx = html.indexOf("</head>");
|
|
2579
|
+
if (headCloseIdx !== -1) return html.slice(0, headCloseIdx) + `<style>${css}</style>` + html.slice(headCloseIdx);
|
|
2580
|
+
return `<head><style>${css}</style></head>${html}`;
|
|
2581
|
+
}
|
|
2582
|
+
const OpenGenerativeUIActivityRendererInner = React.memo(function OpenGenerativeUIActivityRendererInner({ content }) {
|
|
2583
|
+
const initialHeight = content.initialHeight ?? 200;
|
|
2584
|
+
const [autoHeight, setAutoHeight] = useState(null);
|
|
2585
|
+
const sandboxFunctions = useSandboxFunctions();
|
|
2586
|
+
const localApi = useMemo(() => {
|
|
2587
|
+
const api = {};
|
|
2588
|
+
for (const fn of sandboxFunctions) api[fn.name] = fn.handler;
|
|
2589
|
+
return api;
|
|
2590
|
+
}, [sandboxFunctions]);
|
|
2591
|
+
const fullHtml = content.htmlComplete && content.html?.length ? content.html.join("") : void 0;
|
|
2592
|
+
const css = content.cssComplete ? content.css : void 0;
|
|
2593
|
+
const cssReady = !!content.cssComplete;
|
|
2594
|
+
const partialHtml = !content.htmlComplete && content.html?.length ? content.html.join("") : void 0;
|
|
2595
|
+
const previewBody = partialHtml ? processPartialHtml(partialHtml) : void 0;
|
|
2596
|
+
const previewStyles = partialHtml ? extractCompleteStyles(partialHtml) : "";
|
|
2597
|
+
const hasPreview = cssReady && !!previewBody?.trim();
|
|
2598
|
+
const hasVisibleSandbox = !!fullHtml || hasPreview;
|
|
2599
|
+
const containerRef = useRef(null);
|
|
2600
|
+
const sandboxRef = useRef(null);
|
|
2601
|
+
const previewSandboxRef = useRef(null);
|
|
2602
|
+
const previewReadyRef = useRef(false);
|
|
2603
|
+
const sandboxReadyRef = useRef(false);
|
|
2604
|
+
const executedIndexRef = useRef(0);
|
|
2605
|
+
const pendingQueueRef = useRef([]);
|
|
2606
|
+
const jsFunctionsInjectedRef = useRef(false);
|
|
2607
|
+
useEffect(() => {
|
|
2608
|
+
const container = containerRef.current;
|
|
2609
|
+
if (!container || fullHtml || !hasPreview || previewSandboxRef.current) return;
|
|
2610
|
+
let cancelled = false;
|
|
2611
|
+
import("@jetbrains/websandbox").then((mod) => {
|
|
2612
|
+
if (cancelled) return;
|
|
2613
|
+
const sandbox = (mod.default?.default ?? mod.default).create({}, {
|
|
2614
|
+
frameContainer: container,
|
|
2615
|
+
frameContent: "<head></head><body></body>",
|
|
2616
|
+
allowAdditionalAttributes: ""
|
|
2617
|
+
});
|
|
2618
|
+
previewSandboxRef.current = sandbox;
|
|
2619
|
+
sandbox.iframe.style.width = "100%";
|
|
2620
|
+
sandbox.iframe.style.height = "100%";
|
|
2621
|
+
sandbox.iframe.style.border = "none";
|
|
2622
|
+
sandbox.iframe.style.backgroundColor = "transparent";
|
|
2623
|
+
sandbox.promise.then(() => {
|
|
2624
|
+
if (cancelled) return;
|
|
2625
|
+
previewReadyRef.current = true;
|
|
2626
|
+
sandbox.run(`
|
|
2627
|
+
var s = document.createElement('style');
|
|
2628
|
+
s.textContent = 'html, body { overflow: hidden !important; }';
|
|
2629
|
+
document.head.appendChild(s);
|
|
2630
|
+
`);
|
|
2631
|
+
const headParts = [];
|
|
2632
|
+
if (css) headParts.push(`<style>${css}</style>`);
|
|
2633
|
+
if (previewStyles) headParts.push(previewStyles);
|
|
2634
|
+
if (headParts.length) sandbox.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
|
|
2635
|
+
if (previewBody) sandbox.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
|
|
2636
|
+
});
|
|
2637
|
+
}).catch((err) => {
|
|
2638
|
+
console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
|
|
2639
|
+
});
|
|
2640
|
+
return () => {
|
|
2641
|
+
cancelled = true;
|
|
2642
|
+
};
|
|
2643
|
+
}, [hasPreview, fullHtml]);
|
|
2644
|
+
useEffect(() => {
|
|
2645
|
+
if (!previewSandboxRef.current || !previewReadyRef.current) return;
|
|
2646
|
+
const headParts = [];
|
|
2647
|
+
if (css) headParts.push(`<style>${css}</style>`);
|
|
2648
|
+
if (previewStyles) headParts.push(previewStyles);
|
|
2649
|
+
if (headParts.length) previewSandboxRef.current.run(`document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`);
|
|
2650
|
+
if (!previewBody) return;
|
|
2651
|
+
previewSandboxRef.current.run(`document.body.innerHTML = ${JSON.stringify(previewBody)}`);
|
|
2652
|
+
}, [
|
|
2653
|
+
previewBody,
|
|
2654
|
+
previewStyles,
|
|
2655
|
+
css
|
|
2656
|
+
]);
|
|
2657
|
+
useEffect(() => {
|
|
2658
|
+
const container = containerRef.current;
|
|
2659
|
+
if (!container || !fullHtml) return;
|
|
2660
|
+
if (previewSandboxRef.current) {
|
|
2661
|
+
previewSandboxRef.current.destroy();
|
|
2662
|
+
previewSandboxRef.current = null;
|
|
2663
|
+
previewReadyRef.current = false;
|
|
2664
|
+
}
|
|
2665
|
+
let cancelled = false;
|
|
2666
|
+
executedIndexRef.current = 0;
|
|
2667
|
+
jsFunctionsInjectedRef.current = false;
|
|
2668
|
+
sandboxReadyRef.current = false;
|
|
2669
|
+
pendingQueueRef.current = [];
|
|
2670
|
+
const htmlContent = css ? injectCssIntoHtml(fullHtml, css) : fullHtml;
|
|
2671
|
+
import("@jetbrains/websandbox").then((mod) => {
|
|
2672
|
+
if (cancelled) return;
|
|
2673
|
+
const sandbox = (mod.default?.default ?? mod.default).create(localApi, {
|
|
2674
|
+
frameContainer: container,
|
|
2675
|
+
frameContent: ensureHead(htmlContent),
|
|
2676
|
+
allowAdditionalAttributes: ""
|
|
2677
|
+
});
|
|
2678
|
+
sandboxRef.current = sandbox;
|
|
2679
|
+
sandbox.iframe.style.width = "100%";
|
|
2680
|
+
sandbox.iframe.style.height = "100%";
|
|
2681
|
+
sandbox.iframe.style.border = "none";
|
|
2682
|
+
sandbox.iframe.style.backgroundColor = "transparent";
|
|
2683
|
+
sandbox.promise.then(() => {
|
|
2684
|
+
if (cancelled) return;
|
|
2685
|
+
sandboxReadyRef.current = true;
|
|
2686
|
+
sandbox.run(`
|
|
2687
|
+
var s = document.createElement('style');
|
|
2688
|
+
s.textContent = 'html, body { overflow: hidden !important; }';
|
|
2689
|
+
document.head.appendChild(s);
|
|
2690
|
+
`);
|
|
2691
|
+
const queue = pendingQueueRef.current;
|
|
2692
|
+
pendingQueueRef.current = [];
|
|
2693
|
+
for (const code of queue) sandbox.run(code);
|
|
2694
|
+
});
|
|
2695
|
+
}).catch((err) => {
|
|
2696
|
+
console.error("[OpenGenerativeUI] Failed to load sandbox module:", err);
|
|
2697
|
+
});
|
|
2698
|
+
return () => {
|
|
2699
|
+
cancelled = true;
|
|
2700
|
+
if (previewSandboxRef.current) {
|
|
2701
|
+
previewSandboxRef.current.destroy();
|
|
2702
|
+
previewSandboxRef.current = null;
|
|
2703
|
+
previewReadyRef.current = false;
|
|
2704
|
+
}
|
|
2705
|
+
if (sandboxRef.current) {
|
|
2706
|
+
sandboxRef.current.destroy();
|
|
2707
|
+
sandboxRef.current = null;
|
|
2708
|
+
}
|
|
2709
|
+
sandboxReadyRef.current = false;
|
|
2710
|
+
setAutoHeight(null);
|
|
2711
|
+
};
|
|
2712
|
+
}, [
|
|
2713
|
+
fullHtml,
|
|
2714
|
+
css,
|
|
2715
|
+
localApi
|
|
2716
|
+
]);
|
|
2717
|
+
useEffect(() => {
|
|
2718
|
+
if (!content.jsFunctions || jsFunctionsInjectedRef.current) return;
|
|
2719
|
+
jsFunctionsInjectedRef.current = true;
|
|
2720
|
+
const sandbox = sandboxRef.current;
|
|
2721
|
+
if (sandboxReadyRef.current && sandbox) sandbox.run(content.jsFunctions);
|
|
2722
|
+
else pendingQueueRef.current.push(content.jsFunctions);
|
|
2723
|
+
}, [content.jsFunctions]);
|
|
2724
|
+
useEffect(() => {
|
|
2725
|
+
const expressions = content.jsExpressions;
|
|
2726
|
+
if (!expressions || expressions.length === 0) return;
|
|
2727
|
+
const startIndex = executedIndexRef.current;
|
|
2728
|
+
if (startIndex >= expressions.length) return;
|
|
2729
|
+
const newExprs = expressions.slice(startIndex);
|
|
2730
|
+
executedIndexRef.current = expressions.length;
|
|
2731
|
+
const sandbox = sandboxRef.current;
|
|
2732
|
+
if (sandboxReadyRef.current && sandbox) (async () => {
|
|
2733
|
+
for (const expr of newExprs) await sandbox.run(expr);
|
|
2734
|
+
})();
|
|
2735
|
+
else pendingQueueRef.current.push(...newExprs);
|
|
2736
|
+
}, [content.jsExpressions?.length]);
|
|
2737
|
+
const generationDone = content.generating === false;
|
|
2738
|
+
useEffect(() => {
|
|
2739
|
+
const sandbox = sandboxRef.current;
|
|
2740
|
+
if (!generationDone || !sandbox) return;
|
|
2741
|
+
let handled = false;
|
|
2742
|
+
const onMessage = (e) => {
|
|
2743
|
+
if (handled) return;
|
|
2744
|
+
if (e.source === sandbox.iframe.contentWindow && e.data?.type === "__ck_resize") {
|
|
2745
|
+
handled = true;
|
|
2746
|
+
setAutoHeight(e.data.height);
|
|
2747
|
+
window.removeEventListener("message", onMessage);
|
|
2748
|
+
}
|
|
2749
|
+
};
|
|
2750
|
+
window.addEventListener("message", onMessage);
|
|
2751
|
+
const measureOnce = `
|
|
2752
|
+
(function() {
|
|
2753
|
+
var s = document.createElement('style');
|
|
2754
|
+
s.textContent = 'body { height: auto !important; min-height: 0 !important; }';
|
|
2755
|
+
document.head.appendChild(s);
|
|
2756
|
+
var h = document.body.scrollHeight;
|
|
2757
|
+
var cs = getComputedStyle(document.body);
|
|
2758
|
+
h += parseFloat(cs.marginTop) || 0;
|
|
2759
|
+
h += parseFloat(cs.marginBottom) || 0;
|
|
2760
|
+
s.remove();
|
|
2761
|
+
parent.postMessage({ type: "__ck_resize", height: Math.ceil(h) }, "*");
|
|
2762
|
+
})();
|
|
2763
|
+
`;
|
|
2764
|
+
if (sandboxReadyRef.current) sandbox.run(measureOnce);
|
|
2765
|
+
else pendingQueueRef.current.push(measureOnce);
|
|
2766
|
+
return () => {
|
|
2767
|
+
window.removeEventListener("message", onMessage);
|
|
2768
|
+
};
|
|
2769
|
+
}, [generationDone]);
|
|
2770
|
+
const height = autoHeight ?? initialHeight;
|
|
2771
|
+
const isGenerating = content.generating !== false;
|
|
2772
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2773
|
+
ref: containerRef,
|
|
2774
|
+
style: {
|
|
2775
|
+
position: "relative",
|
|
2776
|
+
width: "100%",
|
|
2777
|
+
height: `${height}px`,
|
|
2778
|
+
borderRadius: "8px",
|
|
2779
|
+
backgroundColor: hasVisibleSandbox ? "transparent" : "#f5f5f5",
|
|
2780
|
+
border: hasVisibleSandbox ? "none" : "1px solid #e0e0e0",
|
|
2781
|
+
display: hasVisibleSandbox ? "block" : "flex",
|
|
2782
|
+
alignItems: hasVisibleSandbox ? void 0 : "center",
|
|
2783
|
+
justifyContent: hasVisibleSandbox ? void 0 : "center",
|
|
2784
|
+
overflow: "hidden"
|
|
2785
|
+
},
|
|
2786
|
+
children: isGenerating && /* @__PURE__ */ jsxs("div", {
|
|
2787
|
+
style: {
|
|
2788
|
+
position: "absolute",
|
|
2789
|
+
inset: 0,
|
|
2790
|
+
zIndex: 10,
|
|
2791
|
+
pointerEvents: "all",
|
|
2792
|
+
backgroundColor: "rgba(255, 255, 255, 0.5)",
|
|
2793
|
+
display: "flex",
|
|
2794
|
+
alignItems: "center",
|
|
2795
|
+
justifyContent: "center"
|
|
2796
|
+
},
|
|
2797
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
2798
|
+
width: "48",
|
|
2799
|
+
height: "48",
|
|
2800
|
+
viewBox: "0 0 24 24",
|
|
2801
|
+
fill: "none",
|
|
2802
|
+
style: { animation: "ck-spin 1s linear infinite" },
|
|
2803
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
2804
|
+
cx: "12",
|
|
2805
|
+
cy: "12",
|
|
2806
|
+
r: "10",
|
|
2807
|
+
stroke: "#e0e0e0",
|
|
2808
|
+
strokeWidth: "3"
|
|
2809
|
+
}), /* @__PURE__ */ jsx("path", {
|
|
2810
|
+
d: "M12 2a10 10 0 0 1 10 10",
|
|
2811
|
+
stroke: "#999",
|
|
2812
|
+
strokeWidth: "3",
|
|
2813
|
+
strokeLinecap: "round"
|
|
2814
|
+
})]
|
|
2815
|
+
}), /* @__PURE__ */ jsx("style", { children: `@keyframes ck-spin { to { transform: rotate(360deg) } }` })]
|
|
2816
|
+
})
|
|
2817
|
+
});
|
|
2818
|
+
}, (prev, next) => prev.content === next.content);
|
|
2819
|
+
/**
|
|
2820
|
+
* Frontend tool renderer for generateSandboxedUi.
|
|
2821
|
+
* Displays placeholder messages while the UI is being generated.
|
|
2822
|
+
*/
|
|
2823
|
+
const OpenGenerativeUIToolRenderer = function OpenGenerativeUIToolRenderer(props) {
|
|
2824
|
+
const [visibleMessageIndex, setVisibleMessageIndex] = useState(0);
|
|
2825
|
+
const prevMessageCountRef = useRef(0);
|
|
2826
|
+
const messages = props.args.placeholderMessages;
|
|
2827
|
+
useEffect(() => {
|
|
2828
|
+
if (!messages || messages.length === 0) return;
|
|
2829
|
+
if (messages.length !== prevMessageCountRef.current) {
|
|
2830
|
+
prevMessageCountRef.current = messages.length;
|
|
2831
|
+
setVisibleMessageIndex(messages.length - 1);
|
|
2832
|
+
}
|
|
2833
|
+
if (props.status === ToolCallStatus.Complete) return;
|
|
2834
|
+
const timer = setInterval(() => {
|
|
2835
|
+
setVisibleMessageIndex((i) => (i + 1) % messages.length);
|
|
2836
|
+
}, 5e3);
|
|
2837
|
+
return () => clearInterval(timer);
|
|
2838
|
+
}, [messages?.length, props.status]);
|
|
2839
|
+
if (props.status === ToolCallStatus.Complete) return null;
|
|
2840
|
+
if (!messages || messages.length === 0) return null;
|
|
2841
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2842
|
+
style: {
|
|
2843
|
+
padding: "8px 12px",
|
|
2844
|
+
color: "#999",
|
|
2845
|
+
fontSize: "14px"
|
|
2846
|
+
},
|
|
2847
|
+
children: messages[visibleMessageIndex] ?? messages[0]
|
|
2848
|
+
});
|
|
2849
|
+
};
|
|
2850
|
+
|
|
2851
|
+
//#endregion
|
|
2852
|
+
//#region src/v2/a2ui/A2UIMessageRenderer.tsx
|
|
2853
|
+
/**
|
|
2854
|
+
* The container key used to wrap A2UI operations for explicit detection.
|
|
2855
|
+
* Must match A2UI_OPERATIONS_KEY in @ag-ui/a2ui-middleware and copilotkit.a2ui (Python).
|
|
2856
|
+
*/
|
|
2857
|
+
const A2UI_OPERATIONS_KEY = "a2ui_operations";
|
|
2858
|
+
let initialized = false;
|
|
2859
|
+
function ensureInitialized() {
|
|
2860
|
+
if (!initialized) {
|
|
2861
|
+
initializeDefaultCatalog();
|
|
2862
|
+
injectStyles();
|
|
2863
|
+
initialized = true;
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
function createA2UIMessageRenderer(options) {
|
|
2867
|
+
const { theme, catalog, loadingComponent } = options;
|
|
2868
|
+
return {
|
|
2869
|
+
activityType: "a2ui-surface",
|
|
2870
|
+
content: z.any(),
|
|
2871
|
+
render: ({ content, agent }) => {
|
|
2872
|
+
ensureInitialized();
|
|
2873
|
+
const [operations, setOperations] = useState([]);
|
|
2874
|
+
const { copilotkit } = useCopilotKit();
|
|
2580
2875
|
const lastContentRef = useRef(null);
|
|
2581
2876
|
useEffect(() => {
|
|
2582
2877
|
if (content === lastContentRef.current) return;
|
|
@@ -2728,18 +3023,6 @@ function getOperationSurfaceId(operation) {
|
|
|
2728
3023
|
return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
|
|
2729
3024
|
}
|
|
2730
3025
|
|
|
2731
|
-
//#endregion
|
|
2732
|
-
//#region src/v2/types/defineToolCallRenderer.ts
|
|
2733
|
-
function defineToolCallRenderer(def) {
|
|
2734
|
-
const argsSchema = def.name === "*" && !def.args ? z.any() : def.args;
|
|
2735
|
-
return {
|
|
2736
|
-
name: def.name,
|
|
2737
|
-
args: argsSchema,
|
|
2738
|
-
render: def.render,
|
|
2739
|
-
...def.agentId ? { agentId: def.agentId } : {}
|
|
2740
|
-
};
|
|
2741
|
-
}
|
|
2742
|
-
|
|
2743
3026
|
//#endregion
|
|
2744
3027
|
//#region src/v2/a2ui/A2UIToolCallRenderer.tsx
|
|
2745
3028
|
/**
|
|
@@ -3439,215 +3722,53 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
|
|
|
3439
3722
|
name: fn.name,
|
|
3440
3723
|
description: fn.description,
|
|
3441
3724
|
parameters: schemaToJsonSchema(fn.parameters, { zodToJsonSchema })
|
|
3442
|
-
})));
|
|
3443
|
-
}, [sandboxFunctionsList]);
|
|
3444
|
-
useLayoutEffect(() => {
|
|
3445
|
-
if (!copilotkit || !sandboxFunctionsDescriptors || !openGenUIActive) return;
|
|
3446
|
-
const id = copilotkit.addContext({
|
|
3447
|
-
description: "Sandbox functions available in generated sandboxed UI code. Call via: await Websandbox.connection.remote.<functionName>(args)",
|
|
3448
|
-
value: sandboxFunctionsDescriptors
|
|
3449
|
-
});
|
|
3450
|
-
return () => {
|
|
3451
|
-
copilotkit.removeContext(id);
|
|
3452
|
-
};
|
|
3453
|
-
}, [
|
|
3454
|
-
copilotkit,
|
|
3455
|
-
sandboxFunctionsDescriptors,
|
|
3456
|
-
openGenUIActive
|
|
3457
|
-
]);
|
|
3458
|
-
const contextValue = useMemo(() => ({
|
|
3459
|
-
copilotkit,
|
|
3460
|
-
executingToolCallIds
|
|
3461
|
-
}), [copilotkit, executingToolCallIds]);
|
|
3462
|
-
const licenseContextValue = useMemo(() => createLicenseContextValue(null), []);
|
|
3463
|
-
return /* @__PURE__ */ jsx(SandboxFunctionsContext.Provider, {
|
|
3464
|
-
value: sandboxFunctionsList,
|
|
3465
|
-
children: /* @__PURE__ */ jsx(CopilotKitContext.Provider, {
|
|
3466
|
-
value: contextValue,
|
|
3467
|
-
children: /* @__PURE__ */ jsxs(LicenseContext.Provider, {
|
|
3468
|
-
value: licenseContextValue,
|
|
3469
|
-
children: [
|
|
3470
|
-
runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UIBuiltInToolCallRenderer, {}),
|
|
3471
|
-
runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UICatalogContext, {
|
|
3472
|
-
catalog: a2ui?.catalog,
|
|
3473
|
-
includeSchema: a2ui?.includeSchema
|
|
3474
|
-
}),
|
|
3475
|
-
children,
|
|
3476
|
-
shouldRenderInspector ? /* @__PURE__ */ jsx(CopilotKitInspector, {
|
|
3477
|
-
core: copilotkit,
|
|
3478
|
-
defaultAnchor: inspectorDefaultAnchor
|
|
3479
|
-
}) : null,
|
|
3480
|
-
runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "no_license" }),
|
|
3481
|
-
runtimeLicenseStatus === "expired" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expired" }),
|
|
3482
|
-
runtimeLicenseStatus === "invalid" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "invalid" }),
|
|
3483
|
-
runtimeLicenseStatus === "expiring" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expiring" })
|
|
3484
|
-
]
|
|
3485
|
-
})
|
|
3486
|
-
})
|
|
3487
|
-
});
|
|
3488
|
-
};
|
|
3489
|
-
|
|
3490
|
-
//#endregion
|
|
3491
|
-
//#region src/v2/hooks/use-agent.tsx
|
|
3492
|
-
let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
|
|
3493
|
-
UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
|
|
3494
|
-
UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
|
|
3495
|
-
UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
|
|
3496
|
-
return UseAgentUpdate;
|
|
3497
|
-
}({});
|
|
3498
|
-
const ALL_UPDATES = [
|
|
3499
|
-
UseAgentUpdate.OnMessagesChanged,
|
|
3500
|
-
UseAgentUpdate.OnStateChanged,
|
|
3501
|
-
UseAgentUpdate.OnRunStatusChanged
|
|
3502
|
-
];
|
|
3503
|
-
/**
|
|
3504
|
-
* Clone a registry agent for per-thread isolation.
|
|
3505
|
-
* Copies agent configuration (transport, headers, etc.) but resets conversation
|
|
3506
|
-
* state (messages, threadId, state) so each thread starts fresh.
|
|
3507
|
-
*/
|
|
3508
|
-
function cloneForThread(source, threadId, headers) {
|
|
3509
|
-
const clone = source.clone();
|
|
3510
|
-
if (clone === source) throw new Error(`useAgent: ${source.constructor.name}.clone() returned the same instance. clone() must return a new, independent object.`);
|
|
3511
|
-
clone.threadId = threadId;
|
|
3512
|
-
clone.setMessages([]);
|
|
3513
|
-
clone.setState({});
|
|
3514
|
-
if (clone instanceof HttpAgent) clone.headers = { ...headers };
|
|
3515
|
-
return clone;
|
|
3516
|
-
}
|
|
3517
|
-
/**
|
|
3518
|
-
* Module-level WeakMap: registryAgent → (threadId → clone).
|
|
3519
|
-
* Shared across all useAgent() calls so that every component using the same
|
|
3520
|
-
* (agentId, threadId) pair receives the same agent instance. Using WeakMap
|
|
3521
|
-
* ensures the clone map is garbage-collected when the registry agent is
|
|
3522
|
-
* replaced (e.g. after reconnect or hot-reload).
|
|
3523
|
-
*/
|
|
3524
|
-
const globalThreadCloneMap = /* @__PURE__ */ new WeakMap();
|
|
3525
|
-
/**
|
|
3526
|
-
* Look up an existing per-thread clone without creating one.
|
|
3527
|
-
* Returns undefined when no clone has been created yet for this pair.
|
|
3528
|
-
*/
|
|
3529
|
-
function getThreadClone(registryAgent, threadId) {
|
|
3530
|
-
if (!registryAgent || !threadId) return void 0;
|
|
3531
|
-
return globalThreadCloneMap.get(registryAgent)?.get(threadId);
|
|
3532
|
-
}
|
|
3533
|
-
function getOrCreateThreadClone(existing, threadId, headers) {
|
|
3534
|
-
let byThread = globalThreadCloneMap.get(existing);
|
|
3535
|
-
if (!byThread) {
|
|
3536
|
-
byThread = /* @__PURE__ */ new Map();
|
|
3537
|
-
globalThreadCloneMap.set(existing, byThread);
|
|
3538
|
-
}
|
|
3539
|
-
const cached = byThread.get(threadId);
|
|
3540
|
-
if (cached) return cached;
|
|
3541
|
-
const clone = cloneForThread(existing, threadId, headers);
|
|
3542
|
-
byThread.set(threadId, clone);
|
|
3543
|
-
return clone;
|
|
3544
|
-
}
|
|
3545
|
-
function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
3546
|
-
agentId ??= DEFAULT_AGENT_ID;
|
|
3547
|
-
const { copilotkit } = useCopilotKit();
|
|
3548
|
-
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
3549
|
-
const chatConfig = useCopilotChatConfiguration();
|
|
3550
|
-
threadId ??= chatConfig?.threadId;
|
|
3551
|
-
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
3552
|
-
const updateFlags = useMemo(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
3553
|
-
const provisionalAgentCache = useRef(/* @__PURE__ */ new Map());
|
|
3554
|
-
const agent = useMemo(() => {
|
|
3555
|
-
const cacheKey = threadId ? `${agentId}:${threadId}` : agentId;
|
|
3556
|
-
const existing = copilotkit.getAgent(agentId);
|
|
3557
|
-
if (existing) {
|
|
3558
|
-
provisionalAgentCache.current.delete(cacheKey);
|
|
3559
|
-
provisionalAgentCache.current.delete(agentId);
|
|
3560
|
-
if (!threadId) return existing;
|
|
3561
|
-
return getOrCreateThreadClone(existing, threadId, copilotkit.headers);
|
|
3562
|
-
}
|
|
3563
|
-
const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
|
|
3564
|
-
const status = copilotkit.runtimeConnectionStatus;
|
|
3565
|
-
if (isRuntimeConfigured && (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
|
|
3566
|
-
const cached = provisionalAgentCache.current.get(cacheKey);
|
|
3567
|
-
if (cached) {
|
|
3568
|
-
cached.headers = { ...copilotkit.headers };
|
|
3569
|
-
return cached;
|
|
3570
|
-
}
|
|
3571
|
-
const provisional = new ProxiedCopilotRuntimeAgent({
|
|
3572
|
-
runtimeUrl: copilotkit.runtimeUrl,
|
|
3573
|
-
agentId,
|
|
3574
|
-
transport: copilotkit.runtimeTransport,
|
|
3575
|
-
runtimeMode: "pending"
|
|
3576
|
-
});
|
|
3577
|
-
provisional.headers = { ...copilotkit.headers };
|
|
3578
|
-
if (threadId) provisional.threadId = threadId;
|
|
3579
|
-
provisionalAgentCache.current.set(cacheKey, provisional);
|
|
3580
|
-
return provisional;
|
|
3581
|
-
}
|
|
3582
|
-
if (isRuntimeConfigured && status === CopilotKitCoreRuntimeConnectionStatus.Error) {
|
|
3583
|
-
const cached = provisionalAgentCache.current.get(cacheKey);
|
|
3584
|
-
if (cached) {
|
|
3585
|
-
cached.headers = { ...copilotkit.headers };
|
|
3586
|
-
return cached;
|
|
3587
|
-
}
|
|
3588
|
-
const provisional = new ProxiedCopilotRuntimeAgent({
|
|
3589
|
-
runtimeUrl: copilotkit.runtimeUrl,
|
|
3590
|
-
agentId,
|
|
3591
|
-
transport: copilotkit.runtimeTransport,
|
|
3592
|
-
runtimeMode: "pending"
|
|
3593
|
-
});
|
|
3594
|
-
provisional.headers = { ...copilotkit.headers };
|
|
3595
|
-
if (threadId) provisional.threadId = threadId;
|
|
3596
|
-
provisionalAgentCache.current.set(cacheKey, provisional);
|
|
3597
|
-
return provisional;
|
|
3598
|
-
}
|
|
3599
|
-
const knownAgents = Object.keys(copilotkit.agents ?? {});
|
|
3600
|
-
const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
|
|
3601
|
-
throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
|
|
3602
|
-
}, [
|
|
3603
|
-
agentId,
|
|
3604
|
-
threadId,
|
|
3605
|
-
copilotkit.agents,
|
|
3606
|
-
copilotkit.runtimeConnectionStatus,
|
|
3607
|
-
copilotkit.runtimeUrl,
|
|
3608
|
-
copilotkit.runtimeTransport,
|
|
3609
|
-
JSON.stringify(copilotkit.headers)
|
|
3610
|
-
]);
|
|
3611
|
-
useEffect(() => {
|
|
3612
|
-
if (updateFlags.length === 0) return;
|
|
3613
|
-
let active = true;
|
|
3614
|
-
const handlers = {};
|
|
3615
|
-
let batchScheduled = false;
|
|
3616
|
-
const batchedForceUpdate = () => {
|
|
3617
|
-
if (!active) return;
|
|
3618
|
-
if (!batchScheduled) {
|
|
3619
|
-
batchScheduled = true;
|
|
3620
|
-
queueMicrotask(() => {
|
|
3621
|
-
batchScheduled = false;
|
|
3622
|
-
if (active) forceUpdate();
|
|
3623
|
-
});
|
|
3624
|
-
}
|
|
3625
|
-
};
|
|
3626
|
-
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = batchedForceUpdate;
|
|
3627
|
-
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
|
|
3628
|
-
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
3629
|
-
handlers.onRunInitialized = batchedForceUpdate;
|
|
3630
|
-
handlers.onRunFinalized = batchedForceUpdate;
|
|
3631
|
-
handlers.onRunFailed = batchedForceUpdate;
|
|
3632
|
-
handlers.onRunErrorEvent = batchedForceUpdate;
|
|
3633
|
-
}
|
|
3634
|
-
const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
|
|
3725
|
+
})));
|
|
3726
|
+
}, [sandboxFunctionsList]);
|
|
3727
|
+
useLayoutEffect(() => {
|
|
3728
|
+
if (!copilotkit || !sandboxFunctionsDescriptors || !openGenUIActive) return;
|
|
3729
|
+
const id = copilotkit.addContext({
|
|
3730
|
+
description: "Sandbox functions available in generated sandboxed UI code. Call via: await Websandbox.connection.remote.<functionName>(args)",
|
|
3731
|
+
value: sandboxFunctionsDescriptors
|
|
3732
|
+
});
|
|
3635
3733
|
return () => {
|
|
3636
|
-
|
|
3637
|
-
subscription.unsubscribe();
|
|
3734
|
+
copilotkit.removeContext(id);
|
|
3638
3735
|
};
|
|
3639
3736
|
}, [
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
providerThrottleMs,
|
|
3644
|
-
updateFlags
|
|
3737
|
+
copilotkit,
|
|
3738
|
+
sandboxFunctionsDescriptors,
|
|
3739
|
+
openGenUIActive
|
|
3645
3740
|
]);
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3741
|
+
const contextValue = useMemo(() => ({
|
|
3742
|
+
copilotkit,
|
|
3743
|
+
executingToolCallIds
|
|
3744
|
+
}), [copilotkit, executingToolCallIds]);
|
|
3745
|
+
const licenseContextValue = useMemo(() => createLicenseContextValue(null), []);
|
|
3746
|
+
return /* @__PURE__ */ jsx(SandboxFunctionsContext.Provider, {
|
|
3747
|
+
value: sandboxFunctionsList,
|
|
3748
|
+
children: /* @__PURE__ */ jsx(CopilotKitContext.Provider, {
|
|
3749
|
+
value: contextValue,
|
|
3750
|
+
children: /* @__PURE__ */ jsxs(LicenseContext.Provider, {
|
|
3751
|
+
value: licenseContextValue,
|
|
3752
|
+
children: [
|
|
3753
|
+
runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UIBuiltInToolCallRenderer, {}),
|
|
3754
|
+
runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UICatalogContext, {
|
|
3755
|
+
catalog: a2ui?.catalog,
|
|
3756
|
+
includeSchema: a2ui?.includeSchema
|
|
3757
|
+
}),
|
|
3758
|
+
children,
|
|
3759
|
+
shouldRenderInspector ? /* @__PURE__ */ jsx(CopilotKitInspector, {
|
|
3760
|
+
core: copilotkit,
|
|
3761
|
+
defaultAnchor: inspectorDefaultAnchor
|
|
3762
|
+
}) : null,
|
|
3763
|
+
runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "no_license" }),
|
|
3764
|
+
runtimeLicenseStatus === "expired" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expired" }),
|
|
3765
|
+
runtimeLicenseStatus === "invalid" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "invalid" }),
|
|
3766
|
+
runtimeLicenseStatus === "expiring" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expiring" })
|
|
3767
|
+
]
|
|
3768
|
+
})
|
|
3769
|
+
})
|
|
3770
|
+
});
|
|
3771
|
+
};
|
|
3651
3772
|
|
|
3652
3773
|
//#endregion
|
|
3653
3774
|
//#region src/v2/hooks/use-render-custom-messages.tsx
|
|
@@ -3666,8 +3787,7 @@ function useRenderCustomMessages() {
|
|
|
3666
3787
|
const { message, position } = params;
|
|
3667
3788
|
const resolvedRunId = copilotkit.getRunIdForMessage(agentId, threadId, message.id) ?? copilotkit.getRunIdsForThread(agentId, threadId).slice(-1)[0];
|
|
3668
3789
|
const runId = resolvedRunId ?? `missing-run-id:${message.id}`;
|
|
3669
|
-
const
|
|
3670
|
-
const agent = getThreadClone(registryAgent, threadId) ?? registryAgent;
|
|
3790
|
+
const agent = copilotkit.getAgent(agentId);
|
|
3671
3791
|
if (!agent) return null;
|
|
3672
3792
|
const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
|
|
3673
3793
|
const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
|
|
@@ -3676,426 +3796,161 @@ function useRenderCustomMessages() {
|
|
|
3676
3796
|
const numberOfMessagesInRun = resolvedRunId ? messagesIdsInRun.length : 1;
|
|
3677
3797
|
const stateSnapshot = resolvedRunId ? copilotkit.getStateByRun(agentId, threadId, resolvedRunId) : void 0;
|
|
3678
3798
|
let result = null;
|
|
3679
|
-
for (const renderer of customMessageRenderers) {
|
|
3680
|
-
if (!renderer.render) continue;
|
|
3681
|
-
const Component = renderer.render;
|
|
3682
|
-
result = /* @__PURE__ */ jsx(Component, {
|
|
3683
|
-
message,
|
|
3684
|
-
position,
|
|
3685
|
-
runId,
|
|
3686
|
-
messageIndex,
|
|
3687
|
-
messageIndexInRun,
|
|
3688
|
-
numberOfMessagesInRun,
|
|
3689
|
-
agentId,
|
|
3690
|
-
stateSnapshot
|
|
3691
|
-
}, `${runId}-${message.id}-${position}`);
|
|
3692
|
-
if (result) break;
|
|
3693
|
-
}
|
|
3694
|
-
return result;
|
|
3695
|
-
};
|
|
3696
|
-
}
|
|
3697
|
-
|
|
3698
|
-
//#endregion
|
|
3699
|
-
//#region src/v2/hooks/use-render-activity-message.tsx
|
|
3700
|
-
function useRenderActivityMessage() {
|
|
3701
|
-
const { copilotkit } = useCopilotKit();
|
|
3702
|
-
const config = useCopilotChatConfiguration();
|
|
3703
|
-
const agentId = config?.agentId ?? DEFAULT_AGENT_ID;
|
|
3704
|
-
const renderers = copilotkit.renderActivityMessages;
|
|
3705
|
-
const findRenderer = useCallback((activityType) => {
|
|
3706
|
-
if (!renderers.length) return null;
|
|
3707
|
-
const matches = renderers.filter((renderer) => renderer.activityType === activityType);
|
|
3708
|
-
return matches.find((candidate) => candidate.agentId === agentId) ?? matches.find((candidate) => candidate.agentId === void 0) ?? renderers.find((candidate) => candidate.activityType === "*") ?? null;
|
|
3709
|
-
}, [agentId, renderers]);
|
|
3710
|
-
const renderActivityMessage = useCallback((message) => {
|
|
3711
|
-
const renderer = findRenderer(message.activityType);
|
|
3712
|
-
if (!renderer) return null;
|
|
3713
|
-
const parseResult = renderer.content.safeParse(message.content);
|
|
3714
|
-
if (!parseResult.success) {
|
|
3715
|
-
console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.error);
|
|
3716
|
-
return null;
|
|
3717
|
-
}
|
|
3718
|
-
const Component = renderer.render;
|
|
3719
|
-
const registryAgent = copilotkit.getAgent(agentId);
|
|
3720
|
-
const agent = getThreadClone(registryAgent, config?.threadId) ?? registryAgent;
|
|
3721
|
-
return /* @__PURE__ */ jsx(Component, {
|
|
3722
|
-
activityType: message.activityType,
|
|
3723
|
-
content: parseResult.data,
|
|
3724
|
-
message,
|
|
3725
|
-
agent
|
|
3726
|
-
}, message.id);
|
|
3727
|
-
}, [
|
|
3728
|
-
agentId,
|
|
3729
|
-
config?.threadId,
|
|
3730
|
-
copilotkit,
|
|
3731
|
-
findRenderer
|
|
3732
|
-
]);
|
|
3733
|
-
return useMemo(() => ({
|
|
3734
|
-
renderActivityMessage,
|
|
3735
|
-
findRenderer
|
|
3736
|
-
}), [renderActivityMessage, findRenderer]);
|
|
3737
|
-
}
|
|
3738
|
-
|
|
3739
|
-
//#endregion
|
|
3740
|
-
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
3741
|
-
const EMPTY_DEPS$1 = [];
|
|
3742
|
-
function useFrontendTool(tool, deps) {
|
|
3743
|
-
const { copilotkit } = useCopilotKit();
|
|
3744
|
-
const extraDeps = deps ?? EMPTY_DEPS$1;
|
|
3745
|
-
useEffect(() => {
|
|
3746
|
-
const name = tool.name;
|
|
3747
|
-
if (copilotkit.getTool({
|
|
3748
|
-
toolName: name,
|
|
3749
|
-
agentId: tool.agentId
|
|
3750
|
-
})) {
|
|
3751
|
-
console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
|
|
3752
|
-
copilotkit.removeTool(name, tool.agentId);
|
|
3753
|
-
}
|
|
3754
|
-
copilotkit.addTool(tool);
|
|
3755
|
-
if (tool.render) copilotkit.addHookRenderToolCall({
|
|
3756
|
-
name,
|
|
3757
|
-
args: tool.parameters,
|
|
3758
|
-
agentId: tool.agentId,
|
|
3759
|
-
render: tool.render
|
|
3760
|
-
});
|
|
3761
|
-
return () => {
|
|
3762
|
-
copilotkit.removeTool(name, tool.agentId);
|
|
3763
|
-
};
|
|
3764
|
-
}, [
|
|
3765
|
-
tool.name,
|
|
3766
|
-
tool.available,
|
|
3767
|
-
copilotkit,
|
|
3768
|
-
JSON.stringify(extraDeps)
|
|
3769
|
-
]);
|
|
3770
|
-
}
|
|
3771
|
-
|
|
3772
|
-
//#endregion
|
|
3773
|
-
//#region src/v2/hooks/use-component.tsx
|
|
3774
|
-
/**
|
|
3775
|
-
* Registers a React component as a frontend tool renderer in chat.
|
|
3776
|
-
*
|
|
3777
|
-
* This hook is a convenience wrapper around `useFrontendTool` that:
|
|
3778
|
-
* - builds a model-facing tool description,
|
|
3779
|
-
* - forwards optional schema parameters (any Standard Schema V1 compatible library),
|
|
3780
|
-
* - renders your component with tool call parameters.
|
|
3781
|
-
*
|
|
3782
|
-
* Use this when you want to display a typed visual component for a tool call
|
|
3783
|
-
* without manually wiring a full frontend tool object.
|
|
3784
|
-
*
|
|
3785
|
-
* When `parameters` is provided, render props are inferred from the schema.
|
|
3786
|
-
* When omitted, the render component may accept any props.
|
|
3787
|
-
*
|
|
3788
|
-
* @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
|
|
3789
|
-
* @param config - Tool registration config.
|
|
3790
|
-
* @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
|
|
3791
|
-
*
|
|
3792
|
-
* @example
|
|
3793
|
-
* ```tsx
|
|
3794
|
-
* // Without parameters — render accepts any props
|
|
3795
|
-
* useComponent({
|
|
3796
|
-
* name: "showGreeting",
|
|
3797
|
-
* render: ({ message }: { message: string }) => <div>{message}</div>,
|
|
3798
|
-
* });
|
|
3799
|
-
* ```
|
|
3800
|
-
*
|
|
3801
|
-
* @example
|
|
3802
|
-
* ```tsx
|
|
3803
|
-
* // With parameters — render props inferred from schema
|
|
3804
|
-
* useComponent({
|
|
3805
|
-
* name: "showWeatherCard",
|
|
3806
|
-
* parameters: z.object({ city: z.string() }),
|
|
3807
|
-
* render: ({ city }) => <div>{city}</div>,
|
|
3808
|
-
* });
|
|
3809
|
-
* ```
|
|
3810
|
-
*
|
|
3811
|
-
* @example
|
|
3812
|
-
* ```tsx
|
|
3813
|
-
* useComponent(
|
|
3814
|
-
* {
|
|
3815
|
-
* name: "renderProfile",
|
|
3816
|
-
* parameters: z.object({ userId: z.string() }),
|
|
3817
|
-
* render: ProfileCard,
|
|
3818
|
-
* agentId: "support-agent",
|
|
3819
|
-
* },
|
|
3820
|
-
* [selectedAgentId],
|
|
3821
|
-
* );
|
|
3822
|
-
* ```
|
|
3823
|
-
*/
|
|
3824
|
-
function useComponent(config, deps) {
|
|
3825
|
-
const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
|
|
3826
|
-
const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
|
|
3827
|
-
useFrontendTool({
|
|
3828
|
-
name: config.name,
|
|
3829
|
-
description: fullDescription,
|
|
3830
|
-
parameters: config.parameters,
|
|
3831
|
-
render: ({ args }) => {
|
|
3832
|
-
const Component = config.render;
|
|
3833
|
-
return /* @__PURE__ */ jsx(Component, { ...args });
|
|
3834
|
-
},
|
|
3835
|
-
agentId: config.agentId
|
|
3836
|
-
}, deps);
|
|
3837
|
-
}
|
|
3838
|
-
|
|
3839
|
-
//#endregion
|
|
3840
|
-
//#region src/v2/hooks/use-render-tool.tsx
|
|
3841
|
-
const EMPTY_DEPS = [];
|
|
3842
|
-
/**
|
|
3843
|
-
* Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
|
|
3844
|
-
*
|
|
3845
|
-
* Key behavior:
|
|
3846
|
-
* - deduplicates by `agentId:name` (latest registration wins),
|
|
3847
|
-
* - keeps renderer entries on cleanup so historical chat tool calls can still render,
|
|
3848
|
-
* - refreshes registration when `deps` change.
|
|
3849
|
-
*
|
|
3850
|
-
* @typeParam S - Schema type describing tool call parameters.
|
|
3851
|
-
* @param config - Renderer config for wildcard or named tools.
|
|
3852
|
-
* @param deps - Optional dependencies to refresh registration.
|
|
3853
|
-
*
|
|
3854
|
-
* @example
|
|
3855
|
-
* ```tsx
|
|
3856
|
-
* useRenderTool(
|
|
3857
|
-
* {
|
|
3858
|
-
* name: "searchDocs",
|
|
3859
|
-
* parameters: z.object({ query: z.string() }),
|
|
3860
|
-
* render: ({ status, parameters, result }) => {
|
|
3861
|
-
* if (status === "executing") return <div>Searching {parameters.query}</div>;
|
|
3862
|
-
* if (status === "complete") return <div>{result}</div>;
|
|
3863
|
-
* return <div>Preparing...</div>;
|
|
3864
|
-
* },
|
|
3865
|
-
* },
|
|
3866
|
-
* [],
|
|
3867
|
-
* );
|
|
3868
|
-
* ```
|
|
3869
|
-
*
|
|
3870
|
-
* @example
|
|
3871
|
-
* ```tsx
|
|
3872
|
-
* useRenderTool(
|
|
3873
|
-
* {
|
|
3874
|
-
* name: "summarize",
|
|
3875
|
-
* parameters: z.object({ text: z.string() }),
|
|
3876
|
-
* agentId: "research-agent",
|
|
3877
|
-
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
3878
|
-
* },
|
|
3879
|
-
* [selectedAgentId],
|
|
3880
|
-
* );
|
|
3881
|
-
* ```
|
|
3882
|
-
*/
|
|
3883
|
-
function useRenderTool(config, deps) {
|
|
3799
|
+
for (const renderer of customMessageRenderers) {
|
|
3800
|
+
if (!renderer.render) continue;
|
|
3801
|
+
const Component = renderer.render;
|
|
3802
|
+
result = /* @__PURE__ */ jsx(Component, {
|
|
3803
|
+
message,
|
|
3804
|
+
position,
|
|
3805
|
+
runId,
|
|
3806
|
+
messageIndex,
|
|
3807
|
+
messageIndexInRun,
|
|
3808
|
+
numberOfMessagesInRun,
|
|
3809
|
+
agentId,
|
|
3810
|
+
stateSnapshot
|
|
3811
|
+
}, `${runId}-${message.id}-${position}`);
|
|
3812
|
+
if (result) break;
|
|
3813
|
+
}
|
|
3814
|
+
return result;
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
//#endregion
|
|
3819
|
+
//#region src/v2/hooks/use-render-activity-message.tsx
|
|
3820
|
+
function useRenderActivityMessage() {
|
|
3884
3821
|
const { copilotkit } = useCopilotKit();
|
|
3885
|
-
const
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3822
|
+
const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
|
|
3823
|
+
const renderers = copilotkit.renderActivityMessages;
|
|
3824
|
+
const findRenderer = useCallback((activityType) => {
|
|
3825
|
+
if (!renderers.length) return null;
|
|
3826
|
+
const matches = renderers.filter((renderer) => renderer.activityType === activityType);
|
|
3827
|
+
return matches.find((candidate) => candidate.agentId === agentId) ?? matches.find((candidate) => candidate.agentId === void 0) ?? renderers.find((candidate) => candidate.activityType === "*") ?? null;
|
|
3828
|
+
}, [agentId, renderers]);
|
|
3829
|
+
const renderActivityMessage = useCallback((message) => {
|
|
3830
|
+
const renderer = findRenderer(message.activityType);
|
|
3831
|
+
if (!renderer) return null;
|
|
3832
|
+
const parseResult = renderer.content.safeParse(message.content);
|
|
3833
|
+
if (!parseResult.success) {
|
|
3834
|
+
console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.error);
|
|
3835
|
+
return null;
|
|
3836
|
+
}
|
|
3837
|
+
const Component = renderer.render;
|
|
3838
|
+
const agent = copilotkit.getAgent(agentId);
|
|
3839
|
+
return /* @__PURE__ */ jsx(Component, {
|
|
3840
|
+
activityType: message.activityType,
|
|
3841
|
+
content: parseResult.data,
|
|
3842
|
+
message,
|
|
3843
|
+
agent
|
|
3844
|
+
}, message.id);
|
|
3904
3845
|
}, [
|
|
3905
|
-
|
|
3846
|
+
agentId,
|
|
3906
3847
|
copilotkit,
|
|
3907
|
-
|
|
3848
|
+
findRenderer
|
|
3908
3849
|
]);
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
borderRadius: "50%",
|
|
4014
|
-
backgroundColor: isActive ? "#f59e0b" : isComplete ? "#10b981" : "#a1a1aa",
|
|
4015
|
-
flexShrink: 0
|
|
4016
|
-
} }),
|
|
4017
|
-
/* @__PURE__ */ jsx("span", {
|
|
4018
|
-
style: {
|
|
4019
|
-
fontSize: "13px",
|
|
4020
|
-
fontWeight: 600,
|
|
4021
|
-
color: "#18181b",
|
|
4022
|
-
overflow: "hidden",
|
|
4023
|
-
textOverflow: "ellipsis",
|
|
4024
|
-
whiteSpace: "nowrap"
|
|
4025
|
-
},
|
|
4026
|
-
children: name
|
|
4027
|
-
})
|
|
4028
|
-
]
|
|
4029
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
4030
|
-
style: {
|
|
4031
|
-
display: "inline-flex",
|
|
4032
|
-
alignItems: "center",
|
|
4033
|
-
borderRadius: "9999px",
|
|
4034
|
-
padding: "2px 8px",
|
|
4035
|
-
fontSize: "11px",
|
|
4036
|
-
fontWeight: 500,
|
|
4037
|
-
backgroundColor: isActive ? "#fef3c7" : isComplete ? "#d1fae5" : "#f4f4f5",
|
|
4038
|
-
color: isActive ? "#92400e" : isComplete ? "#065f46" : "#3f3f46",
|
|
4039
|
-
flexShrink: 0
|
|
4040
|
-
},
|
|
4041
|
-
children: isActive ? "Running" : isComplete ? "Done" : status
|
|
4042
|
-
})]
|
|
4043
|
-
}), isExpanded && /* @__PURE__ */ jsxs("div", {
|
|
4044
|
-
style: {
|
|
4045
|
-
marginTop: "12px",
|
|
4046
|
-
display: "grid",
|
|
4047
|
-
gap: "12px"
|
|
4048
|
-
},
|
|
4049
|
-
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
4050
|
-
style: {
|
|
4051
|
-
fontSize: "10px",
|
|
4052
|
-
textTransform: "uppercase",
|
|
4053
|
-
letterSpacing: "0.05em",
|
|
4054
|
-
color: "#71717a"
|
|
4055
|
-
},
|
|
4056
|
-
children: "Arguments"
|
|
4057
|
-
}), /* @__PURE__ */ jsx("pre", {
|
|
4058
|
-
style: {
|
|
4059
|
-
marginTop: "6px",
|
|
4060
|
-
maxHeight: "200px",
|
|
4061
|
-
overflow: "auto",
|
|
4062
|
-
borderRadius: "6px",
|
|
4063
|
-
backgroundColor: "#f4f4f5",
|
|
4064
|
-
padding: "10px",
|
|
4065
|
-
fontSize: "11px",
|
|
4066
|
-
lineHeight: 1.6,
|
|
4067
|
-
color: "#27272a",
|
|
4068
|
-
whiteSpace: "pre-wrap",
|
|
4069
|
-
wordBreak: "break-word"
|
|
4070
|
-
},
|
|
4071
|
-
children: JSON.stringify(parameters ?? {}, null, 2)
|
|
4072
|
-
})] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
4073
|
-
style: {
|
|
4074
|
-
fontSize: "10px",
|
|
4075
|
-
textTransform: "uppercase",
|
|
4076
|
-
letterSpacing: "0.05em",
|
|
4077
|
-
color: "#71717a"
|
|
4078
|
-
},
|
|
4079
|
-
children: "Result"
|
|
4080
|
-
}), /* @__PURE__ */ jsx("pre", {
|
|
4081
|
-
style: {
|
|
4082
|
-
marginTop: "6px",
|
|
4083
|
-
maxHeight: "200px",
|
|
4084
|
-
overflow: "auto",
|
|
4085
|
-
borderRadius: "6px",
|
|
4086
|
-
backgroundColor: "#f4f4f5",
|
|
4087
|
-
padding: "10px",
|
|
4088
|
-
fontSize: "11px",
|
|
4089
|
-
lineHeight: 1.6,
|
|
4090
|
-
color: "#27272a",
|
|
4091
|
-
whiteSpace: "pre-wrap",
|
|
4092
|
-
wordBreak: "break-word"
|
|
4093
|
-
},
|
|
4094
|
-
children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
4095
|
-
})] })]
|
|
4096
|
-
})]
|
|
4097
|
-
})
|
|
4098
|
-
});
|
|
3850
|
+
return useMemo(() => ({
|
|
3851
|
+
renderActivityMessage,
|
|
3852
|
+
findRenderer
|
|
3853
|
+
}), [renderActivityMessage, findRenderer]);
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3856
|
+
//#endregion
|
|
3857
|
+
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
3858
|
+
const EMPTY_DEPS = [];
|
|
3859
|
+
function useFrontendTool(tool, deps) {
|
|
3860
|
+
const { copilotkit } = useCopilotKit();
|
|
3861
|
+
const extraDeps = deps ?? EMPTY_DEPS;
|
|
3862
|
+
useEffect(() => {
|
|
3863
|
+
const name = tool.name;
|
|
3864
|
+
if (copilotkit.getTool({
|
|
3865
|
+
toolName: name,
|
|
3866
|
+
agentId: tool.agentId
|
|
3867
|
+
})) {
|
|
3868
|
+
console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
|
|
3869
|
+
copilotkit.removeTool(name, tool.agentId);
|
|
3870
|
+
}
|
|
3871
|
+
copilotkit.addTool(tool);
|
|
3872
|
+
if (tool.render) copilotkit.addHookRenderToolCall({
|
|
3873
|
+
name,
|
|
3874
|
+
args: tool.parameters,
|
|
3875
|
+
agentId: tool.agentId,
|
|
3876
|
+
render: tool.render
|
|
3877
|
+
});
|
|
3878
|
+
return () => {
|
|
3879
|
+
copilotkit.removeTool(name, tool.agentId);
|
|
3880
|
+
};
|
|
3881
|
+
}, [
|
|
3882
|
+
tool.name,
|
|
3883
|
+
tool.available,
|
|
3884
|
+
copilotkit,
|
|
3885
|
+
JSON.stringify(extraDeps)
|
|
3886
|
+
]);
|
|
3887
|
+
}
|
|
3888
|
+
|
|
3889
|
+
//#endregion
|
|
3890
|
+
//#region src/v2/hooks/use-component.tsx
|
|
3891
|
+
/**
|
|
3892
|
+
* Registers a React component as a frontend tool renderer in chat.
|
|
3893
|
+
*
|
|
3894
|
+
* This hook is a convenience wrapper around `useFrontendTool` that:
|
|
3895
|
+
* - builds a model-facing tool description,
|
|
3896
|
+
* - forwards optional schema parameters (any Standard Schema V1 compatible library),
|
|
3897
|
+
* - renders your component with tool call parameters.
|
|
3898
|
+
*
|
|
3899
|
+
* Use this when you want to display a typed visual component for a tool call
|
|
3900
|
+
* without manually wiring a full frontend tool object.
|
|
3901
|
+
*
|
|
3902
|
+
* When `parameters` is provided, render props are inferred from the schema.
|
|
3903
|
+
* When omitted, the render component may accept any props.
|
|
3904
|
+
*
|
|
3905
|
+
* @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
|
|
3906
|
+
* @param config - Tool registration config.
|
|
3907
|
+
* @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
|
|
3908
|
+
*
|
|
3909
|
+
* @example
|
|
3910
|
+
* ```tsx
|
|
3911
|
+
* // Without parameters — render accepts any props
|
|
3912
|
+
* useComponent({
|
|
3913
|
+
* name: "showGreeting",
|
|
3914
|
+
* render: ({ message }: { message: string }) => <div>{message}</div>,
|
|
3915
|
+
* });
|
|
3916
|
+
* ```
|
|
3917
|
+
*
|
|
3918
|
+
* @example
|
|
3919
|
+
* ```tsx
|
|
3920
|
+
* // With parameters — render props inferred from schema
|
|
3921
|
+
* useComponent({
|
|
3922
|
+
* name: "showWeatherCard",
|
|
3923
|
+
* parameters: z.object({ city: z.string() }),
|
|
3924
|
+
* render: ({ city }) => <div>{city}</div>,
|
|
3925
|
+
* });
|
|
3926
|
+
* ```
|
|
3927
|
+
*
|
|
3928
|
+
* @example
|
|
3929
|
+
* ```tsx
|
|
3930
|
+
* useComponent(
|
|
3931
|
+
* {
|
|
3932
|
+
* name: "renderProfile",
|
|
3933
|
+
* parameters: z.object({ userId: z.string() }),
|
|
3934
|
+
* render: ProfileCard,
|
|
3935
|
+
* agentId: "support-agent",
|
|
3936
|
+
* },
|
|
3937
|
+
* [selectedAgentId],
|
|
3938
|
+
* );
|
|
3939
|
+
* ```
|
|
3940
|
+
*/
|
|
3941
|
+
function useComponent(config, deps) {
|
|
3942
|
+
const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
|
|
3943
|
+
const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
|
|
3944
|
+
useFrontendTool({
|
|
3945
|
+
name: config.name,
|
|
3946
|
+
description: fullDescription,
|
|
3947
|
+
parameters: config.parameters,
|
|
3948
|
+
render: ({ args }) => {
|
|
3949
|
+
const Component = config.render;
|
|
3950
|
+
return /* @__PURE__ */ jsx(Component, { ...args });
|
|
3951
|
+
},
|
|
3952
|
+
agentId: config.agentId
|
|
3953
|
+
}, deps);
|
|
4099
3954
|
}
|
|
4100
3955
|
|
|
4101
3956
|
//#endregion
|
|
@@ -4164,6 +4019,118 @@ function useHumanInTheLoop(tool, deps) {
|
|
|
4164
4019
|
]);
|
|
4165
4020
|
}
|
|
4166
4021
|
|
|
4022
|
+
//#endregion
|
|
4023
|
+
//#region src/v2/hooks/use-agent.tsx
|
|
4024
|
+
let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
|
|
4025
|
+
UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
|
|
4026
|
+
UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
|
|
4027
|
+
UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
|
|
4028
|
+
return UseAgentUpdate;
|
|
4029
|
+
}({});
|
|
4030
|
+
const ALL_UPDATES = [
|
|
4031
|
+
UseAgentUpdate.OnMessagesChanged,
|
|
4032
|
+
UseAgentUpdate.OnStateChanged,
|
|
4033
|
+
UseAgentUpdate.OnRunStatusChanged
|
|
4034
|
+
];
|
|
4035
|
+
function useAgent({ agentId, updates, throttleMs } = {}) {
|
|
4036
|
+
agentId ??= DEFAULT_AGENT_ID;
|
|
4037
|
+
const { copilotkit } = useCopilotKit();
|
|
4038
|
+
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
4039
|
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
4040
|
+
const updateFlags = useMemo(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
4041
|
+
const provisionalAgentCache = useRef(/* @__PURE__ */ new Map());
|
|
4042
|
+
const agent = useMemo(() => {
|
|
4043
|
+
const existing = copilotkit.getAgent(agentId);
|
|
4044
|
+
if (existing) {
|
|
4045
|
+
provisionalAgentCache.current.delete(agentId);
|
|
4046
|
+
return existing;
|
|
4047
|
+
}
|
|
4048
|
+
const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
|
|
4049
|
+
const status = copilotkit.runtimeConnectionStatus;
|
|
4050
|
+
if (isRuntimeConfigured && (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
|
|
4051
|
+
const cached = provisionalAgentCache.current.get(agentId);
|
|
4052
|
+
if (cached) {
|
|
4053
|
+
cached.headers = { ...copilotkit.headers };
|
|
4054
|
+
return cached;
|
|
4055
|
+
}
|
|
4056
|
+
const provisional = new ProxiedCopilotRuntimeAgent({
|
|
4057
|
+
runtimeUrl: copilotkit.runtimeUrl,
|
|
4058
|
+
agentId,
|
|
4059
|
+
transport: copilotkit.runtimeTransport,
|
|
4060
|
+
runtimeMode: "pending"
|
|
4061
|
+
});
|
|
4062
|
+
provisional.headers = { ...copilotkit.headers };
|
|
4063
|
+
provisionalAgentCache.current.set(agentId, provisional);
|
|
4064
|
+
return provisional;
|
|
4065
|
+
}
|
|
4066
|
+
if (isRuntimeConfigured && status === CopilotKitCoreRuntimeConnectionStatus.Error) {
|
|
4067
|
+
const cached = provisionalAgentCache.current.get(agentId);
|
|
4068
|
+
if (cached) {
|
|
4069
|
+
cached.headers = { ...copilotkit.headers };
|
|
4070
|
+
return cached;
|
|
4071
|
+
}
|
|
4072
|
+
const provisional = new ProxiedCopilotRuntimeAgent({
|
|
4073
|
+
runtimeUrl: copilotkit.runtimeUrl,
|
|
4074
|
+
agentId,
|
|
4075
|
+
transport: copilotkit.runtimeTransport,
|
|
4076
|
+
runtimeMode: "pending"
|
|
4077
|
+
});
|
|
4078
|
+
provisional.headers = { ...copilotkit.headers };
|
|
4079
|
+
provisionalAgentCache.current.set(agentId, provisional);
|
|
4080
|
+
return provisional;
|
|
4081
|
+
}
|
|
4082
|
+
const knownAgents = Object.keys(copilotkit.agents ?? {});
|
|
4083
|
+
const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
|
|
4084
|
+
throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
|
|
4085
|
+
}, [
|
|
4086
|
+
agentId,
|
|
4087
|
+
copilotkit.agents,
|
|
4088
|
+
copilotkit.runtimeConnectionStatus,
|
|
4089
|
+
copilotkit.runtimeUrl,
|
|
4090
|
+
copilotkit.runtimeTransport,
|
|
4091
|
+
JSON.stringify(copilotkit.headers)
|
|
4092
|
+
]);
|
|
4093
|
+
useEffect(() => {
|
|
4094
|
+
if (updateFlags.length === 0) return;
|
|
4095
|
+
let active = true;
|
|
4096
|
+
const handlers = {};
|
|
4097
|
+
let batchScheduled = false;
|
|
4098
|
+
const batchedForceUpdate = () => {
|
|
4099
|
+
if (!active) return;
|
|
4100
|
+
if (!batchScheduled) {
|
|
4101
|
+
batchScheduled = true;
|
|
4102
|
+
queueMicrotask(() => {
|
|
4103
|
+
batchScheduled = false;
|
|
4104
|
+
if (active) forceUpdate();
|
|
4105
|
+
});
|
|
4106
|
+
}
|
|
4107
|
+
};
|
|
4108
|
+
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = batchedForceUpdate;
|
|
4109
|
+
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
|
|
4110
|
+
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
4111
|
+
handlers.onRunInitialized = batchedForceUpdate;
|
|
4112
|
+
handlers.onRunFinalized = batchedForceUpdate;
|
|
4113
|
+
handlers.onRunFailed = batchedForceUpdate;
|
|
4114
|
+
handlers.onRunErrorEvent = batchedForceUpdate;
|
|
4115
|
+
}
|
|
4116
|
+
const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
|
|
4117
|
+
return () => {
|
|
4118
|
+
active = false;
|
|
4119
|
+
subscription.unsubscribe();
|
|
4120
|
+
};
|
|
4121
|
+
}, [
|
|
4122
|
+
agent,
|
|
4123
|
+
forceUpdate,
|
|
4124
|
+
throttleMs,
|
|
4125
|
+
providerThrottleMs,
|
|
4126
|
+
updateFlags
|
|
4127
|
+
]);
|
|
4128
|
+
useEffect(() => {
|
|
4129
|
+
if (agent instanceof HttpAgent) agent.headers = { ...copilotkit.headers };
|
|
4130
|
+
}, [agent, JSON.stringify(copilotkit.headers)]);
|
|
4131
|
+
return { agent };
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4167
4134
|
//#endregion
|
|
4168
4135
|
//#region src/v2/hooks/use-capabilities.tsx
|
|
4169
4136
|
/**
|
|
@@ -5629,6 +5596,190 @@ CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
|
|
|
5629
5596
|
*/
|
|
5630
5597
|
const ScrollElementContext = React.createContext(null);
|
|
5631
5598
|
|
|
5599
|
+
//#endregion
|
|
5600
|
+
//#region src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx
|
|
5601
|
+
/**
|
|
5602
|
+
* Grace window before showing the spinner. A matching tool call must
|
|
5603
|
+
* remain unresolved (no `tool`-role result message in `agent.messages`)
|
|
5604
|
+
* for at least this long before the pill appears. This filters out
|
|
5605
|
+
* history-replay flashes — during `connectAgent` replay, tool calls and
|
|
5606
|
+
* their results arrive back-to-back in sub-millisecond bursts, so the
|
|
5607
|
+
* timer is cancelled before it fires. Live runs cross the threshold
|
|
5608
|
+
* easily because the tool actually has to execute.
|
|
5609
|
+
*/
|
|
5610
|
+
const PENDING_THRESHOLD_MS = 100;
|
|
5611
|
+
/** Hold the checkmark briefly before fading out. */
|
|
5612
|
+
const CHECK_HOLD_MS = 800;
|
|
5613
|
+
/**
|
|
5614
|
+
* Duration of the fade-out animation. Must match
|
|
5615
|
+
* `cpk-intelligence-pill-fade-out` keyframes in `v2/styles/globals.css`.
|
|
5616
|
+
*/
|
|
5617
|
+
const FADE_OUT_ANIMATION_MS = 480;
|
|
5618
|
+
/**
|
|
5619
|
+
* Tool-name regex patterns that trigger the indicator. Currently
|
|
5620
|
+
* hardcoded to the Intelligence MCP server's canonical tool name. If
|
|
5621
|
+
* we add per-instance customization later (e.g. a `CopilotKitProvider`
|
|
5622
|
+
* prop or a runtime-info field), this constant becomes the fallback.
|
|
5623
|
+
*/
|
|
5624
|
+
const DEFAULT_TOOL_PATTERNS = [/^copilotkit_knowledge_base_shell$/];
|
|
5625
|
+
const isMatchingToolCallName = (name) => typeof name === "string" && DEFAULT_TOOL_PATTERNS.some((p) => p.test(name));
|
|
5626
|
+
/**
|
|
5627
|
+
* "Tool-call-like" messages do NOT count as a real follow-up: tool
|
|
5628
|
+
* result messages, assistant messages that carry tool calls, and
|
|
5629
|
+
* empty-content assistant messages (which some providers emit as a
|
|
5630
|
+
* standalone wrapper around a batch of tool calls). A real follow-up
|
|
5631
|
+
* is anything else — most importantly an assistant message with prose
|
|
5632
|
+
* content, or a fresh user message.
|
|
5633
|
+
*/
|
|
5634
|
+
const isToolCallLikeMessage = (m) => {
|
|
5635
|
+
if (m.role === "tool") return true;
|
|
5636
|
+
if (m.role === "assistant") {
|
|
5637
|
+
if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).length > 0) return true;
|
|
5638
|
+
const content = m.content;
|
|
5639
|
+
return typeof content !== "string" || content.trim().length === 0;
|
|
5640
|
+
}
|
|
5641
|
+
return false;
|
|
5642
|
+
};
|
|
5643
|
+
/**
|
|
5644
|
+
* The "Using CopilotKit Intelligence" pill. Auto-mounted by
|
|
5645
|
+
* `CopilotChatMessageView` for every message slot when
|
|
5646
|
+
* `copilotkit.intelligence` is configured — callers do not register
|
|
5647
|
+
* this themselves. Self-gates so only the canonical message renders a
|
|
5648
|
+
* pill.
|
|
5649
|
+
*
|
|
5650
|
+
* Render gates (all must hold):
|
|
5651
|
+
* 1. `copilotkit.intelligence !== undefined`
|
|
5652
|
+
* 2. The message is an assistant message with at least one tool call
|
|
5653
|
+
* whose name matches {@link DEFAULT_TOOL_PATTERNS}
|
|
5654
|
+
* 3. The message is the *latest* such matching-assistant message in
|
|
5655
|
+
* `agent.messages` — tool-result messages and prose-only assistant
|
|
5656
|
+
* messages don't invalidate the slot, so the pill stays
|
|
5657
|
+
* continuously through a multi-step tool chain.
|
|
5658
|
+
* 4. The phase machine is past `idle` (the pending-grace timer fired)
|
|
5659
|
+
* and not yet `hidden`.
|
|
5660
|
+
*
|
|
5661
|
+
* Phase machine (per-instance, all timers local):
|
|
5662
|
+
* - Starts in `idle` — nothing rendered.
|
|
5663
|
+
* - `idle → spinner` once a matching tool call has been pending
|
|
5664
|
+
* (no `tool`-role result with a matching `toolCallId`) for
|
|
5665
|
+
* {@link PENDING_THRESHOLD_MS}. Replay flashes (tool call + result
|
|
5666
|
+
* in the same tick) never cross this threshold.
|
|
5667
|
+
* - `spinner → check` as soon as EITHER `agent.isRunning` flips
|
|
5668
|
+
* false OR a non-tool-call-like message appears later in
|
|
5669
|
+
* `agent.messages` (i.e. the agent has produced a "real"
|
|
5670
|
+
* follow-up — prose answer or a new user turn).
|
|
5671
|
+
* - `check → fading` after {@link CHECK_HOLD_MS}.
|
|
5672
|
+
* - `fading → hidden` after {@link FADE_OUT_ANIMATION_MS}.
|
|
5673
|
+
*
|
|
5674
|
+
* Once `hidden`, the phase is sticky — a finished pill never re-spawns
|
|
5675
|
+
* on the same message. New runs mount fresh indicator instances on
|
|
5676
|
+
* their own assistant messages.
|
|
5677
|
+
*
|
|
5678
|
+
* The "exactly one pill at a time" guarantee is structural: only one
|
|
5679
|
+
* message satisfies the latest-matching-assistant gate at any moment.
|
|
5680
|
+
*/
|
|
5681
|
+
function IntelligenceIndicator(props) {
|
|
5682
|
+
const { message, agentId, label = "Using CopilotKit Intelligence" } = props;
|
|
5683
|
+
const { copilotkit } = useCopilotKit();
|
|
5684
|
+
const config = useCopilotChatConfiguration();
|
|
5685
|
+
const { agent } = useAgent({
|
|
5686
|
+
agentId,
|
|
5687
|
+
updates: [UseAgentUpdate.OnRunStatusChanged, UseAgentUpdate.OnMessagesChanged]
|
|
5688
|
+
});
|
|
5689
|
+
const matchingToolCallIds = useMemo(() => {
|
|
5690
|
+
if (message.role !== "assistant") return [];
|
|
5691
|
+
const tcs = Array.isArray(message.toolCalls) ? message.toolCalls : [];
|
|
5692
|
+
const ids = [];
|
|
5693
|
+
for (const tc of tcs) if (isMatchingToolCallName(tc?.function?.name) && tc?.id) ids.push(tc.id);
|
|
5694
|
+
return ids;
|
|
5695
|
+
}, [message]);
|
|
5696
|
+
const hasPending = useMemo(() => {
|
|
5697
|
+
if (matchingToolCallIds.length === 0) return false;
|
|
5698
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
5699
|
+
for (const m of agent.messages) if (m.role === "tool" && m.toolCallId) resolved.add(m.toolCallId);
|
|
5700
|
+
return matchingToolCallIds.some((id) => !resolved.has(id));
|
|
5701
|
+
}, [matchingToolCallIds, agent.messages]);
|
|
5702
|
+
const sawRealFollowup = useMemo(() => {
|
|
5703
|
+
const idx = agent.messages.findIndex((m) => m.id === message.id);
|
|
5704
|
+
if (idx < 0) return false;
|
|
5705
|
+
for (let i = idx + 1; i < agent.messages.length; i += 1) if (!isToolCallLikeMessage(agent.messages[i])) return true;
|
|
5706
|
+
return false;
|
|
5707
|
+
}, [agent.messages, message.id]);
|
|
5708
|
+
const [phase, setPhase] = useState("idle");
|
|
5709
|
+
useEffect(() => {
|
|
5710
|
+
if (phase !== "idle") return void 0;
|
|
5711
|
+
if (!hasPending) return void 0;
|
|
5712
|
+
const t = setTimeout(() => setPhase("spinner"), PENDING_THRESHOLD_MS);
|
|
5713
|
+
return () => clearTimeout(t);
|
|
5714
|
+
}, [phase, hasPending]);
|
|
5715
|
+
useEffect(() => {
|
|
5716
|
+
if (phase !== "spinner") return void 0;
|
|
5717
|
+
if (!agent.isRunning || sawRealFollowup) setPhase("check");
|
|
5718
|
+
}, [
|
|
5719
|
+
phase,
|
|
5720
|
+
agent.isRunning,
|
|
5721
|
+
sawRealFollowup
|
|
5722
|
+
]);
|
|
5723
|
+
useEffect(() => {
|
|
5724
|
+
if (phase !== "check") return void 0;
|
|
5725
|
+
const t = setTimeout(() => setPhase("fading"), CHECK_HOLD_MS);
|
|
5726
|
+
return () => clearTimeout(t);
|
|
5727
|
+
}, [phase]);
|
|
5728
|
+
useEffect(() => {
|
|
5729
|
+
if (phase !== "fading") return void 0;
|
|
5730
|
+
const t = setTimeout(() => setPhase("hidden"), FADE_OUT_ANIMATION_MS);
|
|
5731
|
+
return () => clearTimeout(t);
|
|
5732
|
+
}, [phase]);
|
|
5733
|
+
if (copilotkit.intelligence === void 0) return null;
|
|
5734
|
+
if (!config) return null;
|
|
5735
|
+
if (phase === "idle" || phase === "hidden") return null;
|
|
5736
|
+
if (message.role !== "assistant") return null;
|
|
5737
|
+
if (!(Array.isArray(message.toolCalls) ? message.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) return null;
|
|
5738
|
+
let latestMatchingAssistantId;
|
|
5739
|
+
for (let i = agent.messages.length - 1; i >= 0; i -= 1) {
|
|
5740
|
+
const m = agent.messages[i];
|
|
5741
|
+
if (m.role !== "assistant") continue;
|
|
5742
|
+
if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) {
|
|
5743
|
+
latestMatchingAssistantId = m.id;
|
|
5744
|
+
break;
|
|
5745
|
+
}
|
|
5746
|
+
}
|
|
5747
|
+
if (latestMatchingAssistantId !== message.id) return null;
|
|
5748
|
+
const showSpinner = phase === "spinner";
|
|
5749
|
+
const isFading = phase === "fading";
|
|
5750
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
5751
|
+
className: "cpk-intelligence-pill" + (isFading ? " cpk-intelligence-pill--fading" : ""),
|
|
5752
|
+
role: "status",
|
|
5753
|
+
"aria-live": "polite",
|
|
5754
|
+
"aria-hidden": isFading || void 0,
|
|
5755
|
+
"data-testid": `cpk-intelligence-pill-${message.id}`,
|
|
5756
|
+
title: label,
|
|
5757
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
5758
|
+
className: "cpk-intelligence-pill__icon",
|
|
5759
|
+
viewBox: "0 0 24 24",
|
|
5760
|
+
width: "14",
|
|
5761
|
+
height: "14",
|
|
5762
|
+
"aria-hidden": "true",
|
|
5763
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
5764
|
+
cx: "12",
|
|
5765
|
+
cy: "12",
|
|
5766
|
+
r: "9",
|
|
5767
|
+
fill: "none",
|
|
5768
|
+
strokeWidth: "2.5",
|
|
5769
|
+
strokeLinecap: "round",
|
|
5770
|
+
className: "cpk-intelligence-pill__ring" + (showSpinner ? "" : " cpk-intelligence-pill__ring--done")
|
|
5771
|
+
}), /* @__PURE__ */ jsx("path", {
|
|
5772
|
+
d: "M8 12.5l3 3 5-6",
|
|
5773
|
+
fill: "none",
|
|
5774
|
+
strokeWidth: "2.5",
|
|
5775
|
+
strokeLinecap: "round",
|
|
5776
|
+
strokeLinejoin: "round",
|
|
5777
|
+
className: "cpk-intelligence-pill__check" + (showSpinner ? "" : " cpk-intelligence-pill__check--shown")
|
|
5778
|
+
})]
|
|
5779
|
+
}), /* @__PURE__ */ jsx("span", { children: label })]
|
|
5780
|
+
});
|
|
5781
|
+
}
|
|
5782
|
+
|
|
5632
5783
|
//#endregion
|
|
5633
5784
|
//#region src/v2/components/chat/CopilotChatMessageView.tsx
|
|
5634
5785
|
/**
|
|
@@ -5786,14 +5937,12 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
5786
5937
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
5787
5938
|
useEffect(() => {
|
|
5788
5939
|
if (!config?.agentId) return;
|
|
5789
|
-
const
|
|
5790
|
-
const agent = getThreadClone(registryAgent, config.threadId) ?? registryAgent;
|
|
5940
|
+
const agent = copilotkit.getAgent(config.agentId);
|
|
5791
5941
|
if (!agent) return;
|
|
5792
5942
|
const subscription = agent.subscribe({ onStateChanged: forceUpdate });
|
|
5793
5943
|
return () => subscription.unsubscribe();
|
|
5794
5944
|
}, [
|
|
5795
5945
|
config?.agentId,
|
|
5796
|
-
config?.threadId,
|
|
5797
5946
|
copilotkit,
|
|
5798
5947
|
forceUpdate
|
|
5799
5948
|
]);
|
|
@@ -5876,6 +6025,10 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
5876
6025
|
renderCustomMessage,
|
|
5877
6026
|
stateSnapshot
|
|
5878
6027
|
}, `${message.id}-custom-after`));
|
|
6028
|
+
if (copilotkit.intelligence !== void 0 && message.role === "assistant") elements.push(/* @__PURE__ */ jsx(IntelligenceIndicator, {
|
|
6029
|
+
message,
|
|
6030
|
+
agentId: config?.agentId ?? DEFAULT_AGENT_ID
|
|
6031
|
+
}, `${message.id}-intelligence`));
|
|
5879
6032
|
return elements.filter(Boolean);
|
|
5880
6033
|
};
|
|
5881
6034
|
const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
|
|
@@ -6824,7 +6977,6 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6824
6977
|
const hasExplicitThreadId = !!threadId || !!existingConfig?.hasExplicitThreadId;
|
|
6825
6978
|
const { agent } = useAgent({
|
|
6826
6979
|
agentId: resolvedAgentId,
|
|
6827
|
-
threadId: resolvedThreadId,
|
|
6828
6980
|
throttleMs
|
|
6829
6981
|
});
|
|
6830
6982
|
const { copilotkit } = useCopilotKit();
|
|
@@ -6866,6 +7018,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6866
7018
|
let detached = false;
|
|
6867
7019
|
const connectAbortController = new AbortController();
|
|
6868
7020
|
if (agent instanceof HttpAgent) agent.abortController = connectAbortController;
|
|
7021
|
+
agent.threadId = resolvedThreadId;
|
|
6869
7022
|
const connect = async (agent) => {
|
|
6870
7023
|
try {
|
|
6871
7024
|
await copilotkit.connectAgent({ agent });
|
|
@@ -7274,18 +7427,19 @@ CopilotModalHeader.CloseButton.displayName = "CopilotModalHeader.CloseButton";
|
|
|
7274
7427
|
//#region src/v2/components/chat/CopilotSidebarView.tsx
|
|
7275
7428
|
const DEFAULT_SIDEBAR_WIDTH = 480;
|
|
7276
7429
|
const SIDEBAR_TRANSITION_MS = 260;
|
|
7277
|
-
function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, ...props }) {
|
|
7430
|
+
function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, position = "right", ...props }) {
|
|
7278
7431
|
return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
|
|
7279
7432
|
isModalDefaultOpen: defaultOpen,
|
|
7280
7433
|
children: /* @__PURE__ */ jsx(CopilotSidebarViewInternal, {
|
|
7281
7434
|
header,
|
|
7282
7435
|
toggleButton,
|
|
7283
7436
|
width,
|
|
7437
|
+
position,
|
|
7284
7438
|
...props
|
|
7285
7439
|
})
|
|
7286
7440
|
});
|
|
7287
7441
|
}
|
|
7288
|
-
function CopilotSidebarViewInternal({ header, toggleButton, width, ...props }) {
|
|
7442
|
+
function CopilotSidebarViewInternal({ header, toggleButton, width, position = "right", ...props }) {
|
|
7289
7443
|
const isSidebarOpen = useCopilotChatConfiguration()?.isModalOpen ?? false;
|
|
7290
7444
|
const sidebarRef = useRef(null);
|
|
7291
7445
|
const [sidebarWidth, setSidebarWidth] = useState(width ?? DEFAULT_SIDEBAR_WIDTH);
|
|
@@ -7318,26 +7472,33 @@ function CopilotSidebarViewInternal({ header, toggleButton, width, ...props }) {
|
|
|
7318
7472
|
useLayoutEffect(() => {
|
|
7319
7473
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
7320
7474
|
if (!window.matchMedia("(min-width: 768px)").matches) return;
|
|
7475
|
+
const marginStyleProp = position === "left" ? "marginInlineStart" : "marginInlineEnd";
|
|
7476
|
+
const transitionCssProp = position === "left" ? "margin-inline-start" : "margin-inline-end";
|
|
7321
7477
|
if (isSidebarOpen) {
|
|
7322
|
-
if (hasMounted.current) document.body.style.transition =
|
|
7323
|
-
document.body.style
|
|
7478
|
+
if (hasMounted.current) document.body.style.transition = `${transitionCssProp} ${SIDEBAR_TRANSITION_MS}ms ease`;
|
|
7479
|
+
document.body.style[marginStyleProp] = widthToMargin(sidebarWidth);
|
|
7324
7480
|
} else if (hasMounted.current) {
|
|
7325
|
-
document.body.style.transition =
|
|
7326
|
-
document.body.style
|
|
7481
|
+
document.body.style.transition = `${transitionCssProp} ${SIDEBAR_TRANSITION_MS}ms ease`;
|
|
7482
|
+
document.body.style[marginStyleProp] = "";
|
|
7327
7483
|
}
|
|
7328
7484
|
hasMounted.current = true;
|
|
7329
7485
|
return () => {
|
|
7330
|
-
document.body.style
|
|
7486
|
+
document.body.style[marginStyleProp] = "";
|
|
7331
7487
|
document.body.style.transition = "";
|
|
7332
7488
|
};
|
|
7333
|
-
}, [
|
|
7489
|
+
}, [
|
|
7490
|
+
isSidebarOpen,
|
|
7491
|
+
sidebarWidth,
|
|
7492
|
+
position
|
|
7493
|
+
]);
|
|
7334
7494
|
const headerElement = renderSlot(header, CopilotModalHeader, {});
|
|
7335
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [renderSlot(toggleButton, CopilotChatToggleButton, {}), /* @__PURE__ */ jsx("aside", {
|
|
7495
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [renderSlot(toggleButton, CopilotChatToggleButton, position === "left" ? { className: "cpk:left-6 cpk:right-auto" } : {}), /* @__PURE__ */ jsx("aside", {
|
|
7336
7496
|
ref: sidebarRef,
|
|
7337
7497
|
"data-copilotkit": true,
|
|
7338
7498
|
"data-testid": "copilot-sidebar",
|
|
7339
7499
|
"data-copilot-sidebar": true,
|
|
7340
|
-
|
|
7500
|
+
"data-position": position,
|
|
7501
|
+
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"),
|
|
7341
7502
|
style: {
|
|
7342
7503
|
["--sidebar-width"]: widthToCss(sidebarWidth),
|
|
7343
7504
|
paddingTop: "env(safe-area-inset-top)",
|
|
@@ -7544,7 +7705,7 @@ var CopilotPopupView_default = CopilotPopupView;
|
|
|
7544
7705
|
|
|
7545
7706
|
//#endregion
|
|
7546
7707
|
//#region src/v2/components/chat/CopilotSidebar.tsx
|
|
7547
|
-
function CopilotSidebar({ header, toggleButton, defaultOpen, width, ...chatProps }) {
|
|
7708
|
+
function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ...chatProps }) {
|
|
7548
7709
|
const { checkFeature } = useLicenseContext();
|
|
7549
7710
|
const isSidebarLicensed = checkFeature("sidebar");
|
|
7550
7711
|
useEffect(() => {
|
|
@@ -7552,13 +7713,14 @@ function CopilotSidebar({ header, toggleButton, defaultOpen, width, ...chatProps
|
|
|
7552
7713
|
}, [isSidebarLicensed]);
|
|
7553
7714
|
const SidebarViewOverride = useMemo(() => {
|
|
7554
7715
|
const Component = (viewProps) => {
|
|
7555
|
-
const { header: viewHeader, toggleButton: viewToggleButton, width: viewWidth, defaultOpen: viewDefaultOpen, ...restProps } = viewProps;
|
|
7716
|
+
const { header: viewHeader, toggleButton: viewToggleButton, width: viewWidth, defaultOpen: viewDefaultOpen, position: viewPosition, ...restProps } = viewProps;
|
|
7556
7717
|
return /* @__PURE__ */ jsx(CopilotSidebarView, {
|
|
7557
7718
|
...restProps,
|
|
7558
7719
|
header: header ?? viewHeader,
|
|
7559
7720
|
toggleButton: toggleButton ?? viewToggleButton,
|
|
7560
7721
|
width: width ?? viewWidth,
|
|
7561
|
-
defaultOpen: defaultOpen ?? viewDefaultOpen
|
|
7722
|
+
defaultOpen: defaultOpen ?? viewDefaultOpen,
|
|
7723
|
+
position: position ?? viewPosition
|
|
7562
7724
|
});
|
|
7563
7725
|
};
|
|
7564
7726
|
return Object.assign(Component, CopilotChatView_default);
|
|
@@ -7566,7 +7728,8 @@ function CopilotSidebar({ header, toggleButton, defaultOpen, width, ...chatProps
|
|
|
7566
7728
|
header,
|
|
7567
7729
|
toggleButton,
|
|
7568
7730
|
width,
|
|
7569
|
-
defaultOpen
|
|
7731
|
+
defaultOpen,
|
|
7732
|
+
position
|
|
7570
7733
|
]);
|
|
7571
7734
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isSidebarLicensed && /* @__PURE__ */ jsx(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ jsx(CopilotChat, {
|
|
7572
7735
|
welcomeScreen: CopilotSidebarView.WelcomeScreen,
|
|
@@ -9806,5 +9969,5 @@ function validateProps(props) {
|
|
|
9806
9969
|
}
|
|
9807
9970
|
|
|
9808
9971
|
//#endregion
|
|
9809
|
-
export {
|
|
9810
|
-
//# sourceMappingURL=copilotkit-
|
|
9972
|
+
export { createA2UIMessageRenderer as $, IntelligenceIndicator as A, useInterrupt as B, CopilotChatToggleButton as C, CopilotChatView_default as D, CopilotChat as E, CopilotChatAttachmentRenderer as F, useAgent as G, useSuggestions as H, CopilotChatAssistantMessage_default as I, useFrontendTool as J, useHumanInTheLoop as K, CopilotChatToolCallsView as L, CopilotChatSuggestionPill as M, CopilotChatReasoningMessage_default as N, CopilotChatAttachmentQueue as O, CopilotChatUserMessage_default as P, useAgentContext as Q, useAttachments as R, CopilotModalHeader as S, DefaultOpenIcon as T, useCapabilities as U, useConfigureSuggestions as V, UseAgentUpdate as W, useRenderCustomMessages as X, useRenderActivityMessage as Y, CopilotKitProvider as Z, WildcardToolCallRender as _, ThreadsProvider as a, CopilotKitInspector as at, CopilotPopupView as b, CoAgentStateRendersProvider as c, useRenderTool as ct, shouldShowDevConsole as d, CopilotKitCoreReact as dt, SandboxFunctionsContext as et, useToast as f, CopilotChatInput_default as ft, useCopilotContext as g, useCopilotChatConfiguration as gt, CopilotContext as h, CopilotChatConfigurationProvider as ht, ThreadsContext as i, MCPAppsActivityType as it, CopilotChatSuggestionView as j, CopilotChatMessageView as k, useCoAgentStateRenders as l, defineToolCallRenderer as lt, useCopilotMessagesContext as m, CopilotChatAudioRecorder as mt, defaultCopilotContextCategories as n, MCPAppsActivityContentSchema as nt, useThreads as o, useRenderToolCall as ot, CopilotMessagesContext as p, AudioRecorderError as pt, useComponent as q, CoAgentStateRenderBridge as r, MCPAppsActivityRenderer as rt, CoAgentStateRendersContext as s, useDefaultRenderTool as st, CopilotKit as t, useSandboxFunctions as tt, useAsyncCallback as u, useCopilotKit as ut, CopilotPopup as v, DefaultCloseIcon as w, CopilotSidebarView as x, CopilotSidebar as y, useThreads$1 as z };
|
|
9973
|
+
//# sourceMappingURL=copilotkit-3XTEoVQO.mjs.map
|