Skip to content

feat(loop): graduated context trimming, margin calibration, rolling compaction#102

Merged
jkyberneees merged 2 commits into
mainfrom
feat/context-trimming-compaction
Jul 25, 2026
Merged

feat(loop): graduated context trimming, margin calibration, rolling compaction#102
jkyberneees merged 2 commits into
mainfrom
feat/context-trimming-compaction

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

Summary

Reworks context-window management in the agent loop (internal/loop) and session store (internal/session), plus config/CLI plumbing for a new opt-in compaction feature.

Correctness fixes

  • estimateToolDefs now counts JSON parameter schemas — the bulk of every tool definition across ~26 built-ins + MCP tools was previously invisible to the budget.
  • estimateMessages now counts ReasoningContent, which is echoed back to reasoning models and is often the largest content in a turn.
  • trimToSurvival kept only the last user message despite its doc comment; it now also keeps the original task in multi-turn sessions, preserves the compaction digest, and no longer appends a zero-value message when no user message exists.

Trimming robustness

  • Post-injection budget re-check: memory/skill/episode blocks are injected after the top-of-loop trim and could push an already-near-budget request over the limit on that very call; the budget is now re-checked immediately before client.Call.
  • Graduated trimming: old tool results >2 KiB (except the 4 most recent) are replaced with a [tool output trimmed: N bytes...] marker before any turn group is dropped — preserving the assistant's reasoning and the fact the tool ran.
  • Trim warning moved before the most recent user message (keeps the Anthropic cache-stable head intact, removes the memMsgIdx resync hack), is updated in place with cumulative totals, and names up to 5 dropped tools. New headLen protects system prompt + memory block + digest + original task.
  • Disk-cap session trimming persists a [Session storage limit: ...] marker into the transcript so a resumed session knows earlier history was removed (previously only a stderr warning).

New features

  • Self-calibrating safety margin: when provider-reported input tokens exceed the local estimate by >15%, the margin tightens 0.75 → 0.65 for the engine's lifetime (margin_calibrated signal).
  • Rolling compaction (compaction config / ODEK_COMPACTION / --compaction, default off): turn groups dropped by trimming are summarized by the model into a rolling [Compacted earlier context: ...] digest message — untrusted-wrapped, updated in place, protected from future trims. Summarizer failure never breaks trimming. Plumbed through odek.Config, internal/config, and all CLI entry points (run/repl/serve/schedule), mirroring prompt_caching; settable from project-level odek.json under the same rules as prompt_caching.

Tests

  • 22 new tests in internal/loop/loop_trim_test.go; updated trim/session tests; new config tests (TestGlobalOverlay_Compaction, TestEnvVar_Compaction, TestCLIFlags_Compaction).
  • All introduced/changed functions in internal/loop, internal/session, internal/config are at 100% function coverage (remaining uncovered blocks in those files are pre-existing unreachable-by-design error returns documented in the test files).
  • go test ./... -count=1 ✅ · go test -race ./internal/loop/ ./internal/session/ ./internal/config/ ✅ · golangci-lint run ./... — 0 issues ✅ · ODEK_E2E=true go test ./cmd/odek/ -run TestE2E_

Docs updated: AGENTS.md, docs/CONFIG.md, docs/CLI.md.

…ompaction

Reworks context-window management in the agent loop:

Correctness fixes:
- estimateToolDefs now counts JSON parameter schemas (the bulk of every
  tool definition) instead of ignoring them
- estimateMessages now counts ReasoningContent (echoed back to reasoning
  models, often the largest content in a turn)
- trimToSurvival keeps the original task in multi-turn sessions, preserves
  the compaction digest, and no longer appends a zero-value message when
  no user message exists

Trimming robustness:
- budget re-checked after memory/skill/episode injections, right before
  the LLM call — injected blocks no longer escape the budget for a full
  iteration
- graduated trimming: old tool results >2 KiB (except the 4 most recent)
  are replaced with a marker before any turn group is dropped
- trim warning moved before the most recent user message (cache-stable
  head preserved), updated in place with cumulative totals, and names up
  to 5 dropped tools; new headLen protects system prompt + memory block +
  digest + original task
- disk-cap session trimming persists a [Session storage limit: ...] marker
  into the transcript so resumed sessions know history was removed

New features:
- self-calibrating safety margin: tightens 0.75 -> 0.65 when provider-
  reported input tokens exceed the local estimate by >15%
  (margin_calibrated signal)
- optional rolling compaction (compaction / ODEK_COMPACTION /
  --compaction, default off): dropped turn groups are summarized by the
  model into a rolling, untrusted-wrapped digest message instead of being
  lost; summarizer failures never break trimming

All new/changed loop, session, and config code is at 100% function
coverage. Full unit suite, race detector, golangci-lint, and CLI E2E
tests pass.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 25, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
odek 9655091 Commit Preview URL

Branch Preview URL
Jul 25 2026, 09:40 PM

@jkyberneees
jkyberneees merged commit 641a5b3 into main Jul 25, 2026
8 checks passed
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