diff --git a/docs/architecture/llm-compaction-events-log-projection-draft.md b/docs/architecture/llm-compaction-events-log-projection-draft.md index 3bd9685719c..cb91b4f1b12 100644 --- a/docs/architecture/llm-compaction-events-log-projection-draft.md +++ b/docs/architecture/llm-compaction-events-log-projection-draft.md @@ -7,7 +7,7 @@ counterpart: ./llm-compaction-events-log-projection-draft.zh-CN.md implementation_status: current document_status: draft translation_status: synced -last_verified: 2026-08-28 +last_verified: 2026-10-10 owners: - maka-backend --- @@ -38,7 +38,7 @@ This chapter builds on Chapter 1's log-first Runtime and Chapter 2's distinction The primary subject is **RuntimeEvent history compaction**: a compactor produces either a continuation summary or provider-native compact state, the checkpoint covers a safe prefix of RuntimeEvents, and later requests use that projection in place of the prefix. The same planner and checkpoint transaction serve manual, pre-turn, mid-turn, and overflow triggers. The chapter does not fully cover active or stale pruning of individual Tool Results; those reduce provider messages without creating another LLM compaction mechanism. -This chapter describes the implementation current as of 2026-08-30. Ledger-backed checkpoints use schema V2 for text summaries and schema V3 for provider-native state. OpenAI Codex subscription models prefer Codex remote compaction V2 and retain the text summarizer as a narrow liveness fallback; other providers use text-summary behavior directly. +This chapter describes the implementation current as of 2026-10-10. Ledger-backed checkpoints use schema V2 for text summaries and schema V3 for provider-native state. OpenAI Codex subscription models prefer Codex remote compaction V2 and retain the text summarizer as a narrow liveness fallback; other providers use text-summary behavior directly. ## Start with a long-running Session @@ -146,7 +146,7 @@ HistoryCompactCheckpoint sourceDigest projection V2: summary - V3: providerState { kind, connectionSlug, modelId, itemId, encryptedContent } + V3: providerState { kind, connectionId, modelId, itemId, encryptedContent } limitations estimatedTokens lineage @@ -157,7 +157,7 @@ For V2, the model sees `summary`. For V3, the provider sees its own opaque compa ## Current: every request still begins with RuntimeEvents -The prior-history path for a normal Send begins in `AiSdkBackend.buildPriorMessages()`. It does not reuse the provider messages assembled for an earlier request. Instead, it receives RuntimeEvents from earlier Runs and executes a projection pipeline: +The prior-history path for a normal Send begins in `AiSdkTurn.buildPriorMessages()`. It does not reuse the provider messages assembled for an earlier request. Instead, it receives RuntimeEvents from earlier Runs and executes a projection pipeline: 1. Exclude the current `turnId` to obtain the prior Runtime context. 2. Prepare the context-budget policy. @@ -185,7 +185,7 @@ Capacity is the context window the user declared for the selected model, or noth Trigger owners use that capacity but do not participate in compaction: - the active-turn evaluator emits a Compact command when the previous accepted request's real usage plus the reply reserve reaches the user-declared capacity; -- provider-overflow recovery emits the same command after a real overflow, and the two share one budget: the module is entered at most once per send; +- provider-overflow recovery emits the same command after a real overflow; a successful provider step resets the shaping budget, so recovery stays available on later steps, while the summarizer-failure circuit remains turn-scoped; - manual `context.compact` emits it directly, without manufacturing a high-water crossing. Once emitted, the command always enters the same transaction. The planner receives no force flag, context window, reserve, next-request estimate, high-water ratio, or minimum-recent-Turn policy: @@ -236,11 +236,11 @@ The portable text summarizer remains a bounded liveness fallback. Maka retries o Compaction input preserves assistant-step chronology. Because the Responses converter cannot resend provider-executed tool results under `store:false`, a settled hosted call/result is lowered only for this compaction request into a paired ordinary function call and output, followed by the grounded assistant text. This keeps the available tool evidence in the request without producing an orphan output. -The compaction call receives an output cap of 8,000 tokens and the provider's normal request path decides whether that call fits. Tool Result archive policies may still replace oversized individual results with durable placeholders, but history compaction does not measure the final request or reject a candidate because a local estimate says it is too large. +The portable text summarizer receives an output cap of 8,000 tokens; the native Codex compaction call passes no output cap, and the provider's normal request path decides whether that call fits. Tool Result archive policies may still replace oversized individual results with durable placeholders, but history compaction does not measure the final request or reject a candidate because a local estimate says it is too large. This is deliberately a history-only contract. Maka does not send the current system prompt or tool catalog to the remote compactor, unlike the Codex CLI's whole-request assembly. Those values are neither part of checkpoint source coverage nor frozen into the checkpoint; the subsequent model request always applies its current system prompt and tools. This keeps provider-native and text-summary compactors behind the same small contract, at the cost of not giving the compactor that extra request-shape context. -Maka accepts exactly one `openai.compaction` output with both `itemId` and `encryptedContent`, then persists it in a schema-V3 checkpoint. The state is bound to the connection slug and model ID. A different provider, connection, or model rejects that checkpoint and reprojects from raw RuntimeEvents. Matching checkpoints replay as provider custom parts across pre-Turn compaction, mid-Turn capacity compaction, and reactive overflow retry. +Maka accepts exactly one `openai.compaction` output with both `itemId` and `encryptedContent`, then persists it in a schema-V3 checkpoint. The state is bound to the connection ID and model ID. A different provider, connection, or model rejects that checkpoint and reprojects from raw RuntimeEvents. Matching checkpoints replay as provider custom parts across pre-Turn compaction, mid-Turn capacity compaction, and reactive overflow retry. The V3 schema is a compatibility boundary: older binaries that only understand schema V2 reject it and fall back to raw history. Provider state is redacted from request-capture telemetry and omitted from conversation copies; copied Sessions retain raw RuntimeEvents and may compact them again. The explicit trigger is an observed Codex subscription protocol used by the Codex client, not a claim about the public Responses API contract. diff --git a/docs/architecture/llm-compaction-events-log-projection-draft.zh-CN.md b/docs/architecture/llm-compaction-events-log-projection-draft.zh-CN.md index 2dc3514ab90..60df5cabc2a 100644 --- a/docs/architecture/llm-compaction-events-log-projection-draft.zh-CN.md +++ b/docs/architecture/llm-compaction-events-log-projection-draft.zh-CN.md @@ -7,7 +7,7 @@ counterpart: ./llm-compaction-events-log-projection-draft.md implementation_status: current document_status: draft translation_status: synced -last_verified: 2026-08-28 +last_verified: 2026-10-10 owners: - maka-backend --- @@ -38,7 +38,7 @@ owners: 本文主要讨论 **RuntimeEvent history compaction**:compactor 生成 continuation summary 或 provider-native compact state,checkpoint 覆盖一段安全的 RuntimeEvent 前缀,并在以后请求中用该投影替代前缀。手动、pre-turn、mid-turn 与 overflow 触发器共用同一个 planner 和 checkpoint transaction。本文不完整展开单个 Tool Result 的 active/stale prune;它们会缩小 provider messages,但不会形成另一套 LLM compaction 机制。 -本文描述截至 2026-08-30 的当前实现。ledger-backed checkpoint 中,schema V2 保存文本摘要,schema V3 保存 provider-native state。OpenAI Codex 订阅模型优先使用 Codex remote compaction V2,并保留文本 summarizer 作为范围严格的 liveness fallback;其他 provider 直接使用文本摘要行为。 +本文描述截至 2026-10-10 的当前实现。ledger-backed checkpoint 中,schema V2 保存文本摘要,schema V3 保存 provider-native state。OpenAI Codex 订阅模型优先使用 Codex remote compaction V2,并保留文本 summarizer 作为范围严格的 liveness fallback;其他 provider 直接使用文本摘要行为。 ## 从一个长期会话开始 @@ -146,7 +146,7 @@ HistoryCompactCheckpoint sourceDigest projection V2: summary - V3: providerState { kind, connectionSlug, modelId, itemId, encryptedContent } + V3: providerState { kind, connectionId, modelId, itemId, encryptedContent } limitations estimatedTokens lineage @@ -157,13 +157,13 @@ V2 中模型主要看到 `summary`;V3 中 provider 看到自己的 opaque comp ## Current:完整请求仍从 RuntimeEvents 开始 -每次普通 Send 的 prior-history 路径从 `AiSdkBackend.buildPriorMessages()` 开始。它不会先读取上次已经拼好的 provider messages,而是优先接收此前 Run 的 RuntimeEvents,再执行一条投影流水线: +每次普通 Send 的 prior-history 路径从 `AiSdkTurn.buildPriorMessages()` 开始。它不会先读取上次已经拼好的 provider messages,而是优先接收此前 Run 的 RuntimeEvents,再执行一条投影流水线: 1. 排除当前 `turnId`,得到 prior Runtime context; 2. 准备 context budget policy; 3. 加载最新且兼容的 ledger-backed checkpoint; 4. 在 immutable RuntimeEvent 序列上校验并 replay 已有 checkpoint; -5. 只对未覆盖的 projected remainder 执行 stale oversized Tool Result prune; +5. 按当前与历史 turn 的同一体积规则准备 oversized 文本 Tool Result; 6. 如果 active request 有用户声明的 Maka 窗口,且上一次成功请求的真实 usage 加上回复预留 `min(上次回复 × 2, 8000)` 达到它,选择 safe prefix 与 retained tail; 7. 如果旧 checkpoint 不足以覆盖新的 fold,调用 compactor 滚动生成 successor; 8. successor 通过校验并 durable record 后才能使用; @@ -172,7 +172,7 @@ V2 中模型主要看到 `summary`;V3 中 provider 看到自己的 opaque comp 这条顺序说明三件事。 -第一,checkpoint source matching 始终面对 immutable RuntimeEvent ledger。Stale Tool Result prune 只塑造未覆盖的 replay remainder,因此 recent-turn window 的移动不会改变 digest 所依据的字节,进而错误地让本来匹配的 checkpoint 失效。 +第一,checkpoint source matching 始终面对 immutable RuntimeEvent ledger。Tool Result prune 以独立的 durable projection transition 记录;checkpoint replay 同时校验不可变的覆盖身份与有效覆盖摘要。 第二,compaction 发生在 **model-history projection** 内,而不是 RuntimeEvent append path 内。模型和工具已经产生的事件不会因为以后预算变化而改变。 @@ -236,11 +236,11 @@ Repair 之外的 malformed retry 也有上限。Runtime 为每个 Session backen Compaction input 会保留 assistant step 的时序。由于 Responses converter 在 `store:false` 下无法重新发送 provider-executed tool result,已经完整结算的 hosted call/result 只在这次 compaction request 中降级为成对的普通 function call 与 output,之后再放 grounded assistant text。这样既保留了现有 tool evidence,也不会生成悬空 output。 -Compaction call 的 output 上限是 8,000 tokens,是否能放下由 provider 的正常请求路径决定。Tool Result archive policy 仍可以把过大的单条结果替换为可持久化 placeholder,但 history compaction 不再量最终 request,也不会因为本地估算认为过大而拒绝候选。 +可移植文本 summarizer 的 output 上限是 8,000 tokens;native Codex compaction call 不传 output cap,是否能放下由 provider 的正常请求路径决定。Tool Result archive policy 仍可以把过大的单条结果替换为可持久化 placeholder,但 history compaction 不再量最终 request,也不会因为本地估算认为过大而拒绝候选。 这是有意设计成 history-only 的契约。与 Codex CLI 的 whole-request assembly 不同,Maka 不会把当前 system prompt 或 tool catalog 发给 remote compactor;它们既不属于 checkpoint source coverage,也不会被冻结进 checkpoint,后续模型请求始终使用当时最新的 system prompt 和 tools。这样 provider-native 与 text-summary compactor 可以共享同一份小契约,代价是 compactor 无法利用这部分额外的 request-shape context。 -Maka 只接受唯一一个同时带有 `itemId` 与 `encryptedContent` 的 `openai.compaction` output,并把它持久化为 schema-V3 checkpoint。state 绑定 connection slug 与 model ID;provider、connection 或 model 不匹配时,checkpoint 会被拒绝,并从 raw RuntimeEvents 重新投影。匹配的 checkpoint 在 pre-Turn compaction、mid-Turn capacity compaction 和 reactive overflow retry 中都以 provider custom part 回放。 +Maka 只接受唯一一个同时带有 `itemId` 与 `encryptedContent` 的 `openai.compaction` output,并把它持久化为 schema-V3 checkpoint。state 绑定 connection ID 与 model ID;provider、connection 或 model 不匹配时,checkpoint 会被拒绝,并从 raw RuntimeEvents 重新投影。匹配的 checkpoint 在 pre-Turn compaction、mid-Turn capacity compaction 和 reactive overflow retry 中都以 provider custom part 回放。 V3 schema 也是兼容边界:只理解 schema V2 的旧 binary 会拒绝它并回退 raw history。provider state 会从 request-capture telemetry 中脱敏,也不会进入 conversation copy;复制后的 Session 仍保留 raw RuntimeEvents,需要时可以重新 compact。这里的显式 trigger 是 Codex client 已使用的 Codex 订阅协议,不代表对公开 Responses API contract 的宣称。 @@ -453,7 +453,7 @@ Maka 只有一套 LLM compaction 机制,以及一个相邻的 current-request Active Tool Result Prune 仍是 deterministic、非 LLM 的 rewrite。它先归档 eligible raw Tool Result,再向 AgentRun event ledger 追加 durable projection transition,并由 effective-history reducer 生成 current request。后续 replay、restart、budgeting 与 compaction 也消费同一 reducer。Prune 既不总结 span,也不创建 checkpoint,canonical RuntimeEvents 保持不变。 -工具结果裁剪只保留 `toolResultPrune.enabled`,当前与历史 turn 使用同一个固定体积规则。文本投影超过 7,500 个序列化字符时,保留有界首屏和 `next` 续读参数;图片沿用原有 materialization 策略。`Read` 只有必填的 `path` 和可选、零基行坐标的 `offset` / `limit`。关闭裁剪或传入大 limit 都不能绕过单次响应上限。显式 limit 定义本次读取范围,超长单行由 Harness 自动分段,并用正文校验过的地址续读。ArchiveRead、inspect/query/search 和 active/stale 调参字段直接删除,不保留别名。 +工具结果裁剪只保留 `toolResultPrune.enabled`,当前与历史 turn 使用同一个固定体积规则。文本投影超过 7,500 个 UTF-8 字节时,保留有界首屏和 `next` 续读参数;图片沿用原有 materialization 策略。`Read` 只有必填的 `path` 和可选、零基行坐标的 `offset` / `limit`。关闭裁剪或传入大 limit 都不能绕过单次响应上限。显式 limit 定义本次读取范围,超长单行由 Harness 自动分段,并用正文校验过的地址续读。ArchiveRead、inspect/query/search 和 active/stale 调参字段直接删除,不保留别名。 工具结果地址使用 `maka://runtime/tool-results/`。Host 在调用方 Session 内解析地址,验证已接受的投影 transition,从原事件恢复模型正文;模型不必复写摘要或内部 transition 身份。先持久化 transition,再替换投影;历史重放、压缩尾部和溢出重试都经过同一个 reducer。Checkpoint 仍按不可变事件身份匹配,并校验有效覆盖内容的摘要。