Skip to content

Latest commit

 

History

History
99 lines (89 loc) · 10.5 KB

File metadata and controls

99 lines (89 loc) · 10.5 KB

feishu-codex-bridge 实现规划

配套 feishu-codex-bridge-design.md。从零搭 src/。references 仅学习不抄。 注:yepanywhere 在 /tmp/yepany(临时克隆、无 LICENSE,仅研究 app-server 客户端思路)。

协议层关键事实

  • 更正(generate-ts 实证):app-server v2 有 token 级 delta 通知 —— AgentMessageDeltaNotificationReasoningTextDeltaNotificationCommandExecOutputDeltaNotification,外加 ItemStartedNotification/ItemCompletedNotification + turn/completed/ErrorNotification。→ 可做真·逐字流式,run-state 保留 delta 累加(item/completed 做收尾对账)。
  • 协议绑定已生成入库:src/agent/codex-appserver/protocol/generated/(79 文件 + v2/),barrel protocol/index.ts

状态

  • M0 ✅ 完成并验证:脚手架(package/tsconfig/tsup/bin) + paths + logger + 协议绑定 + cli(doctor 实/start·service 桩)。npm install/typecheck/build/doctor 全绿。
  • M1 agent 后端 ✅ 已建 + 实跑验证agent/types.ts(AgentBackend/Thread/Run/Event) + codex-appserver/{app-server-client,event-map,backend,locate}.ts + agent/index.ts。typecheck 全绿;prototype/appserver-probe/turn-probe.mjs 实跑确认完整 turn 生命周期 + token 级流式。
  • M1 onboarding ✅:keystore + secret-resolver + store/schema + feishu-auth + wizard(扫码 registerApp) + secrets CLI + start 编排。typecheck/build 绿。
  • M1 bot/bridge ✅ 代码完成bot/bridge.ts(createLarkChannel 长连接) + bot/handle-message.ts(群@bot→reply_in_thread 建话题→app-server turn→channel.stream markdown 流式卡片,话题内续用 session) + card/run-render.ts。typecheck/build 绿。
  • M1 ✅ 端到端验证通过(2026-05-26):用户扫码复用 cli_xxxxxxxxxxxxxxxx → 群里 @bot → reply_in_thread 建话题 → app-server 在 cwd 跑一轮 → codex 调工具 + 输出 + 流式 markdown 卡片。终端日志干净。p2p 暂跳过(DM 控制台属 M2)。
  • M3 ✅ 代码完成(2026-05-26, ece8f36):群主区 @bot → 会话配置卡(模型▾/effort▾ + 创建/恢复),点创建→reply_in_thread 建话题开跑;话题内 @bot 直接续跑。card/dispatcher.ts(card.action.trigger 路由) + card/cards.ts + card/session-config-card.ts + bot/handle-message.ts(重构 createOrchestrator) + bot/session-store.ts。去掉 fast(codex 无此参数,见 decisions.md)。
  • M4 ✅ 代码完成(ece8f36):配置卡模型下拉用 backend.listModels();恢复历史→backend.listThreads(cwd)(codex thread/list) 列最近会话→thread/resume,仅新建时可选。
  • 运行卡 ⏹/⚙️ ✅ 代码完成(08ce549):运行输出改流式卡片,运行中挂 ⏹中止、终态挂 ⚙️设置(改本会话 model/effort,下一轮生效,仅挂最新卡)。card/run-card.ts + runStreamed(input,turn?) per-turn override。
  • M5 ✅ 代码完成(a9cb1ce):project/banner.ts 置顶横幅卡片化 + 分支惰性检测(变了才 patch);registry 增 bannerMessageId/branch + updateProject。
  • M7 ✅ 代码完成(45e2ec8):card/dm-cards.ts 私聊菜单/项目列表/删除确认/全局设置卡;dm.* handlers 接 dispatcher(admin gate)。文本命令保留兜底。新建项目暂用 /new 文本(卡片 form input 后续)。
  • M8 ✅ 代码完成 + 真机验证(4337d50, service-dev):launchd 后台服务(adapter/launchd + cli service install/uninstall/status/restart/logs),真机 install→pid→restart→uninstall 清理无残留。
  • 单测 ✅(e548b8e, test-dev):test/{event-map,run-render,schema,watchdog} 24 用例 + vitest.config 限定 test/**,npm test 24/24 绿。
  • reviewer [OK](2fd9248, 2026-05-26):3 轮收敛,全部 HIGH(卡片授权/回调长占/假成功/⏹杀别人 run)+ MEDIUM(泄漏/陈旧/设置语义/pin撤销)关闭;报告见 .plans/reviewer/review-rereview-2fd9248/。
  • ⬜ 待用户端到端真机测试(M3/M4/M5/M7 + 运行卡 + M8):typecheck/build/test 全绿、reviewer [OK],唯一残留=真机 Feishu callback smoke。

已知待办(后续统一处理)

  • 卡片渲染细节统一:运行卡虽已切 card 模式,工具仍在文本上方堆叠、原样 /bin/zsh -lc "..."。后续:有序交错 block + 友好工具头(去 shell 壳) + 可折叠工具面板。(用户明确「先不改,后面统一改」)
  • 新建项目卡片 form:当前 /new 文本兜底;后续用飞书卡片 input + 提交收 form_value。
  • app-server 子进程回收:当前每个活跃话题常驻一个进程;watchdog 管卡死,但完整生命周期回收(话题闲置/超时关进程 + 启动清孤儿)未做。
  • JSON-RPC over stdio:行缓冲 split \n,按 id/method 分流 response/notification/server-request,pendingRequests Map + notification 异步队列。
  • reply_in_thread 响应不透出 thread_id → 从 GET /im/v1/messages/:id 或 receive 事件取。

1. 目标 src/ 结构([复用]references思路 / [改造]骨架可用核心重写 / [全新])

src/
  cli/{index,commands/{start[改],doctor[改],service[复用],secrets[复用],ps[复用]},
       onboarding/{codex-cli[复用],lark-cli[复用],wizard[改],menu-setup-guide[全新]}}
  agent/                                  ★核心全新区
    types.ts[改] index.ts[复用]
    codex-appserver/{backend,app-server-client,process,event-map,model-list}[全新]
      protocol/{index,generated/*}[全新]  ← codex app-server generate-ts 产物入库
  bot/{bridge[改],router[全新],access[复用],keepalive[复用],network[复用],
       run-orchestrator[全新],active-turns[改],pending-policy[全新],
       chat-mode-cache[复用],reaction[复用],quote[复用],media-intake[复用]}
  card/{templates[复用],managed[复用],run-renderer[改],run-state[改],tool-render[复用],
        session-config-card[全新],thread-settings-card[全新],project-cards[全新],
        banner-card[全新],wizard-cards[全新],dispatcher[改]}
  project/{registry,lifecycle,git-info}[全新]   ← 项目=群=cwd 注册表
  session/{store[改],history[改]}               ← 话题=会话 持久化
  config/{schema[改],store[复用],paths[复用],keystore[复用],secret-resolver[复用],defaults[全新]}
  service/{adapter,launchd}[复用]
  media/cache[复用]  runtime/registry[复用]  core/logger[复用]

2. AgentBackend

interface AgentBackend { id; displayName; isAvailable(); listModels(opts?);
  startThread({cwd,model,effort,fast}): AgentThread;
  resumeThread({codexThreadId,cwd,model,effort,fast}): AgentThread; }
interface AgentThread { codexThreadId; runStreamed(input): AgentRun;
  steer(input,expectedTurnId); abort(turnId); close(); }
interface AgentRun { events: AsyncIterable<AgentEvent>; turnId(); waitForExit(ms); }
  • AgentEvent 沿用 reference 形状(system/text/thinking/tool_use/tool_result/usage/done/error)+ 可选 turnId。
  • 一话题一进程:backend 持 Map<feishuThreadId, AppServerClient>;startThread/resumeThread spawn+握手,close 回收。
  • 握手:initialize→等result→notify(initialized)→thread/start{model,cwd,approvalPolicy:'never',sandbox:'danger-full-access'}(resume 走 thread/resume{threadId})。
  • 回收:SIGTERM→grace→SIGKILL;detached 进程组 kill 防孤儿;启动清孤儿;崩溃 reject pending+标卡 error。
  • watchdog/steer/interrupt 挂在 bot/run-orchestrator;server-request 兜底回 -32601 防卡死。
  • 协议绑定:generate-ts 子集入库 + tools/update-codex-protocol.mjs + doctor 校验版本。

3. 里程碑(各自可独立验证)

  • M0 脚手架:package/tsup/vitest/commander/node-sdk、paths/config/logger/keystore 搬入、cli 空壳+doctor、protocol 子集入库。验证 build+doctor。
  • M1 最小垂直闭环 ★:长连接收 message → 群@bot → reply_in_thread 建话题 + 取 thread_id → startThread(写死cwd/默认model) → turn/start → 运行卡流式 patch。需用户先备 §4。
  • M2 项目管理:菜单 bot.menu_v6 → 新建项目(空白git init/指定文件夹)→建群+拉人+置顶→registry;列表/删除(解绑+提示自解散)。cwd 改按群查 registry。
  • M3 会话配置卡+三层默认:群@bot 弹 session-config-card(model/effort/fast 预填)→创建→reply_in_thread;话题运行卡加 ⚙️设置(改下一轮,挂最新卡旧卡patch掉)。
  • M4 动态模型+恢复会话:model/list 喂下拉(effort 随模型联动);恢复历史→session/history→thread/resume(仅新建时)。
  • M5 置顶横幅+分支惰性检测:banner-card+im pins create;消息进/run结束读 git 分支变了 patch。
  • M6 稳定性:watchdog(120s可配)、steer/queue 策略、心跳+自动重连(🔄菜单)、并发FIFO、孤儿回收。
  • M7 访问控制+全局设置卡:admins/allowedUsers/allowedChats;破坏性限 admins。
  • M8 onboarding+service+诊断:wizard扫码建应用、codex/lark-cli onboarding、菜单配置指引、launchd、🩺诊断卡。

4. M1 需用户准备

  1. appSecret(WSClient 必需,存 keystore)
  2. 开放平台事件订阅(长连接):im.message.receive_v1 + card.action.trigger + application.bot.menu_v6,发布版本
  3. scope:im:message / im:message:send_as_bot / im:resource / im:chat / im:chat.announcement(项目横幅改用群公告,docx block 读写) / cardkit:card:write(交互按钮卡片用 CardKit 实体,缺则 cardkit.card.create 报 200610);可选 drive:drive。不需 im:chat:delete
  4. 机器人自定义菜单 5 项 event_key(M2 用,可同时配)
  5. codex 已 login(M1 真实跑 turn 耗 token);记 codex 版本对齐 generate-ts
  6. 一个测试群(bot 在内)+测试 cwd(M1 写死用)

5. 风险与对策

  • card.action/bot.menu 未实跑 → M1 末单独冒烟点一下按钮看回调;失败回退文本指令兜底。
  • 无 token delta → item 级整段渲染,run-state 改 itemId upsert。
  • reply_in_thread 不透出 thread_id → 从消息 get/receive 事件取。
  • 每话题一进程膨胀 → maxConcurrentRuns FIFO + 闲置回收 + 启动清孤儿。
  • 协议漂移 → generated 入库 + update/check 脚本 + doctor 校验。
  • steer expectedTurnId 竞态 → 严格缓存活跃 turnId,失败降级 queue。

6. 技术选型(沿用 references)

tsup(ESM, bin wrapper) · vitest(重点单测 json-rpc 帧/event-map/run-state/pending-policy/registry) · commander · @larksuiteoapi/node-sdk ^1.65(WSClient, includeRawEvent, pingTimeout) · lark-cli(出站+onboarding) · Node≥20 · TS ^5.6 · https-proxy-agent · qrcode-terminal