news 2026/10/2 7:13:28

深入 OpenMuse 与 CopilotKit AG-UI 集成:Rich Threads 持久化与流式事件渲染内幕

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入 OpenMuse 与 CopilotKit AG-UI 集成:Rich Threads 持久化与流式事件渲染内幕

深入 OpenMuse 与 CopilotKit AG-UI 集成:Rich Threads 持久化与流式事件渲染内幕

【免费下载链接】openmuseA personal agent with a browser, terminal, files, and work that keeps going built with CopilotKit and AG-UI.项目地址: https://gitcode.com/gh_mirrors/op/openmuse

OpenMuse 是一个自带浏览器、终端和文件的个人 Agent,任务关闭 App 后也能继续推进。它基于 CopilotKit 构建,核心体验由 AG-UI 流式事件与 Rich Threads 持久化两套机制支撑:回复实时流式渲染为工具卡片,整段对话随时可重放、重命名、归档与恢复。本文带你走进源码,讲清这套机制是如何实现的。

3 件事让你用上 Rich Threads 持久化

OpenMuse 的客户端是共享 iOS、Android 与 Web 的 React Native 应用(源码位于 apps/mobile/),聊天、工具卡片与文档全部通过 CopilotKit 的 headless 钩子渲染。服务端则是一个 Hono API,内嵌 CopilotRuntime 与任务引擎(apps/server/src/agent.ts)。

启用 Rich Threads 只需三步:

  1. 克隆仓库并安装依赖:git clone https://gitcode.com/gh_mirrors/op/openmuse
  2. 运行npx copilotkit@latest login与npx copilotkit@latest project select,生成项目密钥
  3. 把密钥作为CPK_INTELLIGENCE_API_KEY放入 API 服务器环境变量后重启

密钥必须只留在服务端——缺失时 API 会直接启动失败,避免"静默丢对话"。

主对话为何刷新后依然是同一条

这是新手最容易困惑的地方:为什么重新打开应用,主对话不会变成一条新对话?

服务端先"占座"。客户端启动时请求 /api/main-thread:服务端用insertIfAbsent为每个用户固化一个主对话 threadId,再通过intelligence.getOrCreateThread在 CopilotKit Intelligence 中预置它。这样即便首条消息还没发出就刷新,主对话也保持不变。

客户端做重放。选择一条已保存对话时,chat.tsx 会挂载一个私有 Agent 实例(agentId形如openmuse-<threadId>),然后调用copilotkit.connectAgent让 Intelligence 重放整条线程消息。切换过的对话会保持挂载,草稿与消息队列不会因页面导航而丢失。

线程菜单全靠useThreads。threads.tsx 中一个useThreads({ agentId: "default", includeArchived: true, limit: 20 })钩子就覆盖了列出、重命名、归档、恢复与分页加载更多;侧边聊天则由客户端生成全新 threadId,在首次运行时落盘。注意自动命名被关闭(agent.ts 中generateThreadNames: false),命名完全交给用户。

流式事件渲染内幕:一条 AG-UI 事件之旅

流式体验的关键在 engine/conversation.ts:ConversationAgent继承 AG-UI 的AbstractAgent,其run()返回一个Observable<BaseEvent>事件流。一次回复的骨架是:

RUN_STARTED→TEXT_MESSAGE_START/TEXT_MESSAGE_CONTENT(增量文本)/TEXT_MESSAGE_END→ 穿插TOOL_CALL_START/TOOL_CALL_ARGS/TOOL_CALL_END/TOOL_CALL_RESULT→RUN_FINISHED(失败则RUN_ERROR)

这些事件经 app.ts 中挂载在/api/copilotkit/*的 runtime 以 SSE 推给客户端,代码里甚至专门把字符串 chunk 转成字节流,保证浏览器正确接收。

工具卡片是"钩子"而非硬编码。客户端用useRenderTool为每个工具注册渲染器(如browse_web→ 带实时截图的浏览器卡片、search_mail→ 邮件卡片),再由useRenderToolCall在消息流中按toolCallId配对渲染,详见 chat.tsx。这就是"生成式 UI":Agent 调一次工具,界面上就多一张可交互卡片。

富工具消息:任务卡片为何永远是"最新"的

重放一条老对话时,消息里存的是任务 ID 而不是结果快照。渲染器(thread-artifacts.tsx 中的TaskThreadCard)拿到 ID 后,实时请求/api/agent/tasks/<id>拉取当前任务状态、浏览器预览与 PDF 链接。

还有一个安全细节:文件和预览的短时效签名 URL 每次由服务端现场生成,绝不存入线程消息。线程只保留稳定 ID,既避免链接过期,也让历史对话可无限期回放。

跟随队列与停止:让对话"有手感"的细节

  • 回复期间输入框保持可编辑:后续消息进入可见、可删除的队列,当前回复及其持久化完成后按序发送(conversation-queue.ts)。
  • 停止即暂停队列:点停止按钮调用copilotkit.stopAgent,草稿完整保留,队列挂起而非清空;SDK 层的错误也会通过订阅onError统一收敛(conversation-run.ts)。
  • 队列只活在打开的 App 里:它不是服务器收件箱,委派给服务端的长任务则是独立的持久化工作,两者互不混淆。

下一步:从哪里继续读

  • 官方文档入口:docs/README.md
  • Rich Threads 配置与验证边界:docs/RICH-THREADS.md
  • 交互设计与对话行为:docs/EXPERIENCE.md
  • 服务端 Agent 与工具定义:apps/server/src/engine/conversation.ts
  • 客户端线程与聊天实现:apps/mobile/src/
  • 相关测试(真实 runtime + 模拟 Intelligence 边界):tests/rich-threads.test.ts

一句话总结:Rich Threads 负责"对话永远在",AG-UI 流式事件负责"过程看得见"。两者在 OpenMuse 中分工清晰——持久化交给 CopilotKit Intelligence 与稳定 ID,渲染交给事件驱动的 headless 钩子——这正是它既像聊天应用、又像工作台的原因。

【免费下载链接】openmuseA personal agent with a browser, terminal, files, and work that keeps going built with CopilotKit and AG-UI.项目地址: https://gitcode.com/gh_mirrors/op/openmuse

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 7:13:27

057二分查找

二分查找 - 每次消灭一半可能性 057二分搜索&#xff1a;对半分的艺术&#x1f4f0; 5W1H 发明者故事 Who&#xff08;何人&#xff09;- 发明者是谁&#xff1f; 发明者&#xff1a;约翰莫奇利&#xff08;John Mauchly&#xff0c;ENIAC发明者之一&#xff0c;1946年提出&a…

作者头像 李华
网站建设 2026/10/2 7:13:21

激光打标机厂推荐:全自动视觉定位设备生产厂家质量参考评选

南京鼎信机电设备有限公司&#xff0c;是一家专注于激光打标机、气动打标机及激光焊接设备研发生产的制造型企业&#xff0c;成立于2009年&#xff0c;深耕工业标记细分领域十余载。一句话概括企业定位&#xff1a;以质取信、以信为本&#xff0c;为各类制造工厂提供稳定耐用、…

作者头像 李华
网站建设 2026/10/2 7:13:19

Redis八股高频面试总结个人开源笔记

redis底层数据结构 Redis对外暴露了5种基本数据类型&#xff0c;但底层为了兼顾内存效率和操作性能&#xff0c;实际使用了多种物理数据结构。同一种上层类型在不同数据量下&#xff0c;底层类型还会自动切换。 1.String底层数据结构是SDS&#xff0c;简单动态字符串&#xff0…

作者头像 李华
网站建设 2026/10/2 7:12:46

ESP32 External RAM failed memory test报错排查与解决

玩ESP32遇到这行日志“External RAM failed memory test!”&#xff0c;十有八九是板子刚焊好、PSRAM刚贴上去&#xff0c;或是换了一颗Flash/PSRAM之后上电就卡死在启动阶段。ESP32在启动流程里会自动检测并用缓存控制器测试外部SPI RAM&#xff0c;这个测试一旦不过&#xff…

作者头像 李华
网站建设 2026/10/2 7:12:05

动态目标三维重构在应急盲区目标运动推演中的应用

摘要灾害坍塌、楼宇搜救、山林抢险、城市巷战等应急处置场景普遍存在大量视觉盲区与动态遮挡&#xff0c;墙体隔断、废墟堆叠、浓烟水雾、地形沟壑、设备遮挡极易造成救援人员、作业装备、被困目标短时消失、视野失联、轨迹断裂&#xff0c;形成应急态势感知“盲空地带”。传统…

作者头像 李华