CopilotKit 开放生成式 UI(高级):在沙箱 iframe 中调用宿主端沙箱函数

📅 发布时间:2026/9/13 13:40:35
CopilotKit 开放生成式 UI(高级):在沙箱 iframe 中调用宿主端沙箱函数
CopilotKit 开放生成式 UI高级在沙箱 iframe 中调用宿主端沙箱函数【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit导读本文围绕 CopilotKit 与 CrewAI Conversational Flows 集成项目中的open-gen-ui-advanced开放生成式 UI 高级版Demo 展开讲解完全开放的生成式 UI 模式Agent 直接生成一段 HTML/CSS/JavaScript 并渲染进沙箱 iframe同时通过宿主端注册的沙箱函数sandbox functions与页面本体完成双向交互。读完本文你将掌握openGenerativeUI运行时标志与前端 Provider 配置、宿主沙箱函数的注册与调用协议Websandbox.connection.remote.*以及如何用 E2E 测试验证iframe 内点击 → 宿主端执行 → 结果回写 iframe的完整链路。一、场景定位从受约束渲染到完全开放生成在 CopilotKit 的生成式 UI 体系中open-gen-ui-advanced属于开放生成式 UIOpen Generative UI一档。与基于预定义组件库或 A2UI Schema 的受约束模式不同这种模式下的 Agent 拥有极大自由度它直接产出可运行的 HTML/CSS/JavaScript前端将其安全地渲染在一个沙箱 iframe 中。而高级Advanced版本在open-gen-ui基础之上更进一步——Agent 生成的 iframe 内 UI 可以反向调用宿主页面注册的沙箱函数形成宿主 ↔ 沙箱的双向桥接。该能力在 manifest.yaml 中被登记为独立 featureopen-gen-ui-advanced其描述为 Agent-authored UI that invokes host sandbox functions from inside the iframeAgent 编写的 UI 从 iframe 内部调用宿主沙箱函数highlight 文件为page.tsxsandbox-functions.tscopilotkit-ogui 路由二、QA 验收清单与整体数据流仓库中的 QA 文档 open-gen-ui-advanced.md 给出了该功能的手工验收步骤访问/demos/open-gen-ui-advanced页面点击 Calculator (calls evaluateExpression) 建议词验证沙箱化计算器 UI 在 iframe 中渲染操作计算器如计算3 4.5验证结果由宿主端evaluateExpression更新点击 Ping the host (calls notifyHost)验证按钮触发远程调用并在沙箱中显示时间戳。背后对应的完整数据流为用户点击建议词 → 聊天组件将消息发送给 AgentCrewAI Conversational FlowAgent 流式返回一个generateSandboxedUi工具调用其中携带 HTML/CSS 以及通过jsFunctions声明的 in-iframe 点击处理器运行时的OpenGenerativeUIMiddleware由openGenerativeUI: { agents: [...] }开启将该工具调用流转换为open-generative-ui活动事件前端CopilotKitProvider 传入openGenerativeUI配置后内置的OpenGenerativeUIActivityRenderer将 Agent 编写的 HTML/CSS 挂载进带sandbox属性的 iframeiframe 内 UI 通过Websandbox.connection.remote.name(args)调用宿主端沙箱函数宿主执行完成后把返回值回传给 iframe 内调用方。这一流程的代码级注释记录在 page.tsx 的头部注释中。三、后端运行时为开放生成式 UI 单独开一条路由openGenerativeUI是运行时Runtime级别的标志一旦开启会在 probe 响应中全局设置openGenerativeUIEnabled: true这会影响默认运行时上的其他按 Demo 工具注册。因此仓库为开放生成式 UI Demo 专门隔离了一条运行时路由 copilotkit-ogui/route.ts。该路由的关键配置如下import { CopilotRuntime, createCopilotRuntimeHandler } from copilotkit/runtime/v2; import { HttpAgent } from ag-ui/client; const AGENT_URL process.env.AGENT_URL || http://localhost:8000; function createAgent() { return new HttpAgent({ url: ${AGENT_URL}/conversational_flows/frontend-tools, }); } const agents: Recordstring, AbstractAgent { open-gen-ui: createAgent(), open-gen-ui-advanced: createAgent(), }; export const POST async (req: NextRequest) { const copilotHandler createCopilotRuntimeHandler({ runtime: new CopilotRuntime({ agents, openGenerativeUI: { agents: [open-gen-ui, open-gen-ui-advanced], }, }), basePath: /api/copilotkit-ogui, mode: single-route, }); return await copilotHandler(req); };要点说明openGenerativeUI.agents数组用于声明哪些 Agent 允许产出开放生成式 UI这里open-gen-ui与open-gen-ui-advanced两个 Agent 都映射到同一个 CrewAI 端点/conversational_flows/frontend-toolsmode: single-route让该路由独立承载所有运行时请求避免与默认路由互相干扰从源码结构可以推断运行时中OpenGenerativeUIMiddleware负责把generateSandboxedUi工具调用流转换为open-generative-ui活动事件供前端内置渲染器消费。在 Python 侧/frontend-tools端点由FrontendToolFlow提供conversational_flows.py 中可以看到frontend-tools: _conversational_type(FrontendToolFlow)的映射注册Python 测试 test_specialized_flows.py 中也登记了open-gen-ui-advanced: /frontend-tools的对应关系。四、前端集成Provider 上的openGenerativeUI与建议词前端页面 page.tsx 通过CopilotKitProvider 的openGenerativeUI属性把沙箱函数数组交给内置渲染器use client; import { CopilotKit, CopilotChat, useConfigureSuggestions } from copilotkit/react-core/v2; import { openGenUiSandboxFunctions } from ./sandbox-functions; import { openGenUiSuggestions } from ./suggestions; export default function OpenGenUiAdvancedDemo() { return ( CopilotKit runtimeUrl/api/copilotkit-ogui agentopen-gen-ui-advanced openGenerativeUI{{ sandboxFunctions: openGenUiSandboxFunctions }} div classNameflex justify-center items-center h-screen w-full div classNameh-full w-full max-w-4xl Chat / /div /div /CopilotKit ); } function Chat() { useConfigureSuggestions({ suggestions: openGenUiSuggestions, available: always, }); return ( div classNameflex h-full w-full flex-col p-3 CopilotChat agentIdopen-gen-ui-advanced classNameflex-1 rounded-2xl / /div ); }三个关键点runtimeUrl/api/copilotkit-ogui指向第三节专门隔离的运行时路由openGenerativeUI{{ sandboxFunctions: [...] }}将宿主端沙箱函数数组注入 Provider内置的OpenGenerativeUIActivityRenderer会把这些函数作为可在 iframe 内调用的远端对象挂载进沙箱useConfigureSuggestions用于在聊天输入区常驻建议词available: always。建议词定义在 suggestions.ts共三条export const openGenUiSuggestions [ { title: Calculator, message: Calculator (calls evaluateExpression) }, { title: Ping the host, message: Ping the host (calls notifyHost) }, { title: Inline expression evaluator, message: Inline expression evaluator }, ];每条建议词的message字符串会原样作为 Agent 提示词同时也作为 aimock 固定夹具fixture的键在showcase/aimock/d5-all.json中存在与这些消息字符串逐字对齐的夹具条目以保证每次点击建议词都会触发确定性的generateSandboxedUi工具调用而不是被通用兜底夹具吸收。五、宿主沙箱函数定义、安全校验与调用协议沙箱函数是高级模式的灵魂定义在 sandbox-functions.ts。每个函数包含name、description、parametersZod Schema和handler四个部分名称、描述与由 Zod 推导出的 JSON Schema 会被注入 Agent 上下文让 LLM 在生成 HTML/JS 时知道有哪些桥可用。每个 handler 运行在宿主页面上其返回值会被 iframe 内的调用方 await。5.1 evaluateExpression宿主端安全求值{ name: evaluateExpression, description: Safely evaluate a basic arithmetic expression on the host page and return the numeric result. Supports , -, *, /, parentheses, and decimal numbers. Use this from inside a calculator or spreadsheet UI., parameters: z.object({ expression: z.string().describe(An arithmetic expression, e.g. 12 * (3 4.5)), }), handler: async ({ expression }: { expression: string }) { if (!/^[\d\-*/().\s]$/.test(expression)) { return { ok: false, error: Unsupported characters in expression. }; } try { const value Function(use strict; return (${expression});)(); if (typeof value ! number || !Number.isFinite(value)) { return { ok: false, error: Not a finite number. }; } console.log([open-gen-ui/advanced] evaluateExpression, expression, , value); return { ok: true, value }; } catch (err) { return { ok: false, error: err instanceof Error ? err.message : String(err) }; } }, }安全实现要点先用正则/^[\d\-*/().\s]$/白名单过滤仅允许数字、四则运算符、括号、小数点和空白任何含标识符或可疑字符的表达式直接返回ok: false绝不执行任意 JS通过Function(use strict; return (...))求值并对结果做typeof number与Number.isFinite双重校验返回统一结构{ ok, value }或{ ok: false, error }便于 iframe 内 UI 消费。5.2 notifyHost从沙箱向宿主发送通知{ name: notifyHost, description: Send a short notification message from the sandboxed UI to the host page. The host logs the message and returns a confirmation object., parameters: z.object({ message: z.string().describe(A short status message.), }), handler: async ({ message }: { message: string }) { console.log([open-gen-ui/advanced] notifyHost:, message); return { ok: true, receivedAt: new Date().toISOString(), message }; }, }该函数演示了沙箱 → 宿主的通知模式宿主仅记录消息并返回receivedAt时间戳ISO 字符串iframe 内 UI 拿到这个确认对象后即可把时间戳渲染出来——这正好对应 QA 清单第 5 步时间戳显示在沙箱中。5.3 调用协议两个 handler 的函数头注释明确了调用方式Agent 生成的 iframe 内脚本通过Websandbox.connection.remote.name(args)调用这些宿主函数源码见 sandbox-functions.ts。由于函数名、描述和 Schema 都被注入 Agent 上下文LLM 生成 HTML 时会把按钮的点击事件正确绑定到对应远端调用上。从设计上看这类函数的接口应保持小而明确——它们就是 Demo 的应用侧工具app-side tools供沙箱生成的 UI 调用。六、E2E 验证如何证明iframe 内点击 → 宿主执行 → 结果回写仓库为高级开放生成式 UI 提供了完整的 Playwright 测试 open-gen-ui-advanced.spec.ts这也是理解整条链路的最好活文档。测试分为两层断言6.1 冒烟层SMOKE每个提示词Calculator / Ping the host / Inline expression evaluator都断言产生一个srcdoc非空的iframe[sandbox*allow-scripts]确认 open-gen-ui 管线成功挂载了内容。测试通过frameLocator与sandboxallow-scriptsiframe 交互依赖 CDP不受 null origin 限制。6.2 往返层ROUND-TRIP驱动 iframe 内控件断言宿主端 handler 确实执行通过宿主 console 中稳定的[open-gen-ui/advanced]前缀日志捕获且 iframe 内输出元素被宿主返回值更新Ping 测试点击 iframe 内#hi按钮 → 宿主notifyHost被触发 → 断言 iframe#out元素包含 host replied at内联表达式求值测试向#in输入框pressSequentially(22)注释说明fill()在allow-scripts沙箱 iframe 内可能静默失效按键序列总是可达→ 点击#go→ 断言宿主日志出现 4且#out显示 4计算器测试依次点击数字2、运算符、数字3按钮再点#eq→ 断言宿主日志出现 5且显示区#d文本为 5。测试头部注释还透露了两个工程细节驱动采用textarea 填充 回车而非点击建议词 pill因为页面存在 EmptyState 与 SuggestionBar 两套 chip 表面依赖messages.length挂载pill 点击存在时序抖动两条路径最终都会触发同一个runAgentd5-all.json 夹具在 feature-parity.json 之前加载其 first-match-wins 顺序能命中精确的建议词消息避免落入会返回通用问候语的userMessage: hi兜底夹具。6.3 测试要点速查测试项操作路径断言页面加载访问/demos/open-gen-ui-advanced3 个建议词 pill 可见冒烟三条提示词填充输入框并回车iframe[sandbox*allow-scripts]可见且srcdoc/src非空Ping 往返iframe 内点击#hi宿主日志含notifyHost#out含 host replied at内联求值往返#in输入22点击#go宿主日志 4#out含 4计算器往返依次点2、、3、#eq宿主日志 5#d文本为 5七、与基础版open-gen-ui的对照基础版 open-gen-ui 页面 与高级版共用同一条/api/copilotkit-ogui运行时路由两者都列在openGenerativeUI.agents中。两者的本质区别在于基础版Agent 只生成静态 HTML/CSS/可视化内容渲染进沙箱 iframe 即可不涉及宿主回调其 design-skill.ts 通过向 Agent 注入视觉设计技能如像教科书插图或可探索解释一样来约束产出质量高级版在基础能力之上注册宿主沙箱函数让 iframe 内 UI 拥有对外部世界的副作用能力求值、通知等把沙箱从展示容器升级为可交互应用宿主。两者共同的约束是 iframe 安全模型Agent 产出的 HTML 不包含form、不使用typesubmit事件一律通过addEventListener绑定见 suggestions.ts 注释这些约束会写进系统提示词中。八、运行与验证方式该 Demo 位于 CrewAI Conversational Flows 集成 showcase 中manifest.yaml 登记的 slug 为crewai-conversational-flowscopilotkit_version: 2.0.0后端语言 PythonAgent 端点为/conversational_flows/frontend-tools。典型运行方式为启动 Python 后端CrewAI Conversational Flows默认监听http://localhost:8000可用AGENT_URL环境变量覆盖启动 Next.js 前端访问/demos/open-gen-ui-advanced手工按 QA 清单验证或运行tests/e2e/open-gen-ui-advanced.spec.ts进行自动化回归。需要说明的适用前提openGenerativeUI为运行时级全局标志开启会影响 probe 响应因此仓库将其隔离在独立路由/api/copilotkit-ogui上避免干扰默认运行时中按 Demo 的工具注册——在自己项目中接入该能力时建议沿用同样的路由隔离策略。结语open-gen-ui-advanced展示了生成式 UI 的一个关键进阶Agent 自由生成界面而宿主通过注册沙箱函数为其提供受控的能力边界。evaluateExpression的白名单正则与有限性校验、notifyHost的简单确认回执加上 E2E 测试对宿主日志 iframe 输出的双重断言共同勾勒出一条清晰、可验证、可复用的开放生成 沙箱桥接实践路径。【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考