惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
Y
Y Combinator Blog
博客园 - 【当耐特】
V
Visual Studio Blog
GbyAI
GbyAI
V
V2EX
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
D
DataBreaches.Net
Hugging Face - Blog
Hugging Face - Blog
A
About on SuperTechFans
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
N
Netflix TechBlog - Medium
aimingoo的专栏
aimingoo的专栏
B
Blog RSS Feed
量子位
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
Stack Overflow Blog
Stack Overflow Blog
小众软件
小众软件

博客园 - 大树2

agent经典的ReAct过程 Dify用于建 AI 应用(chat,agent,工作流,RAG,MCP, web App)的平台 国内主流大模型的API的申请地址 AI 智能体架构设计的12条原则 AI Agent 是如何一步步开发完成的 Crew AI 多agent 技术媒体编辑部:批量生产科技文章 demo 使用CrewAI 多agent 协作,创作高考优秀作文的demo 使用本地ollama 部署的模型,不需要token,使用ollama及第三方向量模型 RAG 中英双语 Embedding 嵌入模型 langgraph LLM 大模型 做意图分类 llamaindex 开源 RAG 框架 使用汇总 面向多模态检索的向量数据库对比分析和技术选型Chroma,PGVector,Milvus UV python的包和环境管理工具 cursor AI工具配合编程总结 FastApi python, React TS 快速构建AI agent开发 Python conda 调用AI 模型 扣子 工作流程开发 AI图片,图像工具,创作工具 安装openclaw ClawHub CLI openclaw skills 安装 的三种方式:命令安装,手动下载安装,web ui安装 openclaw 学习资源 与三种沙箱模式的区别及配置 Cursor的四大模式:Agent、Plan、Debug、Ask,到底怎么用,能让效率翻倍 你能想到的openclaw 落地应用场景有哪些? windows cmd安装openclaw openclaw 安装手册及链接飞书 conda安装,langchain使用,国内提供大模型api调用的平台 langChain 大模型开发知识汇总 AI大模型应用开发知识体系 Nacos核心参数配置,解决某个应用注册后没有心跳问题,可能是将该服务配置为临时服务 腾讯云:购买域名,域名解析,域名备案,安全组,SSL证书,配置ssl证书,nginx转发
Cumora AI Agent 协同工作平台
大树2 · 2026-09-10 · via 博客园 - 大树2

Human + AI Agent 协同工作平台 / Multi-Agent Team Workspace

1. 系统定位

Cumora 是一个把 AI Agent 作为一等成员的跨平台团队协作系统。人类与 Agent 共用以下协作对象:

  • 群聊、私聊、引用、反应、投票和附件;
  • 项目、看板、日历、文档和邮件;
  • 在线状态、输入状态、通知和协同编辑;
  • Agent 记忆、技能、运行记录、模型调用和成本账本。

系统最重要的架构决策不是“聊天界面调用大模型”,而是将 Agent 拆成两个相互独立的部分:

Agent = Brain(推理与决策) + Computer(执行宿主)

Brain 可以是 Cumora 托管的 OpenAI 兼容模型循环,也可以是用户机器上的 Claude Code、Codex 等本地引擎。两条路径共享同一套消息、工具、权限和持久化协议。

2. 架构原则

2.1 PostgreSQL 是业务真源

消息、成员关系、会话、项目、文档索引、日历、邮件、Agent 运行记录和认证状态最终都落在 PostgreSQL。

Redis 不承担核心业务真源职责,主要用于:

  • 跨实例 pub/sub;
  • WebSocket 实时事件;
  • Agent wake/steer 信号;
  • 短 TTL 协调状态;
  • 频率限制与 freshness boundary。

因此,短暂丢失 Redis 事件不会直接丢失已经提交的消息。客户端可以重新拉取,Agent 也会在连接后重新读取 inbox。

2.2 写入和通知分离

典型写链路遵循:

校验身份与租户
  -> 数据库事务写入
  -> 提交事务
  -> 发布 Redis 事件
  -> WebSocket / Agent scheduler / Push 消费

数据库写入是事实,Redis 事件是“尽快通知其他执行者”的加速层。

2.3 人类身份与 Agent 身份分离

系统存在三个不同的授权平面:

  • 人类客户端:OAuth 身份 + session Bearer token;
  • WebSocket:由 session 换取的 60 秒单次 ticket;
  • Agent runtime:绑定 agentId + companyId 的 runtime JWT。

BYOA daemon 还拥有设备凭据。模型子进程本身不应拿到 runtime JWT、服务端地址或设备密钥。

2.4 Agent 的 I/O 与 Brain 解耦

无论 Agent 由云端模型还是本地 CLI 驱动,业务动作最终都收敛到相同的 cumora 命令语义,再由 runtime API 执行。

Brain
  -> 结构化工具 / cumora argv
  -> runtime authorization
  -> 领域操作
  -> PostgreSQL
  -> Redis 实时事件

这使模型供应商、执行宿主和协作数据模型可以独立演进。

2.5 大模型只用于真实任务

模型分为两层:

  • Brain:真实 Agent 回合与 convene 发言;
  • Cerebellum:分类、triage、压缩、摘要、路由、日程判断等辅助任务。

server/src/agents/model-policy.ts 是运行时策略入口;CI 中还有静态 guard 防止辅助任务误用昂贵模型。

3. 系统上下文

flowchart LR Human[人类用户] Desktop[Electron Desktop] Mobile[iOS / Android] Web[Web 登录壳] Admin[Admin 管理端] API[Cumora Node 服务\nAPI + Runtime + WS + SPA] PG[(PostgreSQL)] Redis[(Redis)] Storage[(本地磁盘 / R2)] Managed[Managed Agent Pods] BYOA[BYOA Daemon\n用户电脑或 VPS] Provider[OpenAI 兼容模型供应商] EmailGate[Cloudflare Email Worker] R2Gate[Cloudflare R2 Gate] Resend[Resend] Push[APNs / FCM] Human --> Desktop Human --> Mobile Human --> Web Human --> Admin Desktop <-->|HTTP + WS| API Mobile <-->|HTTP + WS| API Web -->|OAuth / handoff| API Admin -->|Admin API| API API <--> PG API <--> Redis API <--> Storage API -->|创建/唤醒| Managed API <-->|SSE + Runtime API| Managed API <-->|SSE + Runtime API| BYOA Managed --> Provider BYOA --> Provider EmailGate -->|HMAC webhook| API API --> Resend API --> Push Storage --> R2Gate

4. 仓库结构与交付边界

本仓库不是 npm workspaces,而是一个主应用加若干独立子包。

4.1 主应用

  • src/:React renderer,共享 UI、状态层和 API 客户端;
  • server/:Express、WebSocket、数据库、Agent runtime 和后台任务;
  • electron/:桌面宿主、系统集成和自动更新;
  • ios/android/:Capacitor 原生容器;
  • public/:前端静态资源;
  • docs/:产品与运行时设计文档。

4.2 Agent 交付物

  • agent-cli/:发布到 npm 的 BYOA daemon 启动入口;
  • agent-fuse/:Managed Agent Pod 使用的 Go FUSE 工作区桥;
  • server/docker/agent-computer.Dockerfile:Managed Agent 运行镜像;
  • server/src/agents/computer/:BYOA daemon 和本地引擎适配器;
  • server/src/agents/runtime/:两类 Agent 共用的 runtime 协议与编排。

4.3 边缘组件

  • workers/email-gate/:接收 Cloudflare Email Routing 邮件并签名转发;
  • workers/r2-gate/:公开头像与受签名保护附件的读取网关;
  • website/:营销站点;
  • benchmarks/:多 Agent 协作基准。

4.4 工程与发布

  • scripts/:架构 guard、发布 smoke 和资源生成;
  • .github/workflows/:PR、构建、部署、发布和生产回读;
  • server/docker/:服务端与 Agent 镜像;
  • server/k8s/:GKE 和本地 Kubernetes 清单;
  • compose.yaml:PostgreSQL、Redis 和应用的本地容器拓扑。

5. 前端架构

5.1 单 renderer、多宿主壳

所有前端形态共享一份 React bundle。src/App.tsx 根据运行上下文选择壳:

App
├─ NotificationWindow   # Electron 独立通知窗口
├─ AdminApp             # admin.* 或 /admin
├─ InviteAcceptScreen   # 邀请流程优先于普通壳
├─ WebShell             # app.* 的 OAuth 与桌面端 handoff
└─ AuthGate
   └─ AuthedApp
      ├─ Onboarding     # 免费层必须先配对自有 Computer
      ├─ MobileApp      # Capacitor 或移动 viewport
      └─ DesktopApp     # Electron/桌面布局

Desktop 与 Mobile 共享业务数据和多数业务组件,但拥有独立导航与布局状态。WebShell 不是完整 Web 聊天端,而是登录和桌面应用交接面。AdminApp 使用相同认证体系,但不加载聊天 stores。

5.2 状态分层

前端采用 Zustand,状态可以按职责分为四类。

身份与作用域

  • src/stores/auth.ts:token、用户、公司列表和当前公司;
  • src/stores/contextEpoch.ts:租户/登录态切换后的异步写入隔离;
  • src/stores/preferences.ts:用户偏好。

contextEpoch 的作用是阻止旧请求在切换 workspace 后回写当前界面。App 同时通过 userId + companyId remount 主壳,形成第二层隔离。

UI 导航状态

  • src/stores/app.ts:当前视图、选中会话、移动导航栈、右侧详情、thread、artifact peek 和 composer;
  • composerDrafts.ts / composerDraftsStorage.ts:会话草稿;
  • sound.ts:声音偏好;
  • devtools.ts:本地开发开关。

实时业务投影

  • messages.ts:消息列表、流式 delta、typing;
  • conversations.ts:会话、未读、mute 和最后消息;
  • participants.ts:成员、状态和头像;
  • computers.ts:Computer 在线状态和引擎能力;
  • whispers.ts:Agent 私下交流视图。

工作对象

  • documents.ts:文档元数据;
  • boards.ts:看板、列、卡片和评论;
  • calendar.ts:日历事件与派发;
  • shipping.ts:交付流程。

5.3 前端数据流

flowchart LR View[React View] Store[Zustand Store] HTTP[HTTP Client] WS[WsClient] API[Server API] View -->|action| Store Store -->|request| HTTP HTTP -->|Bearer + x-company-id| API API -->|response| Store API -->|Redis -> WS event| WS WS -->|patch / reload| Store Store -->|selector| View

规则:

  1. UI 不直接维护服务端真源,只维护当前租户的投影;
  2. HTTP 负责命令与初始查询;
  3. WebSocket 负责增量事件;
  4. 重连、hello 或作用域变化后重新拉取,恢复与数据库的一致性;
  5. 401 自动清除 auth,返回登录流程。

5.4 API 地址解析

src/api/client.ts 按以下优先级确定服务端 origin:

localStorage['cumora.serverUrl']
  -> VITE_CUMORA_API_BASE
  -> 当前页面同源

运行时切换 origin 会清空 session 并要求整页重载,避免旧服务请求与新服务状态交叉。

5.5 WebSocket 与文档协同

客户端不会把长期 session token 放入 WebSocket URL。连接前先调用 /api/auth/ws-ticket,再使用一次性 ticket 连接 /ws?t=...

同一条 WebSocket 基础设施承载:

  • 消息新增与流式 delta;
  • typing、participant/computer status;
  • reaction、poll、board、calendar;
  • conversation 更新与 convene;
  • Yjs 文档 update、awareness 和 mention。

文档编辑使用 Tiptap + Yjs。客户端 src/lib/yjsClient.ts 与服务端 server/src/documents/rooms.ts 共同维护房间状态,Redis 负责多服务实例之间的 CRDT 更新转发。

5.6 宿主差异

Electron

  • electron/main.cjs:窗口、协议、生命周期和系统集成;
  • electron/preload.cjs:受控 IPC bridge;
  • electron/autoUpdater.cjs:自动更新;
  • 生产使用 app:// 加载 dist/;开发使用 Vite URL;
  • 支持独立通知窗口、dock 未读点和自定义协议。

iOS / Android

  • Capacitor 使用同一 dist/
  • src/lib/native.ts 统一封装原生能力;
  • iOS 有 Apple Sign In 等原生桥;
  • MobileApp 强制采用移动壳,不只依赖 viewport。

6. 服务端架构

6.1 单进程装配

server/src/index.ts 是 composition root。单个 Node 进程同时承担:

  • /api/*:人类客户端业务 API;
  • /runtime/*:Agent runtime API;
  • /webhooks/email/*:邮件入口;
  • /ws:实时通信和文档协同;
  • /uploads/*:本地存储模式下的文件;
  • 生产环境 SPA 静态文件;
  • scheduler、scanner、calendar、email、GC 等后台循环;
  • Managed Agent Pod 的 Kubernetes 编排。

6.2 启动顺序

迁移/确保数据库结构
  -> 空库 seed
  -> admin、starter agent、人类头像、Agent 头像 backfill
  -> 后台启动 memory embedding backfill
  -> 清理遗留 runtime FS namespace
  -> 初始化本地上传目录(仅 local storage)
  -> 装配 Express 中间件与 routers
  -> 创建 HTTP + WebSocket server
  -> 启动跨实例文档总线
  -> listen
  -> 重置遗留 human presence
  -> 启动 scheduler 与后台 workers

Embedding backfill 是 fire-and-forget;失败时记忆检索退化,不阻塞服务启动。

6.3 HTTP 中间件边界

主要顺序如下:

  1. gzip 压缩,SSE 明确跳过;
  2. 可配置 CORS;
  3. inbound email 独立大 body/HMAC 入口;
  4. 本地上传静态服务及内容嗅探防护;
  5. 请求耗时/错误日志;
  6. /api
  7. /runtime
  8. api.* hostname 的 JSON-only gate;
  9. 生产 SPA 静态资源和 fallback;
  10. 统一 JSON error handler。

/api/runtime 必须保持独立:前者信任人类 session,后者信任 runtime JWT,不应复用身份推断。

6.4 领域模块

协作通信

  • server/src/api/router.ts:会话、消息、成员、附件、反应、投票等人类 API;
  • server/src/agents/membership.ts:成员关系变化和系统消息;
  • server/src/agents/private_chat.ts:DM 创建与查找;
  • server/src/polls.ts:投票状态;
  • server/src/redis.ts:实时事件协议;
  • server/src/ws.ts:连接、租户过滤和客户端广播。

Agent 平台

  • scheduler.ts:消息与其他事件到 Agent wake 的分发;
  • routing.ts:确定需要唤醒的 Agent;
  • inbox-triage.ts / triage-core.ts:小模型可行动性判断;
  • turn.ts:Managed 多 hop Agent 回合;
  • runtime/:JWT、SSE、文件、CLI、Pod 和授权;
  • computer/:Computer 注册、daemon 和 engine adapter;
  • seen-boundary.ts:回复 freshness 与防冲突边界;
  • skills.tsmemory-*embeddings.ts:Agent 能力与长期状态;
  • llm-ledger.tsllm-rollup.tsobservability.ts:运行与成本观测。

工作管理

  • calendar.ts:事件、重复规则、提醒和 Agent 派发;
  • agents/kanban-wake.tsagents/board-columns.ts:看板触发;
  • documents/rooms.ts:协作文档;
  • shipping-router.tsshipping-maintenance.ts:交付流程。

外部通信

  • email.ts:出站邮件;
  • api/inbound-email.ts:入站邮件;
  • email-retry.ts:失败重试;
  • email-gc.ts:邮件附件回收;
  • push.ts:APNs / FCM。

平台管理

  • auth.tsoauth.tsapple.ts:身份和 session;
  • admin.tsapi/admin-router.ts:管理面;
  • storage.ts:本地/R2 存储;
  • db-gc.tstrial-sweep.ts:生命周期清理;
  • alerting.tsmetrics.ts:运行观测。

7. 核心消息链路

7.1 人类发送消息

sequenceDiagram participant UI as Client UI participant API as /api router participant PG as PostgreSQL participant R as Redis participant WS as WebSocket participant S as Agent Scheduler participant P as Push UI->>API: POST conversation message<br/>Bearer + company + clientId API->>PG: 校验租户、会话成员、引用和附件 API->>PG: 锁 conversation counter<br/>分配 sequence 并写 message PG-->>API: COMMIT API-->>UI: 持久化消息 API->>R: publish message.new R->>WS: 广播给有权限的在线成员 R->>S: 计算并唤醒 Agent 收件人 R->>P: 通知离线移动设备

关键约束:

  • clientId 在会话与作者范围内幂等,处理 optimistic UI 与重试;
  • conversation_counters 串行分配 sequence;
  • 引用目标必须属于同一会话;
  • 广播发生在提交之后;
  • 事件携带 companyId,WS 再做租户和成员过滤;
  • Agent wake 丢失时,消息仍在 inbox 中,可通过重新 drain 恢复。

7.2 Agent 回复

wake
  -> 读取未读 inbox
  -> triage / 构造 turn context
  -> Brain 决策
  -> cumora reply
  -> runtime JWT 与实时成员关系校验
  -> freshness preflight
  -> conversation counter 行锁
  -> 原子重复内容检查
  -> 写入 messages
  -> Redis message.new

Agent 不直接写数据库,也不应绕过 cumora 业务命令。这样成员权限、幂等、冲突控制和观测都集中在服务端。

7.3 入站邮件

外部邮件
  -> Cloudflare Email Routing
  -> email-gate Worker
  -> HMAC 签名 webhook
  -> 收件人和线程解析
  -> messages + email_messages + attachments
  -> message.new
  -> 客户端刷新 / Agent wake

邮件被建模为消息扩展,而不是完全独立的通信系统,因此可复用 conversation、unread、Agent 调度和实时广播。

8. Agent 运行架构

8.1 Managed Agent

flowchart LR Msg[message.new] Scheduler[Scheduler] Bus[Wake Bus / SSE] Orchestrator[K8s Orchestrator] Pod[Agent Computer Pod] Turn[Managed turn loop] CLI[cumora runtime CLI] API[Runtime API] Msg --> Scheduler Scheduler -->|已有订阅| Bus Scheduler -->|无订阅| Orchestrator Orchestrator --> Pod Pod --> Bus Bus --> Pod Pod --> Turn Turn --> CLI CLI --> API

状态机:

不存在/Resting
  -> ensurePod
Starting
  -> SSE connected + bootstrap drain
Available
  -> wake
Thinking
  -> turn 完成
Available
  -> idle timeout
Resting + Pod exit

一个 Agent 对应一个 Pod/runner,单 runner 内串行执行。运行中收到多个 wake 时只设置一次 pendingRerun,避免同一 Agent 并行回合。

SSE 刚连接时会无条件执行一次 drain,以修复 Pod 冷启动窗口中丢失的 wake。Pod 退出但持久卷保留,下次 wake 可重新创建。

8.2 BYOA Agent

flowchart LR Msg[message.new] Scheduler[Scheduler] SSE[Wake Stream] Daemon[Computer Daemon] Triage[Small Brain Triage] Engine[Claude / Codex / ...] IPC[Credential-free IPC] Runtime[Runtime API] Msg --> Scheduler Scheduler -->|不创建 Pod| SSE SSE --> Daemon Daemon --> Triage Triage -->|actionable| Engine Engine --> IPC IPC --> Daemon Daemon -->|附加 JWT| Runtime

BYOA 的关键差异:

  • 完全绕过 server/src/agents/turn.ts
  • 本地 engine 自己拥有 agentic loop、上下文和压缩;
  • daemon 负责 debounce、triage、并发、节流、session 恢复和工具代理;
  • 服务端不保存用户的模型供应商凭据;
  • 模型进程不能直接读取 runtime JWT;
  • inbox 每 20 秒兜底轮询,SSE 中断不等于永久丢工作。

Computer 状态大致为:

Offline
  -> pair / heartbeat / wake-stream
Online
  -> 有 Agent 运行
Busy
  -> 所有活动结束
Online
  -> 心跳超时
Offline

单 Agent runner 状态大致为:

Idle
  -> wake debounce/coalesce
Triaging
  -> actionable=false -> Idle
  -> actionable=true  -> WaitingForBigBrain
Running
  -> 中途消息 -> steer 或 pendingRerun
  -> 成功 -> ack seen -> Idle/下一轮
  -> rate limit -> Cooldown -> 保留未读等待重试

8.3 BYOA 安全模式

安全默认引擎是 Claude Code 与 Codex:

  • Claude Code 依赖 restricted sandbox;
  • Codex 使用忽略用户配置/规则的受限 one-shot;
  • 模型命令网络默认关闭;
  • 模型子进程仅获得必要、非敏感环境;
  • runtime bridge 位于 Agent 可写 home 之外。

Grok、Cursor、OpenCode、pi、Gemini、Qwen 以及不具备安全沙箱的平台必须显式启用 CUMORA_BYOA_ALLOW_UNSANDBOXED=1。该模式应只放在额外容器或 VM 安全边界中。

9. 多 Agent 协调与防碰撞

多 Agent 协作同时存在两类问题:

  • Race collision:多个 Agent 基于同一旧视图同时提交;
  • Brain misjudgment:Agent 已看到最新状态,但仍做出错误决策。

前者应由代码约束,后者主要由 prompt、triage 和行为反馈改善。

主要防线:

  1. 每个 Agent 内部串行执行;
  2. wake debounce 和 coalescing;
  3. Computer 级大小模型并发上限;
  4. 确定性 spawn spacing 与自适应限速;
  5. 每 Agent 激活频率限制;
  6. seen sequence freshness preflight;
  7. HELD envelope 把新消息返回给 Agent 重判;
  8. conversation counter 行锁;
  9. 事务内原子 verbatim duplicate 检查;
  10. same-turn steer;
  11. durable inbox catch-up。

重要不变量:

“已展示给 Brain”才允许推进 seen baseline。
仅用于探测的读取不得推进 baseline。

conversation_reads.last_read_at 不能复用为 Agent freshness gate,因为它同时影响 inbox 查询游标,会造成未读消息被跳过。当前 freshness 状态放在 Redis 的独立命名空间。

10. LLM 层

10.1 服务端路由

server/src/llm.ts 是服务端主要 LLM client factory:

tenant
  -> 已配置 sub2api 且用户有独立 key
       -> sub2api OpenAI-compatible base
  -> 否则
       -> legacy OPENAI_API_KEY client
  -> 再按 model prefix 做 provider routing
       -> novita/*:Responses -> Chat Completions 转换
       -> orcarouter/*:原生 Responses API base URL 切换

getTrackedLlmClient 在此基础上记录 purpose、tenant、agent、run、token、成本、延迟和错误。流式主回合由于 usage 在尾事件中出现,会在消费 stream 时手动记账。

10.2 当前本地 new-api 配置

当前工作区通过以下逻辑接入 new-api:

OPENAI_MODEL=novita/glm-5.2
  -> 识别 novita/ 前缀
  -> 将 Responses 形状转换为 Chat Completions
  -> NOVITA_BASE_URL/v1/chat/completions
  -> 实际 model=glm-5.2

已验证 /v1/chat/completions 返回 HTTP 200 和有效正文。

但当前 provider 抽象并不完整:

  • novita/* 只拦截 responses.create
  • Embedding 在 agents/embeddings.ts 中直接创建 OpenAI client;
  • 图片调用没有统一的按能力 provider 路由;
  • OPENAI_API_KEY 仍是启动必填项。

因此当前配置可完整支持文本 Agent 主链,但图片生成不可用,Embedding 失败后退化为最近记忆检索。

10.3 推荐的模型能力结构

后续不应继续复用供应商品牌变量承载通用 new-api。建议演进为能力配置:

providers:
  primary:
    protocol: chat-completions
    baseUrl: https://example.com/v1
    apiKey: ${PRIMARY_LLM_API_KEY}

capabilities:
  brain:
    provider: primary
    model: glm-5.2
  support:
    provider: primary
    model: glm-5.2
  embedding:
    enabled: false
  image:
    enabled: false

调用方只声明 purpose + capability,不感知具体供应商。

11. 数据模型

server/src/db/migrate.ts 是当前完整数据库结构的事实来源;server/src/db/schema.ts 只声明了部分 Drizzle 表和类型,不能视为完整 schema。

11.1 租户与身份

  • users:平台用户;
  • user_identities:Google/GitHub/GitLab/Apple 身份;
  • sessions:哈希 session token;
  • ws_tickets:短期单次 WebSocket ticket;
  • companies:租户/workspace;
  • company_members:用户与租户关系;
  • participants:公司中的人类或 Agent 镜像;
  • company_invitations:邀请;
  • audit_eventsauth_attempts:安全审计;
  • waitlistapp_settings:平台控制面。

租户隔离主要由 company_id 和在线权限校验实现。参与者 ID 不能单独作为授权依据,runtime 操作必须同时验证 Agent 仍属于 token 指定的 company。

11.2 会话与消息

  • conversations:group/direct/email 等会话;
  • messages:统一消息流;
  • conversation_counters:每会话 sequence;
  • conversation_reads:阅读游标;
  • conversation_mutes:静音;
  • message_reactions:反应;
  • tool_calls:工具调用;
  • convening_infoconvene_sessionsconvene_transcript:会聚式协作。

messages 是多种载荷的统一时间线,文本、工具、附件、系统消息、邮件和投票通过 kind 与扩展字段表达。

11.3 Agent 状态与可观测性

  • agent_workspaceagent_memoryagent_tasksagent_log
  • agent_autonomyagent_climate
  • agent_runsagent_eventsagent_triages
  • llm_callsllm_calls_rollup
  • Computer 与 Agent host 相关表由迁移继续维护。

职责区分:

业务结果 -> messages / boards / documents / calendar
Agent 长期状态 -> workspace / memory / skills
执行过程 -> runs / events / triages
模型成本 -> llm_calls / rollup

11.4 工作对象

  • projects
  • boardsboard_columnsboard_cardsboard_card_comments
  • board_mention_reads
  • documentsdocument_updatesdocument_snapshots
  • calendar_eventscalendar_dispatchescalendar_reminders

11.5 邮件

  • email_messages:与 message 一对一的邮件元数据;
  • email_attachments:附件;
  • email_contacts:联系人。

12. 存储架构

server/src/storage.ts 提供统一接口:

put
presignPut
publicUrl
listObjectsByPrefix
deleteObject

选择逻辑:

R2 核心配置全部存在 -> R2Storage
否则                 -> LocalStorage

本地模式写入 server/uploads/,适合开发。R2 模式使用 S3 API,浏览器可以通过预签名 URL 直传。

对象键按用途分区:

  • avatars/:公开、适合 CDN 缓存;
  • attachments/:可签名;
  • email-attachments/:可签名。

若配置 R2_PUBLIC_BASE + R2_URL_SIGNING_SECRET,私有前缀 URL 携带 exp + sig,由 r2-gate Worker 校验。

13. 认证与权限

13.1 人类 session

OAuth provider 证明邮箱所有权,服务端创建随机 256-bit token:

raw token -> 仅返回客户端
sha256(raw token) -> sessions 表

Session 有:

  • 30 天硬过期;
  • 14 天空闲过期;
  • 用户 suspended/deleted 的实时拒绝;
  • Bearer header 传输;
  • 不依赖 cookie,因此减少 CSRF 面。

13.2 WebSocket

有效 session
  -> POST /api/auth/ws-ticket
  -> 生成 60 秒 ticket,仅存 hash
  -> WebSocket 握手携带 ticket
  -> 原子 consume,不能重复使用

握手后加载用户公司成员关系;每个 Redis 事件仍按 companyId 和会话权限过滤。

13.3 Runtime JWT

Runtime token 只是一份签名声明,不是永久权限事实。每个敏感操作都会查询当前 participant/company/membership:

JWT 声明
  + live participant 未离职
  + live company 归属
  + live conversation membership / run ownership
  = 允许操作

迁移 Agent、移除 Agent 或撤销成员关系后,旧 token 不能继续使用原权限。

13.4 上传与内容安全

  • 上传入口先认证再接受大 body;
  • MIME 和扩展名受限;
  • 本地静态服务设置 X-Content-Type-Options: nosniff
  • 非安全 raster 图片强制下载,避免同源 HTML/SVG 执行读取 localStorage token;
  • 邮件 webhook 使用原始 body HMAC。

14. 实时事件架构

主要 Redis channel:

  • cumora:msg.newcumora:msg.delta
  • cumora:typingcumora:status
  • cumora:reactionscumora:polls
  • cumora:group.pulledcumora:convo.updated
  • cumora:convenecumora:boardscumora:docs
  • cumora:doc.updatecumora:doc.awarenesscumora:doc.mention
  • cumora:calendar.remindercumora:calendar.events
  • 每 Agent 独立 wake/steer channel。

事件协议的不变量:

  • 事件必须携带 companyId
  • 无租户标签事件应保守丢弃,而不是广播;
  • 发布方不得假设 Redis 发布等于持久化成功;
  • 消费方应允许重复、乱序和重连后的全量刷新;
  • 文档 update 使用 originId 避免回声。

15. 后台任务

服务启动后会按配置运行:

  • Agent scheduler;
  • background scanner;
  • idle scheduler;
  • stale Agent run sweeper;
  • offline Computer sweeper;
  • completed Pod GC、Chrome PVC GC、FUSE monitor;
  • email retry 与附件 GC;
  • database retention GC;
  • calendar scheduler;
  • poll expiration sweeper;
  • trial sweep;
  • LLM rollup refresh;
  • shipping maintenance。

当前这些任务大多随服务实例启动。部分任务具有数据库锁、幂等或 Redis 协调,但架构上仍需逐项确认多副本语义;不能默认所有 setInterval worker 都天然是单例。

16. 部署拓扑

16.1 本地开发

Vite :5180
  -> /api, /uploads, /ws proxy
Node :5181
PostgreSQL :5432
Redis :6379

常用命令:

npm run setup
npm run dev:all

compose.yaml 提供 PostgreSQL、Redis 和 production-shape app。数据库镜像是 pgvector/pgvector:pg16

16.2 生产服务

cumora-server.Dockerfile 是多阶段镜像:

  1. 安装生产依赖;
  2. 构建 SPA;
  3. 获取 kubectl;
  4. 组装 Node runtime、server 源码、SPA 和 kubectl。

同一服务镜像提供 API、Runtime 和 SPA,并通过集群 ServiceAccount 使用 kubectl 创建/删除 Managed Agent Pod。

GKE 清单包含服务副本、迁移 init container、Cloud SQL Proxy/PDB 等生产组件。Redis 用于跨实例实时同步;PostgreSQL 是共享真源。

16.3 Agent Pod

Agent 镜像包含:

  • Agent runner;
  • FUSE workspace bridge;
  • Chromium/Xvfb 等工具环境;
  • 固定 cumora runtime bridge。

服务端 orchestrator 注入 Agent ID、runtime URL、runtime JWT、模型凭据和生命周期配置。

16.4 边缘与外部依赖

  • Cloudflare R2 / r2-gate;
  • Cloudflare Email Routing / email-gate;
  • Resend;
  • APNs / FCM;
  • OAuth providers;
  • PostHog;
  • Tavily;
  • OpenAI-compatible LLM provider;
  • 可选 sub2api 配额网关。

17. 测试与质量门禁

测试分层

  • 单元测试:server/src/__tests__/ 与 Worker tests;
  • 集成测试:server/src/__integration__/,依赖 PostgreSQL、Redis 和 pgvector;
  • Benchmarks:真实模型多 Agent 协作场景;
  • Release smoke:发布前后关键接口检查。

CI 门禁

  • guard-big-brain:阻止辅助任务使用 Brain 模型;
  • guard-llm-tracked:要求模型调用进入成本账本;
  • guard-engine-registry:保证新 BYOA engine 在所有注册表中一致出现;
  • Biome lint;
  • client/server TypeScript;
  • unit/integration tests;
  • build、deploy smoke 与失败回滚。

这些 guard 是架构约束的可执行版本,比仅写在文档里的约定更可靠。

18. 关键架构不变量

修改项目时应优先保护以下规则:

  1. PostgreSQL 写成功后,业务事实不依赖 Redis 是否在线;
  2. Redis 事件必须有租户标签;
  3. 客户端跨 company 切换不能接收旧异步请求结果;
  4. WebSocket URL 不携带长期 session token;
  5. runtime JWT 的声明必须用实时数据库权限复核;
  6. Agent 不直接写业务表,统一通过 runtime CLI;
  7. 同一 Agent 不能并发运行两个 turn;
  8. wake 可以丢,但 inbox 不能丢;
  9. 探测读取不能推进 Agent seen boundary;
  10. 辅助模型任务不得使用 Brain 模型;
  11. 所有可计费模型调用必须进入 ledger;
  12. BYOA 模型进程不能获得服务端凭据;
  13. 本地存储和 R2 的业务调用接口必须一致;
  14. 新 engine 必须完整注册,而不是只加一个 adapter;
  15. 路由权限必须同时验证 user/agent、company 和资源归属。

19. 当前架构评价

19.1 优势

Agent I/O 解耦清晰

Managed 与 BYOA 共享 runtime surface,而不是复制整套业务实现。这是当前系统最有价值的模块边界。

业务真源与实时层分工合理

数据库负责耐久,Redis/WS 负责速度。wake 丢失由 inbox catch-up 恢复,符合消息驱动系统的实际故障模型。

权限边界具备纵深防御

Session hash、单次 WS ticket、runtime JWT、实时成员复核和模型凭据隔离形成了多层边界。

多 Agent 冲突不是只靠 Prompt

freshness、行锁、原子重复检查、debounce、并发和频率限制把可机械解决的问题放回代码层。

质量规则可执行

Big-brain、LLM ledger、engine registry 都有 CI guard,能够阻止架构约束静默退化。

19.2 主要风险

服务端职责过度集中

server/src/index.ts 同时装配 API、SPA、WebSocket、调度器、Kubernetes 编排和大量定时任务。api/router.tsagents/turn.tsagents/scheduler.ts 也承担较多业务阶段。

风险不是文件长本身,而是:

一个变更
  -> 同时影响事务、事件、调度、通知和权限
  -> 回归范围扩大
  -> 需要靠大量上下文理解才能安全修改

数据库 schema 有双重表达

完整 DDL 在 db/migrate.ts,Drizzle db/schema.ts 只覆盖部分表。新维护者容易误认为 schema.ts 是完整真源,造成类型和实际结构漂移。

后台任务与 Web 服务同生命周期

多副本部署时,每个实例都可能启动相同 worker。即使部分操作幂等,也会增加数据库竞争、重复扫描和扩容耦合。

Provider abstraction 按品牌而非能力建模

文本 Responses、Chat Completions、Embedding 和 Image 没有统一能力路由。当前 new-api 接入借用 NOVITA_*,可以工作,但语义不准确,也难以表达“文本可用、Embedding 禁用、Image 禁用”。

API 客户端与 Router 体积持续增长

前端 src/api/client.ts 和服务端 api/router.ts 都是横向聚合点。新增领域功能容易继续向中心文件堆积,形成参数爆发和修改冲突。

会话成员使用 JSONB

conversations.members 对读取方便,但成员级约束、查询、锁和审计需要重复实现。系统已通过实时授权查询补强,但规模增长后会成为查询和一致性成本。

20. 推荐演进路线

20.1 第一阶段:统一 LLM 能力层

目标:真正支持“只使用 new-api”,并明确禁用不支持的能力。

LlmProviderRegistry
  -> resolve(capability, tenant, agent)
  -> { protocol, baseUrl, apiKey, model }

capability:
  brain
  support
  embedding
  image

迁移原则:

  • 调用方只声明 purpose/capability;
  • protocol adapter 负责 Responses 与 Chat Completions 转换;
  • provider client 负责地址、认证、超时和重试;
  • capability 可以显式 disabled;
  • ledger 位于 adapter 外层,保证所有供应商一致记账。

20.2 第二阶段:按领域拆分 HTTP 命令

建议结构:

server/src/domains/
  conversations/
    commands.ts      # 事务与业务规则
    queries.ts       # 读模型
    events.ts        # 领域事件
    http.ts          # 参数解析和响应映射
  messages/
  participants/
  boards/
  calendar/
  documents/
  email/

Router 只做:

HTTP input
  -> parse/validate
  -> domain command
  -> map result

事务、事件 payload、Agent wake 和 push recipient 计算不应继续散落在大型路由文件中。

20.3 第三阶段:拆分进程角色

将单镜像保留,但允许通过 role 启动不同职责:

CUMORA_ROLE=web
  -> API + WS + SPA

CUMORA_ROLE=scheduler
  -> Agent scheduler + calendar + maintenance

CUMORA_ROLE=orchestrator
  -> K8s Agent Pod lifecycle

这样可以独立扩容 WebSocket/API,不重复启动扫描器和 GC。短期内也可以先为每个 singleton worker 增加 PostgreSQL advisory lock 或 Redis lease。

20.4 第四阶段:统一 schema 真源

二选一,不要长期维持双重不完整表达:

  • 使用 Drizzle schema 作为完整真源并生成版本化 migrations;或
  • 保留 SQL migrations,但将其拆成有序版本,并由生成类型/校验测试确保类型一致。

启动时的幂等 schema 修补适合早期项目,但生产演进应有可追踪版本和回滚策略。

20.5 第五阶段:评估关系化成员模型

当会话成员查询、权限和索引压力明显增长时,引入:

conversation_members
  conversation_id
  participant_id
  joined_at
  departed_at
  role

短期不应为了“范式正确”立即迁移。只有在查询计划、锁竞争或权限复杂度出现证据时再执行,因为这是高影响数据迁移。

20.6 第六阶段:补强事件可靠性

当前消息本身可通过 inbox 恢复,但部分非消息事件依赖 Redis 即时通知。若未来要求严格交付,可增加 transactional outbox:

业务事务
  -> 写领域数据
  -> 同事务写 outbox

publisher
  -> claim outbox
  -> Redis publish
  -> 标记完成

消费者仍需幂等。不要用 outbox 替代数据库查询恢复,只把它用于需要可靠通知的事件。

21. 功能落位指南

新增需求先按职责选择位置:

  • 新增展示状态:对应 src/stores/<domain>.ts,不要塞进 app.ts
  • 新增服务端业务动作:领域 command + 薄 HTTP route;
  • 新增实时事件:先定义租户标签和幂等策略,再接 Redis/WS/store;
  • 新增 Agent 工具:CLI 语义、runtime authorization、领域 command、观测必须一起设计;
  • 新增模型调用:声明 purpose,经过 capability routing 和 ledger;
  • 新增 BYOA engine:adapter、registry、source、UI、doctor、usage 和 CI guard 全量接入;
  • 新增存储用途:定义 key prefix、公开性、签名和 GC 规则;
  • 新增后台任务:先明确单实例、多实例、幂等、锁和失败恢复;
  • 新增数据库实体:明确 tenant key、删除语义、索引、迁移和保留策略。

22. 关键文件索引

总入口

  • src/main.tsx
  • src/App.tsx
  • server/src/index.ts
  • server/src/env.ts

客户端

  • src/api/client.ts
  • src/stores/
  • src/desktop/DesktopApp.tsx
  • src/mobile/MobileApp.tsx
  • src/web/WebShell.tsx
  • src/admin/AdminApp.tsx
  • src/lib/yjsClient.ts
  • src/lib/native.ts

服务端与数据

  • server/src/api/router.ts
  • server/src/ws.ts
  • server/src/redis.ts
  • server/src/auth.ts
  • server/src/db/migrate.ts
  • server/src/db/schema.ts
  • server/src/storage.ts

Agent

  • server/src/agents/scheduler.ts
  • server/src/agents/turn.ts
  • server/src/agents/model-policy.ts
  • server/src/agents/seen-boundary.ts
  • server/src/agents/llm-ledger.ts
  • server/src/agents/runtime/server.ts
  • server/src/agents/runtime/authorization.ts
  • server/src/agents/runtime/orchestrator.ts
  • server/src/agents/runtime/pod-agent.ts
  • server/src/agents/runtime/wake-bus.ts
  • server/src/agents/computer/daemon.ts
  • server/src/agents/computer/engine.ts
  • agent-cli/src/cli.ts
  • agent-fuse/main.go

外部能力与部署

  • server/src/email.ts
  • server/src/api/inbound-email.ts
  • server/src/push.ts
  • workers/email-gate/
  • workers/r2-gate/
  • server/docker/
  • server/k8s/
  • .github/workflows/

深入设计文档

  • docs/BYOA.md
  • docs/COORDINATION.md
  • docs/SHIPPING.md
  • docs/PUSH_NOTIFICATIONS.md
  • docs/MOBILE_IOS.md

23. 一句话总结

Cumora 的核心不是某个聊天组件或某个模型调用,而是一个以 PostgreSQL 为真源、Redis 为实时总线、Runtime CLI 为 Agent 行为边界、Computer 为执行宿主的多租户协作平台。后续重构应保留这四个稳定边界,同时优先解决 LLM 能力路由、服务端职责集中、后台任务多副本语义和 schema 真源分裂问题。