Skip to content

Xiaoyuan-Liu/happycodex

Repository files navigation

happycodex

Codex 版 HappyClaw 运行时——把 HappyClaw 的 Agent 执行层从 Claude Agent SDK 迁移到 codex app-server(JSON-RPC over stdio)的运行时实现。

引擎底座(Stage 0-4):协议契约 + app-server 客户端 + 流式事件映射 + thread/turn 注入循环 + 17 个工具(dynamicTools)+ 多租户编排(per-folder 隔离 / resume / 单写者)+ 针对真实 codex 的 PoC 验证。基线 codex-cli 0.137.0

完整应用(A 阶段已搬迁):在引擎底座之上,HappyClaw 的应用层(Web 前后端、五渠道 IM、 调度、计费、权限)已忠实搬迁为 codex-only 版,并叠加了 codex 特有的 per-user 登录与自定义 模型 provider。MVP 端到端(Web 登录→发消息→codex 执行→流式回复→重启 resume,host + Docker 双轨)已验证。

上游同步台账见 docs/UPSTREAM-SYNC.md;per-user 登录/provider 细节见 docs/CODEX-PERUSER-AUTH.md。本 README 主体描述引擎底座(Stage 0-4) 的协议/架构;下方「运行完整应用」给出起 Web 服务的命令。


项目定位

HappyClaw 用 agent-runner 在容器/宿主机进程里调用 Claude Agent SDK,把流式事件 经 OUTPUT_MARKER 包裹写 stdout,主进程解析后广播到 Web/IM。happycodex 把这条执行 管道的「引擎」换成 codex app-server:

  • 协议层:codex app-server 是一个长驻子进程,走 newline-delimited JSON-RPC(省略 "jsonrpc":"2.0" 头)。thread = 会话,turn = 一轮对话,token 增量通过 item/agentMessage/delta 等通知流式推送。
  • 复用点:codex 的流式通知映射到 HappyClaw 既有的 StreamEvent 形状(shared/stream-event.ts), 再经同一套 OUTPUT_MARKER → WebSocket stream_event 管道吐给前端,前端 chat store 无需改动

与 HappyClaw 的对应关系

HappyClaw happycodex 说明
container/agent-runner/ src/runtime/codex-runner.ts 执行引擎:消费输入 + IPC 注入,驱动会话,吐 StreamEvent
Claude Agent SDK query() src/runtime/session.ts(thread/turn) 单会话生命周期 + 注入循环
SDK 内部 spawn cli.js src/appserver/client.ts spawn codex app-server,JSON-RPC 分帧/关联/背压重试
shared/stream-event.ts src/shared/stream-event.ts StreamEvent 类型(语义对齐,冻结
OUTPUT_START/END_MARKER 流式管道 同名 marker(shared/stream-event.ts runner → stdout → 主进程解析,协议复用
SDK 流式事件 → StreamEvent src/runtime/stream-mapper.ts 把 app-server 通知映射成 0..N 个 StreamEvent(纯函数)

架构与模块

┌─────────────────────────────────────────────────────────────┐
│  codex app-server (子进程, JSON-RPC over stdio)              │
└───────────────▲───────────────────────────┬─────────────────┘
   请求/通知/审批 │                            │ 增量通知(delta / item / turn)
┌───────────────┴───────────────────────────▼─────────────────┐
│  src/appserver/client.ts   AppServerClient                   │
│   spawn + 行分帧 + id 关联 + -32001 背压重试 + 通知/请求分发     │
└───────────────▲───────────────────────────┬─────────────────┘
                │ request/notify             │ onNotification
┌───────────────┴───────────────────────────▼─────────────────┐
│  src/runtime/session.ts    ThreadSession                     │
│   thread/start|resume · turn/start|steer · activeTurnId 维护  │
│      │  通知 → StreamMapper → onStreamEvent                   │
│      ▼                                                        │
│  src/runtime/stream-mapper.ts  StreamMapper(纯映射)         │
│      app-server 通知 → StreamEvent[]                          │
└───────────────▲───────────────────────────┬─────────────────┘
                │ onStreamEvent              │
┌───────────────┴───────────────────────────▼─────────────────┐
│  src/runtime/codex-runner.ts  CodexRunner                    │
│   消费 CodexRunnerInput + IPC 注入,StreamEvent 经            │
│   OUTPUT_MARKER 包裹写 sink(默认 stdout)                     │
└──────────────────────────────────────────────────────────────┘
模块 职责
src/contracts.ts 冻结:跨模块公共契约(接口 + 构造签名),各实现针对它编程
src/appserver/protocol.ts 冻结:codex app-server JSON-RPC 协议子集(手工策展,对齐 generate-ts 产物)
src/appserver/client.ts AppServerClient:spawn 进程、JSON-RPC 分帧/关联、背压重试、握手、通知/请求分发
src/runtime/stream-mapper.ts StreamMapper:单条 app-server 通知 → 0..N 个 StreamEvent(无副作用,可单测)
src/runtime/session.ts ThreadSession:thread/turn 生命周期;sendUserMessage 自动判定 turn/start vs turn/steer
src/runtime/codex-runner.ts CodexRunner:agent-runner 等价物,OUTPUT_MARKER 包裹写 stdout;可挂工具层
src/runtime/tools/types.ts 冻结:工具层契约(ToolBridge / ToolDefinition / IToolRegistry / IToolDispatcher)
src/runtime/tools/registry.ts ToolRegistry:聚合工具、产出 dynamicTools schema、按名分发(never throws)
src/runtime/tools/builtin.ts createBuiltinTools():HappyClaw 12 个工具的 dynamicTools 定义(schema + handler)
src/runtime/tools/ipc-bridge.ts IpcToolBridge:工具副作用落成 HappyClaw 风格 IPC 文件 + 记忆文件操作
src/runtime/tools/dispatcher.ts ToolDispatcheritem/tool/call server 请求 → registry.dispatch → respond
src/runtime/multitenant/types.ts 冻结:多租户层契约(ISessionManager / ISessionStore / ICodexHomeProvisioner / ISerialQueue)
src/runtime/multitenant/session-manager.ts SessionManager:编排 N 个 folder(per-folder app-server、resume、idle 回收、LRU 驱逐、可选工具)
src/runtime/multitenant/session-store.ts SessionStore:folder→threadId JSON 持久化(映射 HappyClaw sessions 表,原子写)
src/runtime/multitenant/codex-home.ts FsCodexHomeProvisioner:per-folder CODEX_HOME + 复制共享 auth(幂等、路径安全)
src/runtime/multitenant/serial-queue.ts SerialQueue:per-key 单写者闸门(防 rollout 无锁并发损坏,对应 group-queue)
src/shared/stream-event.ts 冻结:StreamEvent 类型 + OUTPUT_MARKER 常量(对外流式协议单一真相源)
src/poc/poc-stream.ts PoC R1:token 流式增量
src/poc/poc-steer.ts PoC R2:运行中注入(turn/steer)
src/poc/poc-resume.ts PoC:跨进程 thread/resume 续接
src/poc/poc-tools.ts PoC R3:12 个工具走 dynamicTools,端到端往返 + 副作用落地
src/poc/poc-multitenant.ts PoC Stage 4:2 个 folder 并发,隔离 + 并发 + 跨进程 resume
protocol/ts/protocol/schema/ codex 0.137.0 generate-ts / generate-json-schema 全量参考产物(不入编译)

如何跑

前置条件

  1. 安装 codex CLI,版本对齐基线 0.137.0(可用 codex --version 确认)。
  2. codex 认证
    • 共享/默认账号(首次部署的基线):服务端 codex login(或 codex login --api-key)一次, 凭据落 ~/.codex/auth.json。它满足首次 setup 门控、并作为未自登用户的回退账号。
    • per-user 自登(启动后,各用户在 Web 界面):进「设置 → Codex 账号」用自己的 codex 账号 登录——支持「浏览器登录」(本机推荐,自动开浏览器)/「设备码登录」(远程)/「API key」/ 「access-token」。无需预先在终端 codex login。登录态按用户隔离(data/config/user-im/{userId}/codex/)。
    • 也可在「Codex 配置」里配第三方模型 provider(兼容 OpenAI Responses API 的 GLM 等)。
    • 注意:首次 setup 门控目前仍看共享账号,故全新机器至少需要一次服务端 codex login 来过 setup;之后各用户即可在 UI 里登录自己的账号。
  3. CODEX_HOME:指向有效的 codex 配置目录。PoC 默认用当前环境的 CODEX_HOMEpoc-resume 的两次 client 必须共享同一 CODEX_HOME,否则第二个进程读不到第一个 写入的 rollout,无法续接。(完整应用为每个 folder provision 独立的 per-folder CODEX_HOME。)
  4. 安装依赖:npm install

命令

# 类型检查(tsc --noEmit)
npm run typecheck        # 或:make typecheck

# 单测(vitest,纯逻辑模块:stream-mapper / client 分帧等)
npm run test             # 或:make test

# PoC(针对真实 codex app-server,需登录态 + CODEX_HOME)
npm run poc:stream       # 或:make poc-stream  —— R1 token 流式
npm run poc:steer        # 或:make poc-steer   —— R2 运行中注入 turn/steer
npm run poc:resume       # 或:make poc-resume  —— 跨进程 thread/resume 续接
npm run poc:tools        # 或:make poc-tools        —— R3 dynamicTools 工具端到端
npm run poc:multitenant  # 或:make poc-multitenant  —— Stage 4 多租户隔离/并发/resume

PoC 会话统一用 { approvalPolicy: 'never', sandbox: 'read-only' }:不触发审批回环阻塞、 不写磁盘。每个脚本结尾打印 OK / UNCERTAIN / FAIL 结论并按结果 process.exit

运行完整应用(Web + IM)

# 1) 构建前端(首次 / 改前端后):产物 web/dist 由后端静态托管
cd web && npm run build && cd ..

# 2) 起后端(host 模式 tsx 直跑;WEB_PORT 自定端口,避免与同机其它服务冲突)
WEB_PORT=3100 npm run dev          # 生产可 npm run build → node dist/index.js

浏览器打开 http://localhost:<WEB_PORT> → 首次按向导建管理员(setup)→ 进「设置 → Codex 账号」 登录你自己的 codex(浏览器/设备码/API key),即可发消息让 codex 执行。

同机若另跑了 happyclaw,给 happycodex 用不同端口即可(session cookie 已用专属名 happycodex_session,与 happyclaw 互不顶替)。


Stage 0-4 范围 & 已知未做

本仓库已覆盖(Stage 0-4)

  • 协议契约冻结(contracts.ts / protocol.ts / stream-event.ts / tools/types.ts / multitenant/types.ts)。
  • AppServerClient:JSON-RPC over stdio、-32001 背压指数退避重试、握手、通知/请求分发。
  • StreamMapper:app-server 通知 → StreamEvent 纯映射。
  • ThreadSession:thread/turn 生命周期 + 运行中注入(turn/start vs turn/steer 自动判定)。
  • CodexRunner:OUTPUT_MARKER 流式管道(对齐 HappyClaw agent-runner)+ 可挂工具层。
  • Stage 3 工具层:12 个 HappyClaw 工具走 dynamicTools(注册 + item/tool/call 客户端代理执行)。
  • Stage 4 多租户(standalone):SessionManager 编排 N 个 folder——per-folder CODEX_HOME 隔离(共享单账号,auth 复制进各 home,对齐 HappyClaw 全局凭据 + 配置目录隔离模型)、 SessionStore 持久化 folder→threadId(resume 续接)、SerialQueue 单写者闸门、idle 回收 + LRU 驱逐。
  • 五个 PoC 针对真实 codex app-server 验证 R1/R2/resume/tools/multitenant。

已知未做(明确不在本仓库 standalone 范围)

  • 接 HappyClaw 主仓:改 HappyClaw container-runnercodex-runnerIpcToolBridge 对接真实 主进程 IPC/task-scheduler/memory(含 listTasks 真状态)、映射真实 sessions 表——是最终目标, 跨两个仓库,留待后续。
  • 共享单账号 token 刷新集中化:standalone 下各 per-folder CODEX_HOME 独立 refresh 可能竞争; 生产应集中一个 refresh owner(随"接主仓"一起做)。
  • provider failover(P0):HappyClaw 的多账号失效转移在 codex 架构下作废,不重做。
  • provider failover 作废(P0):HappyClaw 的 provider 限额切换/上下文恢复机制在 codex 架构下作废——codex app-server 自管 provider,不在 happycodex 运行时重做。
  • 容器化 / Docker 卷挂载、IM 通道、Web 前端:均属 HappyClaw 主仓既有能力,本仓库只替换执行引擎。

开发约束

  • ESM + NodeNext:所有相对 import 必须带 .js 扩展名(即使源文件是 .ts)。
  • 严格 TSstrict + noUncheckedIndexedAccess + noImplicitOverride,避免 any 滥用。
  • 冻结契约src/contracts.tssrc/appserver/protocol.tssrc/shared/stream-event.ts 是冻结文件,修改 = 改公共 API,需同步所有实现方。
  • 升级 codex 后:npm run protocol:regen 重新生成 protocol/,再对照 protocol.ts diff。

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors