如何在 React Native 中用 @copilotkit/react-native/headless 搭建 CopilotKit 聊天界面

发布时间:2026/9/11 14:12:56
如何在 React Native 中用 @copilotkit/react-native/headless 搭建 CopilotKit 聊天界面 如何在 React Native 中用 copilotkit/react-native/headless 搭建 CopilotKit 聊天界面【免费下载链接】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在 React Native 项目里你往往不想要 CopilotKit 自带的聊天组件而想用自己的FlatList、TextInput拼一个完全自定义的聊天界面。copilotkit/react-native/headless就是这个场景的入口它只提供CopilotKitProvider和一组平台无关的 hooksuseAgent、useCopilotKit、useFrontendTool等不带任何预渲染 UI也不引入聊天/附件相关的原生依赖。本文围绕这条最短主路径走一遍装包、配 polyfill、起一个本地 Copilot Runtime、用 hooks 搭出聊天屏、运行最后验证它真的能收发。适用前提来自源文档一个 OpenAI API key或其他受支持的模型 provider、React Native 0.70bare CLI 或 Expo、Node.js 20。/headless子路径从1.64.0起提供且需要 package exports 解析Metro 0.82 / React Native 0.79 起默认开启React Native 0.72–0.78 需手动开resolver.unstable_enablePackageExports true0.72 以下不支持。准备安装依赖在 React Native 工程根目录安装前端包和本地 Runtime并装上跑 runtime 用的tsx工具链npm install copilotkit/react-native copilotkit/runtime npm install -D tsx typescript types/nodepnpm 用pnpm add .../pnpm add -D ...yarn 用yarn add ...等价。装完先确认实际解析到的版本因为/headless只存在于 1.64.0 及以上npm ls copilotkit/react-native如果你项目固定在 1.63.x 或更早/headless在 bundle 阶段会报Unable to resolve module copilotkit/react-native/headlessMetro 看起来像装坏了其实是版本不匹配。优先升到 1.64.0。若因对齐固定的copilotkit/runtime而无法升级同一套CopilotKitProvider、useAgent、useCopilotKit也从包根copilotkit/react-native导出把导入路径里的/headless去掉即可。注意这不是零成本替换——旧版本根桶静态 import 了expo-document-picker和expo-file-system你必须装或 stub这两个否则 release bundle 会报Unable to resolve module expo-document-picker。/headless的导出面无 native peer 依赖Metro 不需要解析聊天/附件模块对照 headless 入口 可以看到它导出CopilotKitProvider、useAgent、useCopilotKit、useFrontendTool、useRenderTool等。入口文件polyfill 必须最先加载React Native 的 JS 运行时Hermes缺少 CopilotKit 依赖的若干 Web API。包会在首次 import 时自动安装这些 polyfill但有两件事必须发生在入口文件最顶部、任何 CopilotKit import 之前先装安全随机源再引 polyfill barrel。先装安全 RNGnpm install react-native-get-random-valuesimport react-native-get-random-values; // 安全 RNG —— 必须在第一行 import copilotkit/react-native/polyfills; import { AppRegistry } from react-native; import App from ./App; import { name as appName } from ./app.json; AppRegistry.registerComponent(appName, () App);导入顺序对 crypto 是有硬约束的CopilotKit 的cryptopolyfill 和react-native-get-random-values都只在crypto.getRandomValues仍为 undefined 时安装——先写者胜出。如果任何 CopilotKit 模块先被求值CopilotKit 非加密的Math.random回退会被永久锁定react-native-get-random-values变成静默 no-op。所以安全 RNG 必须留在第一行。可选分支——如果某些 API 你已经在别处 polyfill 了比如ReadableStream可以不引 barrel只引需要的细粒度子路径import copilotkit/react-native/polyfills/streams; import copilotkit/react-native/polyfills/encoding; import copilotkit/react-native/polyfills/crypto; import copilotkit/react-native/polyfills/dom; import copilotkit/react-native/polyfills/location;创建 Copilot Runtime加一个小的 Node 服务把 Copilot Runtime 挂在/api/copilotkit上并注册一个名为default的内置 agentimport { createServer } from node:http; import { BuiltInAgent, CopilotRuntime } from copilotkit/runtime/v2; import { createCopilotNodeListener } from copilotkit/runtime/v2/node; const runtime new CopilotRuntime({ agents: { default: new BuiltInAgent({ model: openai:gpt-5-mini, prompt: You are a helpful assistant for a React Native app., }), }, }); const port Number(process.env.PORT ?? 8200); createServer( createCopilotNodeListener({ runtime, basePath: /api/copilotkit, cors: true, }), ).listen(port, () { console.log( Copilot Runtime listening at http://localhost:${port}/api/copilotkit, ); });model用provider:model或provider/model字符串形式时runtime 会从对应环境变量读 keyopenai读OPENAI_API_KEY。createCopilotNodeListener直接接到 Node 内置node:http的createServer不依赖 Hono 或 Express。要指向 OpenAI 兼容端点时设置OPENAI_BASE_URL同理ANTHROPIC_BASE_URL、GOOGLE_GENERATIVE_AI_BASE_URL未设置时 provider 回退到默认端点无需自建模型实例。用 CopilotKitProvider 指向 runtimeCopilotKitProvider是一个只提供 context、自己不渲染视图的 provider作为最外层包装。runtimeUrl是唯一必填 prop。注意地址要换成设备能到达的Android 模拟器用10.0.2.2模拟器对宿主机localhost的别名iOS 模拟器可直接用localhost。import { CopilotKitProvider } from copilotkit/react-native/headless; import { Platform } from react-native; import { ChatScreen } from ./src/ChatScreen; const runtimeUrl Platform.OS android ? http://10.0.2.2:8200/api/copilotkit : http://localhost:8200/api/copilotkit; export default function App() { return ( CopilotKitProvider runtimeUrl{runtimeUrl} ChatScreen / /CopilotKitProvider ); }真机测试时把localhost/10.0.2.2换成开发机的局域网 IP例如http://192.168.1.23:8200/api/copilotkit。headers可传Recordstring, string或返回它的函数用于鉴权例如Authorizationbearer若传函数它是在 provider渲染时被调用并 memoize 的不是每次请求都重读token 轮换要靠 React 状态触发重渲染或改用copilotkit.setHeaders。React Native provider 目前不支持 web 侧的publicApiKey/licenseToken云 props只能通过runtimeUrl连你自己的 Runtime。用 useAgent 和 useCopilotKit 搭聊天屏/headless给的是 hooks 而非组件所以聊天界面完全由标准 React Native 组件构成。下面是一个最小聊天屏用useAgent拿 agent 和消息用useCopilotKit拿实例来跑一轮。发送一轮是两步——agent.addMessage(...)然后copilotkit.runAgent({ agent })runner 在 core 上不在 agent 上。import { useCallback, useRef, useState } from react; import { FlatList, KeyboardAvoidingView, Platform, Text, TextInput, TouchableOpacity, View, } from react-native; import { useAgent, useCopilotKit } from copilotkit/react-native/headless; export function ChatScreen() { const [inputText, setInputText] useState(); const flatListRef useRefFlatList(null); const { copilotkit } useCopilotKit(); const { agent } useAgent({ agentId: default }); const messages agent?.messages ?? []; const isLoading agent?.isRunning ?? false; const chatMessages messages.flatMap((message) { if ( (message.role user || message.role assistant) typeof message.content string message.content.length 0 ) { return [{ id: message.id, content: message.content }]; } return []; }); const handleSend useCallback(async () { const text inputText.trim(); if (!text || isLoading || !agent) return; setInputText(); agent.addMessage({ id: user-${Date.now()}, role: user, content: text, }); await copilotkit.runAgent({ agent }); }, [inputText, isLoading, agent, copilotkit]); return ( KeyboardAvoidingView style{{ flex: 1 }} behavior{Platform.OS ios ? padding : height} FlatList ref{flatListRef} data{chatMessages} renderItem{({ item }) ( View style{{ padding: 12, maxWidth: 80% }} Text{item.content}/Text /View ) keyExtractor{(item, i) item.id ?? String(i)} onContentSizeChange{() flatListRef.current?.scrollToEnd({ animated: true }) } / View style{{ flexDirection: row, padding: 8 }} TextInput style{{ flex: 1, borderWidth: 1, borderRadius: 8, padding: 8 }} value{inputText} onChangeText{setInputText} placeholderType a message... / TouchableOpacity onPress{handleSend} style{{ padding: 8 }} TextSend/Text /TouchableOpacity /View /KeyboardAvoidingView ); }如果 agent 会调你应用里的函数并渲染 UI用useFrontendTool注册parameters是 Standard Schemazod是copilotkit/react-native的可选 peer 依赖需要的话把它加进应用。工具注册在设备端模型调用到达你客户端的handler让改 UI 的工具走客户端useFrontendTool而不是放进服务端tools列表。要渲染 markdown注意自定义 UI 里普通Text会原样显示 markdown——想渲染 markdown 要复用CopilotMarkdown或自带渲染器。启动 runtime 和 App一个终端起 Copilot Runtimeexport OPENAI_API_KEYsk-... npx tsx server.ts另一个终端跑 React Native App# iOS npx react-native run-ios # Android npx react-native run-android验证是否跑通移动端没有浏览器所以验证靠下面几步组合源文档明确说明单看其中任何一步都不足以判定成功runtime 可达且 agent 能应答——从托管 runtime 的机器不是设备上跑npx copilotkit verify --round-trip --runtime-url http://localhost:8200/api/copilotkit它通过 runtime 发一个请求并把答案从线程读回来用于区分agent 配置好了和agent 真能跑。CLI 默认探测http://localhost:3000/api/copilotkit所以要显式传--runtime-url http://localhost:8200/api/copilotkitruntime 声明了多个 agent 时再传--agent id。注意它只证明有答案回来不保证答案内容也不说明是哪个部署应答的——所以这是第一步不是绿灯。确认/info能列出 default agent、且设备能到达runtimeUrl访问http://localhost:8200/api/copilotkit/info应返回defaultagent。真机要用开发机局域网 IP 而非localhost。工具 UI 真的渲染在设备上——起模拟器、驱动 App、截屏。Androidadb devices # 确认有一个已启动目标 adb exec-out screencap -p proof.png # 截屏 adb logcat -d -s ReactNativeJS:E # 没有未解决的 redboxUSB 真机先执行adb reverse tcp:8200 tcp:8200让设备上的localhost能到你的 runtimeadb reverse仅限 AndroidiOS 没有对应命令。iOS 用xcrun simctl io booted screenshot proof.png最接近且需要完整 Xcode——仅 Command Line Tools 不带simctl。如果环境里根本没有模拟器直接说明不要拿浏览器截图顶替。常见问题排查按源文档列出的现象对照Metro 无法解析模块清缓存npx react-native start --reset-cache。流式不工作确认 polyfill 在入口文件里先于任何 CopilotKit 代码导入。runtime 无响应确认 runtime 服务在跑、http://localhost:8200/api/copilotkit/info能返回defaultagent、设备能到达runtimeUrl真机用局域网 IP 而非localhost。模型鉴权错误确认运行npx tsx server.ts的那个终端里设置了OPENAI_API_KEY。Property ReadableStream doesnt exist或TextEncoder、DOMException、Headers同类报错polyfill 没装上。1.69.2 及更早所有版本里polyfillsbarrel 被发布成空的构建把五个 polyfill import 都丢了所以照上面装的等于啥也没装。升级到最新版即可若被固定改用上面列出的细粒度 import这些从未受影响。已有 polyfill 冲突用细粒度 import 替换 barrel 的polyfillsimport。release bundle 可能因jose经遥测链路copilotkit/shared→segment/analytics-node→jose引入 Node 版node:模块而报Unable to resolve module node:crypto只在 bundle 时出现、typecheck 不报。修法是在metro.config.js里对jose及jose/前缀单独用resolver.resolveRequest指到它的browsercondition而不是全局断言browser全局断言会改整个依赖图的解析并丢掉 Metro 默认的react-nativecondition。/headless能免去为聊天/附件 peer 写 stub但jose这条 resolver 与导入面选择无关两种情况都需要。限制与边界自定义 UI 里的 markdown普通Text原样显示 markdown复用CopilotMarkdown或自带渲染器CopilotMarkdown由react-native-streamdown支撑。useAgent上的threadId暂不支持传进去不过类型检查且会被忽略线程隔离来自 chat-configuration provider。云 provider propsReact Native provider 不支持publicApiKey/licenseToken只能连runtimeUrl。Web 专属渲染 hooks 不导出useDefaultRenderTool、useRenderCustomMessages、useRenderActivityMessage均不可用useRenderToolCall是导出的可把已注册的工具调用画在聊天外的任意表面。useRenderTool是 React Native 自己的 hook非 react-core 的它同时注册工具与渲染器所以别再用useFrontendTool注册同名工具在这里不要用*作为名字会注册一个真名为*的前端工具并广播给模型。Voicecopilotkit/voice未适配 React Native语音需自带 STT拿到转写后走同一条agent.addMessagecopilotkit.runAgent发送路径。Inspector是浏览器 overlayReact Native 无对应面copilotkit/react-native不打包它。延伸阅读完整场景与更多细节React Native 文档模型选择、key 与自定义端点Model Selection/headless的导出实现headless 入口包版本与 peer 依赖package.json【免费下载链接】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),仅供参考