Skip to content

feat(context): compression config surface, structured handoff prompt, and summary-request elision - #3532

Open
Raing5Days wants to merge 6 commits into
GCWing:mainfrom
Raing5Days:feat/context-compression-foundations
Open

Raing5Days wants to merge 6 commits into
GCWing:mainfrom
Raing5Days:feat/context-compression-foundations

Conversation

@Raing5Days

Copy link
Copy Markdown
Contributor

Summary

First batch of the context-compression roadmap (three separable commits, each independently revertible):

  1. Config surface + settings page — add six ai.context_compression_* config keys (every default preserves current behavior; reserved keys are documented as such) and surface the previously config-file-only ai.enable_context_compression_prefetch flag on a new ai.context settings page (en-US / zh-CN / zh-TW). No new Tauri commands; the page reads and writes through the existing config API.
  2. Structured handoff summary prompt — rewrite build_compact_prompt from a free-form bullet list into fixed sections (Goal / Constraints & Preferences / Progress / Key Decisions / Next Steps / Critical Context) with hard retention rules: exact paths, symbols, commands, error messages, unanswered user questions verbatim, repository state. The anti-bulk-copy, reloadable-guidance, and summary-only-turn constraints carry over unchanged.
  3. Summary-request elision for planning dead-ends — the planner floors the cutoff above the first atomic unit, so a gigantic first message pins the summary input: every plan overflows and the turn previously died into L2 emergency truncation with no summary. When planning dead-ends (cutoff stops moving, or the tail ladder has no room), a new request-side elision ladder folds complete fenced/XML blocks (>= threshold, oldest first, per-pass budget capped, up to 3 progressively deeper passes) into the summary request copy only. Stored history, message identities, and the compression plan are never rewritten. Exhausted elision keeps the existing terminal semantics; no local summary fallback is introduced.

Fixes #

Type and Areas

Type: Feature

Areas: Rust core (config contracts, agentic session/execution compression), web UI (settings page, locales)

Motivation / Impact

Users hitting the context window currently have exactly one automatic path (LLM summary) whose input can, in a real corner case (huge first paste), become impossible to summarize, silently ending in hard truncation. This batch: (a) makes the compression prefetch toggle user-visible, (b) improves summary quality/structure for every compaction, and (c) turns the dead-end into a bounded, logged rescue that keeps stored history intact. Reserved config keys land inert with their documented defaults so the follow-up provider-native compaction and pruning PRs do not need another config migration.

Verification

  • cargo test --locked -p openbitfun-config-contracts --lib — 129 passed (incl. new legacy-payload / default-omission / round-trip test for the six keys)
  • cargo test --locked -p openbitfun-core --no-default-features --features agent-runtime,git --lib compression — 70 passed (8 new elision unit tests; dead-end recovery + exhaustion integration tests; existing ladder/prefetch tests unchanged)
  • cargo test --locked -p openbitfun-core --no-default-features --features agent-runtime,git --lib -- config_export_round_trip_covers_persisted_preference_groups every_catalog_config_option — 4 passed
  • node scripts/i18n-audit.mjs — passed (en-US / zh-CN / zh-TW parity for the new namespace)
  • pnpm run theme:color-audit (web-ui surface) — passed (no new color tokens; page reuses existing semantic styles)
  • pnpm --dir src/web-ui run type-check and ContextSettingsPage vitest (3 passed) were run on the pre-rebase tree; the web-ui files in this branch are byte-identical to that state (verified via git diff between the branches), CI covers the full frontend matrix.
  • pnpm run fmt:rs applied to all touched Rust files.

Reviewer Notes

  • Commit 1 (config+UI) and commit 2 (prompt) are independent; commit 3 depends only on the config keys from commit 1. Happy to split if preferred.
  • Elision is request-scoped by design: the microcompact removal taught us prefix rewrites break provider KV caches and drive tool-call loops; nothing here mutates stable history (no new message IDs, no context-store writes).
  • The dead-end trigger is deliberately narrower than "any overflow": the existing recent-tail ladder keeps absolute priority; elision only arms when the cutoff can no longer move.
  • Upgrade compatibility: legacy configs without the new keys deserialize to current behavior and re-serialize without defaulted keys (typed test locks this); compression failure semantics unchanged (context preserved, turn terminates).
  • Rollback: ai.context_compression_request_elision=false restores the previous terminal path; the prompt change (commit 2) reverts cleanly as text.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

Add the configuration contract for the context compression roadmap
(option-first; every default preserves current behavior):

- ai.context_compression_method (summary | native_first, reserved)
- ai.context_compression_summary_mode (rewrite | iterative, reserved)
- ai.context_compression_summary_max_tokens (reserved)
- ai.context_compression_request_elision (default on)
- ai.context_compression_prune_on_compact (default off, reserved)
- ai.context_compression_elide_min_tokens (default 400)

The engine does not read the reserved keys yet; they land with the
following compression PRs. Typed serde tests cover legacy payloads that
predate the keys, defaulted-key omission, and explicit-value round
trips, and the config export/import round-trip fixture covers the new
paths.

Surfaces the existing ai.enable_context_compression_prefetch flag on a
new ai.context settings page (en-US, zh-CN, zh-TW) so prefetch stops
being a config-file-only option. No new Tauri commands; the page reads
and writes through the existing config API.

Verification:
- cargo test -p openbitfun-config-contracts --lib (112 passed)
- cargo test --locked -p openbitfun-core --no-default-features
  --features agent-runtime,git,ssh-remote --lib --
  config_export_round_trip_covers_persisted_preference_groups
  every_catalog_config_option (4 passed)
- pnpm --dir src/web-ui run test:run ContextSettingsPage (3 passed)
- pnpm run i18n:audit; pnpm run theme:color-audit
- pnpm --dir src/web-ui run type-check
Rewrite build_compact_prompt from a free-form bullet list into a fixed
sectioned handoff template, keeping the summary-only turn contract and
the anti-bulk-copy / reloadable-guidance rules from the previous text:

- Fixed sections in order: Goal, Constraints & Preferences, Progress
  (Done / In Progress / Blocked), Key Decisions, Next Steps, Critical
  Context; sections with no content may be omitted.
- Retention requirements: exact file paths, symbol names, commands, and
  error messages; user questions still awaiting an answer preserved
  verbatim; repository state (branch, uncommitted changes) when relevant.
- Next Steps are imperative actions addressed to the successor, and the
  handoff itself must never appear as progress or a next step.

Default behavior change is prompt text only: the request shape, retry
ladder, todo checkpoint, transcript reference, and summary message
assembly are untouched.

Verification:
- cargo test --locked -p openbitfun-core --no-default-features
  --features agent-runtime,git,ssh-remote --lib compression
  (60 passed, incl. new compact_prompt_is_structured_ascii_and_constrained)
The planner floors the cutoff above the first atomic unit, so a gigantic
first message pins the summary input: the recent-tail ladder can never
shrink it, every plan overflows, and the turn terminates with no summary
before L2 emergency truncation drops rounds silently.

Add a request-side elision ladder that runs only when planning dead-ends
(cutoff stops moving, or the tail ladder has no room left):

- New session::compression::elision module: a pure scanner folds complete
  fenced code blocks and top-level lowercase XML blocks (>= a threshold,
  oldest first, per-pass budget capped) across message text and
  result_for_assistant copies. Stored history, message identities, and
  the compression plan are never rewritten.
- CompressionJob::run applies up to three progressively deeper passes
  (threshold, /2, /4) to the summary request copy after the unelided
  attempt; the recent-tail ladder keeps priority while it can move the
  cutoff. Exhausted elision keeps the existing terminal semantics
  (cannot-reduce-further and plan-N overflow errors) with no local
  summary fallback.
- Honors ai.context_compression_request_elision and
  ai.context_compression_elide_min_tokens from the PR-1 config surface,
  defaulting to enabled/400 when the config service is unavailable.

Verification:
- cargo test --locked -p openbitfun-core --no-default-features
  --features agent-runtime,git,ssh-remote --lib compression
  (70 passed: 8 new elision unit tests, dead-end recovery + exhaustion
  integration tests; existing ladder and prefetch tests unchanged)
…tic manual

CI Frontend Build failed because capabilities:check requires every
settings page registered in settingsRegistry.ts to have a semantic
capability entry. Add setting.ai.context to the interactive-capabilities
manual (bilingual titles/summary/keywords/highlights/steps, two
documented items for compression prefetch and summary-request elision,
destination ai.context) and regenerate the derived artifacts:
docs/interactive-capabilities, the global-search runtime catalog, the
generated product-control catalog, and the productControl TS bindings.

Both items are classified as open controls (unstructuredInteraction):
their config paths stay out of the agent-controllable option registry
for now because ai.enable_context_compression_prefetch is deliberately
omitted from persisted config when true, so the config-path option
readback contract does not apply to it yet.

Verification:
- node scripts/generate-interactive-capabilities.mjs --check (verified
  23 features + 22 settings)
- node --test scripts/interactive-capabilities.test.mjs (16 passed)
- cargo test --locked -p openbitfun-core --no-default-features
  --features agent-runtime,git --lib -- every_catalog_config_option
  config_export_round_trip_covers_persisted_preference_groups (4 passed)
…cture

The registry IA test asserts the exact per-category page list and total page count, so registering ai.context must update both. Verified with the full web-ui suite (settingsRegistry 30 passed) plus type-check after gen:types.
The appearance contract audit rejects data-openbitfun-view values missing from the surface descriptor, so the new ai.context settings page needs its own facet value. Verified with node scripts/audit-appearance-contracts.mjs and a full pnpm run build:web.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant