Summary
#4574 makes the provider the only judge of whether a request fits: Maka's own action is a reversible fold, triggered either by the previous accepted request's real usage reaching the user-declared window, or by a real provider rejection. That contract assumes the provider speaks: it reports usage, and it rejects a request that does not fit in a way Maka can classify. Three situations break that assumption. Review of #4574 (@likun666661) asked that they be named and given a visible behaviour rather than left as open semantics. This issue is that definition, plus the two small follow-up PRs that close the remaining gap.
The three degraded modes
| Provider behaviour |
What Maka can observe |
Behaviour after #4574 |
Gap |
| No usage in the response (some relays) |
token_usage has no lastRequestAnchor |
No baseline → no proactive fold, no eviction check. Provider rejection still folds once and retries. The composer indicator (#4576) shows a dash with "provider reported no usage". |
None planned. OpenAI-compatible chat now requests stream usage by default (stream_options.include_usage); a relay that rejects that field fails with its own error, by contract (test in #4574). |
| Rejection Maka cannot classify (unknown wording) |
An ordinary 4xx provider error |
Turn ends with the provider's message; the user's message stays editable; manual /compact then resend works. Same as before #4574. |
PR E: a "compact and retry" action on that error, running the same fold-once → resend path the runtime already has for classified overflow. UI + one runtime command. |
Silent eviction / rewrite (Ollama truncating to num_ctx, server-side compaction) |
Usage stops growing or drops while Maka only appended |
Declared window: the proactive fold keeps usage under it; the provider never truncates. Undeclared: within one send the context_provider_dropping note fires from step 2 on; across turns nothing fires — #4574's own live Ollama run plateaued at 3716 input tokens with no signal. |
PR D: apply the same rule at the turn boundary: first request of a send has inputTokens at or below the persisted anchor's, and Maka neither folded nor pruned before sending → write the context_provider_dropping note. Not-greater, not strictly-fewer: a provider truncating to its own window reports the same total on every later request, which is exactly the plateau the live Ollama run showed. Note only; no action; a rare false positive after a user edit costs one line of text. |
What "no declared window" guarantees, stated
- Maka never fails a request on its own estimate. Every send goes to the provider.
- A classified rejection is folded once and resent; a second rejection is reported as the provider's error.
- With usage present, a shrinking or stalled input while Maka only appended is reported as a note (mid-turn today, cross-turn after PR D).
- Without usage, the only signal is the indicator's dash; compaction is reactive only.
Plan
Refs #4559, #4574
中文
#4574 之后,"请求放不放得下"只由供应商裁决,Maka 自己只做可逆的折叠。这个约定的前提是供应商会说话:返回 usage,拒绝时报 Maka 认得出的错。三种情况打破这个前提,评审要求把它们的信号和行为写清楚,而不是留成开放语义。
- 不返回 usage:没有基线,不主动折叠;供应商拒绝时仍折叠一次重发;指示器显示横线。不再另做。
- 拒绝但认不出措辞:turn 以供应商原文报错结束,消息可编辑;手动
/compact 后重发可用。PR E 加一个"压缩后重试"按钮,走同一条 fold-once → 重发。
- 静默丢弃(Ollama 截到
num_ctx):设了窗口就被主动折叠兜住;没设窗口时,同一次发送内第 2 步起能检测,跨 turn 抓不到。PR D 把同一条规则挪到 turn 边界:新发送第一步 input 不高于上次落盘 anchor,且发送前没折叠没归档,就写提示(持平就是 Ollama 那种截断的信号,严格小于抓不到)。只写提示,不做动作。
Summary
#4574 makes the provider the only judge of whether a request fits: Maka's own action is a reversible fold, triggered either by the previous accepted request's real usage reaching the user-declared window, or by a real provider rejection. That contract assumes the provider speaks: it reports usage, and it rejects a request that does not fit in a way Maka can classify. Three situations break that assumption. Review of #4574 (@likun666661) asked that they be named and given a visible behaviour rather than left as open semantics. This issue is that definition, plus the two small follow-up PRs that close the remaining gap.
The three degraded modes
token_usagehas nolastRequestAnchorstream_options.include_usage); a relay that rejects that field fails with its own error, by contract (test in #4574)./compactthen resend works. Same as before #4574.num_ctx, server-side compaction)context_provider_droppingnote fires from step 2 on; across turns nothing fires — #4574's own live Ollama run plateaued at 3716 input tokens with no signal.inputTokensat or below the persisted anchor's, and Maka neither folded nor pruned before sending → write thecontext_provider_droppingnote. Not-greater, not strictly-fewer: a provider truncating to its own window reports the same total on every later request, which is exactly the plateau the live Ollama run showed. Note only; no action; a rare false positive after a user edit costs one line of text.What "no declared window" guarantees, stated
Plan
docs/architecture/llm-compaction-events-log-projection-draftonce D lands.Refs #4559, #4574
中文
#4574 之后,"请求放不放得下"只由供应商裁决,Maka 自己只做可逆的折叠。这个约定的前提是供应商会说话:返回 usage,拒绝时报 Maka 认得出的错。三种情况打破这个前提,评审要求把它们的信号和行为写清楚,而不是留成开放语义。
/compact后重发可用。PR E 加一个"压缩后重试"按钮,走同一条 fold-once → 重发。num_ctx):设了窗口就被主动折叠兜住;没设窗口时,同一次发送内第 2 步起能检测,跨 turn 抓不到。PR D 把同一条规则挪到 turn 边界:新发送第一步 input 不高于上次落盘 anchor,且发送前没折叠没归档,就写提示(持平就是 Ollama 那种截断的信号,严格小于抓不到)。只写提示,不做动作。