共享历史不等于共享活会话

**做「手机看/控电脑上的 Agent」时,「手机和电脑同一个会话」有三个不同层级,别把它们当成一回事:①同一个历史 thread;②同一个正在运行的 turn;③同一个电脑界面(Desktop/CLI 当前窗口)。只共享 ①,手机上能看到上文,但那不是「活的同一个进程」。**

三个层级

层级含义能不能做到
① 同一历史会话用同一个 threadId / 会话记录可以
② 同一运行中 turn手机发消息进入同一个常驻 runtime,实时收 delta可以(需常驻 app-server)
③ 同一电脑界面手机发的消息直接出现在已打开的 Desktop/CLI 窗口里最难,取决于该界面是否连同一个 runtime

「新进程 + resume threadId」的迷惑性

codex exec resume <threadId> "..." 是每条消息新起一个一次性进程,只是带着上次的 thread id。所以:

  • 手机能看到上文 → 因为 resume 带了历史,不是因为进程还活着。
  • 它属于「① 共享历史」,不是「② 共享活会话」。
  • 副作用:codex exec 本来就是一次性进程,退出码异常时桥接服务会当成错误 → 手机上表现为「卡在生成中 / code exit」。

判据:如果每发一条消息电脑上就多一个 codex exec 子进程,那就只是共享历史。

「引用会话」也不等于「在该会话上继续」。 手机端引用一个已导入的会话、然后从引用卡片开始新对话时,平台是新建一个会话(历史消息只是被读进来当上下文),消息记在新会话里,原会话保持不动。所以「我在那个会话里发了消息」和「那个会话里多了我的消息」是两件事 —— 想真正接续,要在会话列表里打开原会话再发。

独立 app-server 也能实现层级 ②,但必须成为唯一真源

官方 remote-control 会被「第三方 key 不能用」卡住,所以另起一个独立 app-server 是对的。但独立 app-server 要真同步,前提是电脑端和手机端都走这同一个 app-server:

电脑端输入/界面 ─┐
                ├─→ 同一个 owned app-server ─→ 事件广播给所有客户端
手机端输入/界面 ─┘

硬边界:如果电脑端仍用官方 Desktop 作为主界面,而它不连这个 owned app-server,那独立 app-server 看不到它的实时流。 想同步,电脑端入口也得改走同一个 bridge(本地 Web UI / menubar companion / CLI wrapper 皆可)。

第三条路线:原生会话镜像器(文件 watcher)

如果坚持「电脑端继续用原生 Codex CLI / Desktop,不改输入入口」,那就不是 owned runtime,而是镜像器:

原生 Codex CLI / Desktop
  → 写 ~/.codex/session_index.jsonl、~/.codex/sessions/**/*.jsonl
codex-server.mjs
  → 监听文件变化 → 增量解析 user / assistant 可见消息 → 推给手机 App
手机 App → 展示历史;要续聊时用 threadId resume

它的能力边界很干净:

能力能否
电脑发消息、手机同步能(加强现有导入逻辑)
准实时同步能 —— 前提是原生运行时会边跑边写 JSONL;若只在结束后落盘,就只能结束后同步
手机接续(resume)能
手机中断 / 接管电脑原生正在跑的 turn一般不行 —— 那个进程不是 bridge 启动的

判断依据:真源(谁拥有正在跑的那个 turn)决定实时性上限。 想让电脑原生输入也被实时同步,只有两条路——要么电脑端入口改走同一个 bridge(= owned app-server),要么退化成文件镜像器(准实时 + 不能接管)。

不做通用 engine 的判断

要不要抽象出统一 Engine,按「要覆盖多少个 provider × 多少个平台」定价:只有 Claude Code + Codex 两个 provider、电脑 server + 手机 App 两个入口时,做完整 engine(provider 切换、平台 adapter、command engine)是过度设计。保留两个原生 bridge,只抽很小的共享层(bridge-events.mjs / thread-store.mjs 这类)即可。参见 Agent编排层薄自建优先于重型框架。

相关

  • 远程控制本机Agent要让bridge跑在本机
  • 远程Agent控制要定义执行协议与状态模型
  • 终端画面同步Agent状态不稳定 —— 想连「界面」一起同步时的另一条路线(tmux)
  • Agent编排层薄自建优先于重型框架
  • 上下文按卡片切换会话记忆按账号共享 —— 同一条「共享」谱系:会话记忆按账号共享,上下文按卡片切换
  • 同名provider冲突会让模型路由漂移 —— 同一会话的另一处坑:导入只带消息不带 provider 归属,续聊时会解析到错误的供应商