Skip to content

Design: last-resort for non-tool content overflow — export-then-truncate vs full compression (global T2) #88

Description

@ranxianglei

Problem

When a conversation's context is dominated by non-tool content (a large user paste, an assistant dump) and there is no compressible tool result to shrink, the kernel's only hard valve — the emergency tool-result truncate (src/truncate-tools.ts) — is a no-op. It only shrinks old tool-result messages, skips the last preserveRecentMessages (5), skips results < 1000 tok, and never touches user/assistant text. The last user message (the current prompt) is always protected (src/recommend.ts). So a provable overflow exists: a large non-tool message that is neither a tool-result nor compressible, at/over the window, with the advisory nudge ignored (model non-compliance).

This is the last-resort gap the other layers do not cover:

  • Preventive (output-headroom — reserves the output budget) does not help when the context itself is already over the window from non-tool content.
  • Reactive (overflow self-heal — learns the window + arms the next turn's emergency) still lands on an emergency truncate that is a no-op for non-tool content.

Purpose of the last-resort (design intent)

The truncation is not meant to be a permanent loss. Its purpose is to temporarily truncate / drop some information so that a NEW compression can succeed — i.e. it is a bridge to recovery, not the end state. On that basis a lossy last-resort is worth it.

That intent opens the door to combining it with export: in an emergency, export first (so the truncated information is recoverable), then truncate.

Current state (verified)

Capability Status
Kernel emergency truncate Only old tool-results; no-op on user/assistant text; skips last 5 + <1000 tok.
Last user message Always protected (the current prompt).
Export Exists only in the proxy as an offline CLI command bili export (src/export.ts:147 exportSession(selector,{dir,output,full})renderHandoff): default = folded view via kernel prune (summaries in place of compressed ranges); --full = every original message; markdown; optional file output. Operator-invoked, offline, NOT on the emergency path. The extension has no export.
"Full compression" Does not exist. No tool/mode (kernel, proxy, or extension) that summarizes everything except the last N messages into a single T2 summary. The kernel has a tiered T1→T2→T3 system (src/compression-rules.ts) but no single "full compress" op.
Session persistence Incremental — compression state + compressed originals only; uncompressed conversation text is not fully persisted (v3 files have a lastMessages snapshot, v2 does not) → an offline export of an older session may lack the full text.

Candidate approaches

A. Export-then-truncate

On emergency (context ≥ threshold, nothing viable to compress, no tool-result to shrink):

  1. Export the full current context to a file (reuse the proxy's exportSession/renderHandoff, but make it live — in the emergency path, using the in-memory context the host already has).
  2. Truncate the oldest large non-tool message(s) (skip the last user message + the last N), down to a small prefix+suffix (like the tool truncate).

The truncated information is recoverable from the export. This creates room so the model's next compression succeeds (the bridge).

B. Full compression ("global T2")

A new full_compress op: within the remaining compressible space, have the model summarize everything except the last N messages into a single T2 summary (a global tier-2 distill). More elegant — the model summarizes, so the loss is controlled and it produces a real summary block the tier system can later condense — but it needs a model round-trip (not instant) and a new tool/mode.

Open questions (for discussion)

  1. Which approach — A, B, or an A-then-B escalation ladder (instant truncate as the immediate backstop, full-compression as the follow-up)?
  2. Placement — truncate/full-compress are kernel capabilities (shared by all hosts); export is a host capability (proxy has it, extension doesn't). Should the kernel emit a "last-resort" signal that the host fulfils (export + optional truncate), or should the kernel do the truncate itself while the host does the export?
  3. Making export live — the current export is offline CLI. An in-emergency export needs the full current context, which the host has in memory but does not fully persist (incremental persistence). How do we obtain the full text at emergency time?
  4. What to truncate — which non-tool messages (oldest first? skip the last user message + last N?), and how much to keep (prefix+suffix size)? The user-paste loss is the risk being mitigated by the export.
  5. Full-compression latency — it needs a model round-trip. Acceptable in an emergency (adds a turn), or must the last-resort be instant (truncate)?
  6. Extension parity — the extension has no export. Does it need one for the last-resort?
  7. Trigger condition — exactly when does the last-resort fire (e.g. ≥95% of the (headroom-reserved) window + no viable range + no tool-result to shrink), and how does it interact with the existing overflow self-heal (learned window + armed emergency) and output-headroom?

Scope / non-goals

  • This is a design-discussion issue (no implementation in this issue).
  • It complements the already-landed preventive (output-headroom) and reactive (overflow self-heal) layers in the two downstream hosts.

Related

  • billion-context PR #172 (proxy: self-heal + output-headroom)
  • billion-context-pi PR #177 (extension: self-heal + output-headroom)
  • Kernel: src/truncate-tools.ts (emergency truncate), src/recommend.ts (viability + last-user protection), src/compression-rules.ts (T1→T2→T3 tiers), src/nudge-text.ts (tier distill nudges)
  • Proxy: src/export.ts (offline exportSession/renderHandoff), src/persist.ts (incremental persistence, v2/v3)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions