English

第 4 部

开放上下文而不失控

客户端可以渲染上下文,但 runtime 必须仍然是真相来源。

第 8 章:面向客户端的上下文

阅读契约: 把本章当作 context ownership 与 context display 的分界。阅读时分清 TUI、realtime、app-server、token usage 和 trace 能展示什么,以及它们为什么不是 truth source。

第 7 章展示了 runtime 可以从 rollout 证据重建有效上下文。最后一层是暴露:用户和客户端需要看到上下文状态:token usage、compaction 提示、realtime 模式、thread 历史,以及附加到已存在线程时的回放 usage。Codex 通过 TUI、app-server 通知、realtime context 模块、rollout trace 和 telemetry 暴露这些事实。核心规则始终是:客户端渲染上下文,runtime 拥有上下文。

这种分离让 UI 不会变成另一个 context manager:TUI 可以显示剩余上下文,app-server 可以回放 token usage,trace 可以解释 compaction,但 live 历史账本和 turn envelope 留在 core。

读完本章,你应该把客户端面理解为 runtime 拥有的上下文状态的投影。

客户端面与它们的 owner

Codex 通过几个面暴露上下文。表很短但值得记住:

它显示什么Runtime ownerOwner 错位时的失败模式
TUI token barinput/cached/output token 与剩余比例。ContextManager.token_info + 显示 baseline。UI 自己造一个预算数字。
App-server token 通知已连接客户端的实时 token usage 事件。采样后的 token usage 事件。客户端从文本渲染推断状态。
App-server 回放重新连接时恢复的 token usage 更新。rollout 证据 + 重连作用域。回放把事件复制给其他订阅者。
Realtime fragmentRealtime 模式起止作为模型上下文。TurnContext.modes + 设置更新。模式只在 transport 出现, prompt 里看不到。
Rollout trace已安装 checkpoint, compaction 原因。compaction 安装事件。trace 把 compact-input 与后续 prompt 混在一起。

最右一列才是关键。每个面都有一种”runtime 不是真相来源”时的精确失败方式。

Token Usage 是上下文面

TUI token usage 模型把 input、cached input、output、reasoning output 和 total token 分开,再相对于经过 baseline 调整的上下文窗口计算剩余百分比。这个 baseline 是显示选择,不是 runtime 的唯一预算规则。Core runtime 仍然用模型信息和 token usage 触发 compaction。 同一份源事实喂给多个面。这就是 UI 不撒谎的原因。模式是”从一个事实 fan-out”,而不是”让每个消费者算自己的数字”。如果 TUI bar 与 compaction 阈值不一致,那是 bug,不是显示偏好。

App-Server 回放

客户端附加到已有 thread 时,app-server 可以向那条连接发送一次恢复后的 token usage 更新。代码把这当作生命周期回放,而不是新的模型事件。这避免了重复持久化的 usage 记录,也避免向其他订阅者发送旧更新带来的困扰。

Attribution 很谨慎:如果最近持久化的 token 计数有显式 turn id 且重建后的 thread 仍包含它,就用那个 id;如果重建中 turn id 变化,则回退到 token 计数出现时记录的活动 turn 位置。

// 伪代码 -- 说明回放归属。
owner = findTurnActiveWhenLatestTokenCountWasPersisted(rollout)
if rebuiltThread.hasTurn(owner.id):
    notify(connection, owner.id, usage)
else:
    notify(connection, rebuiltThread.turnAt(owner.position), usage)

模式很微妙:客户端回放是”连接作用域”的,因为它向新观察者解释历史,而不是一次新的 runtime 事件。

这个范围规则说明了为什么这次 replay 事件只发给附加的客户端:其他订阅者已经在事件实时发生时看过它,再发一次会被当成新模型动作,扰乱它们的状态。

Realtime 是上下文, 不只是 transport

Realtime 状态出现在 settings update 逻辑中。Realtime 起止可以发出模型可见指引。这是正确的,因为 realtime 改变的是模型该如何交互,而不只是字节的传输方式。如果语音或 realtime 客户端改变了交互契约,模型必须看到关于这种模式的上下文。

这强化了第 2 章的信封理念:客户端元信息和 realtime 标志属于 turn context,因为它们改变 runtime 契约。

一张小对比表说明这层动作:

处理方式结果
Realtime 仅作 transport 标志。模型继续输出长篇文字, 音频客户端却期待 turn 短答。
Realtime 作为 context fragment。模型收到显式指引: 短回合, 预期被打断, 留出沉默。

正确的处理跨过了一层边界:原本是客户端元信息,因为在模型层面会改变语义,被提升为 prompt 可见状态,而不只是停留在线路层。

Trace 提供 Compaction 证据

远程 compaction 记录已安装 checkpoint payload,里面包含输入历史与 replacement history。这条 trace 边界与之后的推理请求不同。这种区分让 reducer 与 debugger 能精确表达发生了什么:provider 压缩了一份历史,Codex 安装了另一份 live 历史,未来采样使用更新后的 prompt projection。

好的可观测性不只是数 token,它还保留语义边界。

Semantic trace boundary:compact input、checkpoint install、future sampling、trace reducers、runtime ledger 与 client surfaces 的分界
Trace 有价值,是因为它没有把 compact input、checkpoint install 与后续 sampling 混成一个模糊事件;每个阶段都可以单独审计。

三阶段同处一条 trace:compact、install、sample。朴素 trace 会把它们折成一个”compaction 事件”,让单独审计每个阶段变得不可能。

应用模式

  1. Runtime-Owned Display: 客户端可以渲染上下文事实,但不能拥有它;迁移时让 UI 状态从 runtime 事件派生;避免只存在于 UI、模型从未看到的上下文替代 runtime state。
  2. Connection-Scoped Replay: 历史上下文事实只回放给正在附加的观察者;迁移到 resume 客户端;标记 replay 事件,避免它们被当成新 live 事件。
  3. Attribution Fallback: 恢复 usage 时优先按 id,其次按位置归属;迁移到重建时间线;避免重新生成的 id 破坏 UI 状态。
  4. Mode as Context: 改变行为的交互模式视为模型可见上下文;迁移时 diff 模式状态;不要把改变行为的 transport 标志藏在 prompt 之外。
  5. Semantic Trace Boundary: 把上下文重写当作 install 事件 trace;迁移时区分 compaction input 与后续 sampling input;避免 observability 把多阶段折成一团。