Skip to content

feat(compaction): layered pressure architecture + reserve-aware budget alignment#558

Open
100yenadmin wants to merge 1 commit intoMartian-Engineering:mainfrom
electricsheephq:feat/sweep-target-and-reserve-aware-budget
Open

feat(compaction): layered pressure architecture + reserve-aware budget alignment#558
100yenadmin wants to merge 1 commit intoMartian-Engineering:mainfrom
electricsheephq:feat/sweep-target-and-reserve-aware-budget

Conversation

@100yenadmin
Copy link
Copy Markdown
Contributor

@100yenadmin 100yenadmin commented May 3, 2026

Summary

This PR ships a layered four-band compaction pressure architecture, plus reserve-aware budget alignment so percentages mean what they say.

        effective prompt budget = tokenBudget − reserveTokens
        ┌────────────────────────────────────────────────────────────┐
0%   60%/trigger  70%/tier-1  80%/tier-2  91%/sweep        100%/overflow
├─────┼───────────┼───────────┼───────────┼───────────────────────────┤
│ low │  normal   │  tier-1   │  tier-2   │   SWEEP                   │
│     │  1 pass / │  2 passes │  3 passes │   (unlimited passes,      │
│     │  dispatch │  / disp.  │  / disp.  │    target 50%)            │
│     │  exit @60%│  exit @60%│  exit @60%│   exit @ 50% of budget    │
└─────┴───────────┴───────────┴───────────┴───────────────────────────┘

What changed

Three new capabilities + one new behavior change:

  1. sweepTriggerThreshold (default 0.91) — separate from contextThreshold, controls when dispatched compaction switches into deep SWEEP mode. Below this, dispatched work targets contextThreshold (gentle). At/above, runs unlimited passes targeting sweepTargetThreshold.

  2. pressureTiers (default [{ratio:0.70,maxPasses:2},{ratio:0.80,maxPasses:3}]) — pressure-tiered pass cap ladder. Multi-pass amortizes prefix-cache invalidation: every pass in a single dispatch invalidates the SAME cache prefix, so 3 passes/dispatch cost the same cache-wise as 1 but reduce 3× as many tokens.

  3. sweepTargetThreshold (default 0.50) — fraction of token budget that SWEEP targets when it fires. Decouples sweep stopping point from contextThreshold. With sweep target 0.50 and trigger 0.91, when sweep fires it creates ~40% headroom (~5+ turns of runway).

  4. Reserve-aware budget alignment — LCM reads runtimeContext.reserveTokens (or legacy reserveTokensFloor) and subtracts it from the resolved tokenBudget before computing percentages.

Behavior change: contextThreshold default lowered from 0.750.60. The lower trigger gives the cache-aware deferral system more room to operate and feeds the new pressure-tier ladder cleanly.

Why this layering — the cache invalidation insight

When LCM compacts the oldest chunk, the prefix cache breaks at the modification point and everything from there to the end of the prompt must re-tokenize on the next turn. Doing 1 pass vs 3 passes vs 6 passes invalidates the SAME prefix — more passes just produce more reduction off that one cache break.

Tier Passes Cache cost Reduction Efficiency
Normal (1 pass) 1 ~17K 17K / cache-break
Tier 1 (2 passes) 2 ~34K 34K / cache-break ← 2×
Tier 2 (3 passes) 3 ~51K 51K / cache-break ← 3×
Sweep (unlimited) 5–7 ~80–100K huge / cache-break

Multi-pass per dispatch is the right shape at higher pressure, not "fire more often" (which would multiply cache invalidations).

Code surface

File Change
src/db/config.ts New fields: sweepTriggerThreshold, pressureTiers (with sorted-ascending validator). Lowered contextThreshold default 0.75 → 0.60.
src/compaction.ts compactFullSweep accepts new maxPasses cap (shared across leaf+condensed phases).
src/engine.ts New resolvePressureDispatchPolicy helper picks targetRatio + maxPasses from current pressure. Wired into executeCompactionCore sweep path. Reserve-aware applyReserveTokens helper subtracts reserve from resolved budget.
openclaw.plugin.json New uiHints + configSchema entries for sweepTriggerThreshold and pressureTiers.
README.md New "Compaction pressure architecture" section with layered ASCII diagram, pressure-band table, cache-invalidation efficiency math, scenario walkthrough.
test/sweep-target-and-reserve-aware-budget.test.ts 26 cases covering config resolution, budget alignment, and resolvePressureDispatchPolicy tier ladder (including boundary cases at exactly tier-1 / tier-2 / sweep ratios).

Backward compatibility

All additions default to gracefully extended behavior:

  • If pressureTiers is unset/empty/malformed: defaults to the canonical ladder (no behavior break)
  • If sweepTriggerThreshold is unset: defaults to 0.91 (so the deep sweep target only fires at high pressure, not on every threshold-mode dispatch)
  • If runtimeContext.reserveTokens is not present: LCM uses raw budget unchanged (legacy plugins/runtimes)
  • contextThreshold default change is the one operator-visible behavior shift — operators wanting legacy 0.75 set it explicitly

The resolvePressureDispatchPolicy falls back to sweep semantics (target = 0.50, no pass cap) when current token count is unavailable, preserving the prior version of this PR's behavior for any caller that doesn't supply a pressure signal.

Recommended companion: PR #557

PR #557's criticalBudgetPressureRatio default 0.70 lines up exactly with this PR's tier-1 ratio. Without #557, tier-1 dispatches at 70% would still be cache-throttled up to 5 minutes per dispatch, defeating the whole point of having tiers. With #557, dispatched work fires reliably the moment the system enters tier-1.

Test plan

  • pnpm exec vitest run846 tests passing (820 baseline + 26 new)
  • pnpm build — clean
  • New tests cover the full pressure-tier matrix including boundary cases
  • Updated test/config.test.ts defaults assertions to match the new architecture

Scenario walkthrough — real session data

Real Eva session on gpt-5.5 (258K context, 20K reserve = 238K effective budget) before any patches: 6 emergency truncations / 18hrs.

After both this PR + PR #557 with default config:

Eva crosses... Tier Pass count Action
143K (60% of 238K) Normal 1 Maintenance debt queued, fires when cache cold
167K (70% of 238K) Tier 1 2 Cache delay BYPASSED (PR #557), 2 passes per dispatch
190K (80% of 238K) Tier 2 3 3 passes per dispatch
If tier 1+2 fail, crosses 217K (91%) Sweep unlimited Deep catch-up to 119K

Result: 0 emergency truncations instead of 6 in the same window.

Copilot AI review requested due to automatic review settings May 3, 2026 10:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the compaction system to (1) decouple the “sweep stop point” from the existing compaction trigger threshold, and (2) align all threshold percentages to an effective prompt budget by subtracting any runtime-provided reserve token buffer.

Changes:

  • Add sweepTargetThreshold config (default 0.50) and plumb it through the engine into sweep compaction so sweeps can create multi-turn headroom.
  • Make resolveTokenBudget reserve-aware by subtracting runtimeContext.reserveTokens (or legacy reserveTokensFloor) from the resolved budget.
  • Add/adjust tests, plugin schema/manifest text, README documentation, and a changeset entry.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/compaction.ts Adds optional targetRatio to full sweeps and uses it for sweep loop stopping conditions.
src/engine.ts Applies reserve token subtraction during token budget resolution; passes sweepTargetThreshold to sweep calls.
src/db/config.ts Introduces sweepTargetThreshold on LcmConfig with env override and clamping.
openclaw.plugin.json Adds schema + UI hints for sweepTargetThreshold and clarifies contextThreshold help text.
test/sweep-target-and-reserve-aware-budget.test.ts New tests covering sweepTargetThreshold resolution and reserve-aware budget behavior.
test/config.test.ts Asserts the new default config value.
README.md Documents compaction pressure “bands”, sweep target decoupling, and reserve-aware budgeting.
.changeset/sweep-target-and-reserve-aware-budget.md Patch changeset describing the new behaviors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/compaction.ts Outdated
Comment thread test/sweep-target-and-reserve-aware-budget.test.ts
Comment thread README.md Outdated
Comment thread src/engine.ts Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/sweep-target-and-reserve-aware-budget.test.ts
Comment thread test/sweep-target-and-reserve-aware-budget.test.ts
Comment thread src/compaction.ts
Comment thread src/engine.ts Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread .changeset/sweep-target-and-reserve-aware-budget.md Outdated
@100yenadmin 100yenadmin requested a review from Copilot May 3, 2026 10:34
@100yenadmin 100yenadmin force-pushed the feat/sweep-target-and-reserve-aware-budget branch 2 times, most recently from c34206a to a57779a Compare May 3, 2026 10:37
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/compaction.ts
Comment thread test/sweep-target-and-reserve-aware-budget.test.ts
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md
Comment thread .changeset/sweep-target-and-reserve-aware-budget.md Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/engine.ts
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
@100yenadmin 100yenadmin force-pushed the feat/sweep-target-and-reserve-aware-budget branch from a57779a to 5c6c30c Compare May 3, 2026 11:29
@100yenadmin 100yenadmin changed the title feat(compaction): decouple sweep target + reserve-aware budget alignment feat(compaction): layered pressure architecture + reserve-aware budget alignment May 3, 2026
@100yenadmin
Copy link
Copy Markdown
Contributor Author

100yenadmin commented May 3, 2026

Reworked this PR significantly after design feedback and running test scenarios on 5.5 and 5.4 agents.

The new version (5c6c30c) ships the full layered four-band architecture that balances quality, latency, and preventing overflows in high tool and normal use claw setups:

  • Trigger at 60% (lowered from 0.75): normal compaction, 1 pass/dispatch, exits at trigger
  • Tier 1 at 70%: 2 passes/dispatch, exits at trigger
  • Tier 2 at 80%: 3 passes/dispatch, exits at trigger
  • Sweep at 91%: NEW separate sweepTriggerThreshold knob — deep sweep to 50%, unlimited passes, ONLY at this pressure

The cache-invalidation insight: each dispatch's prefix-cache cost is FIXED regardless of pass count (all passes invalidate the same prefix from oldest-modification-point forward). So 3 passes/dispatch costs the same cache-wise as 1 but reduces 3× as many tokens. That's why higher pressure → more passes per dispatch is the right shape.

Companion to PR #557 — that PR's criticalBudgetPressureRatio was lowered from 0.85 → 0.70 to align with this PR's tier-1 ratio. Without that, tier-1 dispatches at 70% would still be cache-throttled. The issue most users hate is sweep mode taking 60-120 seconds. By handling the system pressure much earlier with additional passes allowed, sweep mode should never happen unless a blow out (load a massive log file or OC breaks).

PR description rewritten to reflect the new architecture. README's compaction-pressure-architecture section rewritten with the layered diagram + cache efficiency table + scenario walkthrough. Tests: 846 passing (26 new covering the full pressure-tier matrix incl. boundary cases). Force-pushed; will reply individually to any new review comments.

This PR also counts as overall system wide "overflow" adoption of new overflow logic from OpenClaw which sets default overflow of 20k token reserve for output tokens.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/compaction.ts
Comment thread openclaw.plugin.json Outdated
@100yenadmin 100yenadmin force-pushed the feat/sweep-target-and-reserve-aware-budget branch 2 times, most recently from fa3f425 to e7edf81 Compare May 3, 2026 11:57
@100yenadmin
Copy link
Copy Markdown
Contributor Author

Spawned 4 hardcore adversarial bug-hunters in parallel to find any remaining bugs. They returned 30+ findings; addressed everything that was real (filtered ~12 stale + uncertain). New commit e7edf81 has 7 fixes:

P0:

  • maintain() reserve-bypass fixedruntimeTokenBudget now goes through applyReserveTokens BEFORE being passed to consumeDeferredCompactionDebt. Previously, when recordedTokenBudget was null (fresh maintenance row), the raw budget propagated through executeCompactionCore's alreadyReserveAdjusted: true flag and silently bypassed reserve subtraction — defeating the PR's reserve-alignment goal on the most common drain path. assemble() path requires runtimeContext on its signature, which it doesn't have today — flagged as known limitation.
  • Made sweepTriggerThreshold and pressureTiers optional on LcmConfig — required fields would have caused TS compile breakage for downstream callers constructing LcmConfig literals. Runtime defaults to 0.91/0.50/canonical-tier-ladder when absent.

P1:

  • resolvePressureDispatchPolicy safe defaults — when currentTokenCount is unknown, falls back to GENTLEST policy (1 pass, target=contextThreshold) instead of aggressive sweep mode. The old fallback would silently jump to multi-pass deep sweeps when a caller didn't supply pressure data.
  • applyReserveTokens budget=1 fix — when reserve >= rawBudget (misconfig), now logs a warn and returns rawBudget instead of silently producing budget=1 (which propagated 0-target pathological loops through compactFullSweep).
  • Schema/resolver bound mismatchpressureTiers[].ratio schema uses exclusiveMinimum/exclusiveMaximum to match resolver's strict (0, 1) bounds. Also added required: ["ratio", "maxPasses"] so silent config drops don't happen.
  • resolvePressureDispatchPolicy defensive sort + per-tier validation — guards against unsorted/malformed tiers if a caller mutates config or constructs literally.
  • Defensive defaults for missing config fields in resolvePressureDispatchPolicy — uses DEFAULT_PRESSURE_TIERS/DEFAULT_SWEEP_TARGET_THRESHOLD/DEFAULT_SWEEP_TRIGGER_THRESHOLD constants instead of crashing on missing.

P2:

  • contextThreshold clamp [0,1] — symmetric with the new fields. Prevents operator setting 2.5 and breaking trigger logic.

Process:

  • Bumped changeset patchminor per adversarial finding (contextThreshold default 0.75→0.60 is operator-visible).
  • 2 regression tests updated to match new (correct) safe-default behavior.
  • 848 tests passing.

Force-pushed (fa3f425e7edf81).

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/engine.ts Outdated
Comment thread src/engine.ts Outdated
Comment thread src/engine.ts Outdated
@100yenadmin 100yenadmin force-pushed the feat/sweep-target-and-reserve-aware-budget branch 3 times, most recently from 037579a to 4a5955f Compare May 3, 2026 12:23
@100yenadmin
Copy link
Copy Markdown
Contributor Author

Round 3 adversarial sweep complete — applied 4 of 6 findings (commit 4a5955f):

Verified ✓ (all 12 round-2 fixes applied correctly): maintain reserve-bypass, assemble reserve-bypass, optional fields, safe defaults, applyReserveTokens warn, schema bounds, contextThreshold clamp, changeset minor, defensive sort, log.warn assertion, Math.floor test, README example. All confirmed by adversarial agent.

Round 3 fixes applied:

  1. afterTurn() default-budget fallback bypassed reserve subtraction (HIGH/LOW) — when neither params.tokenBudget nor runtimeContext.tokenBudget was supplied, the literal 128_000 fallback skipped applyReserveTokens. Same pattern as maintain() but afterTurn() didn't have the fix. Now applied.
  2. assemble() doesn't propagate runtimeContext to drain helper (MEDIUM/LOW) — added param-passing through maybeConsumeDeferredCompactionDebtForAssemble so downstream executeCompactionCore can consume provider/model/manualCompaction fields rather than falling back to telemetry-only legacy params.
  3. compact() public entry: adjustedBudget ?? params.tokenBudget fallback was dead but unsafe (LOW/LOW) — dropped the fallback. If adjustedBudget is undefined, executeCompactionCore now returns "missing token budget" error instead of silently slipping RAW value through with alreadyReserveAdjusted: true (which would bypass reserve). Made tokenBudget? optional in CompactionExecutionParams.
  4. pressureTiers: [] engine path untested (MEDIUM/LOW) — added regression test for engine-side empty-array fallback to default ladder.

Plus inline bot review fixes from previous push:

  • Centralized DEFAULT_PRESSURE_TIERS/DEFAULT_SWEEP_TARGET_THRESHOLD/DEFAULT_SWEEP_TRIGGER_THRESHOLD/DEFAULT_CONTEXT_THRESHOLD exports in src/db/config.ts — single source of truth, no more engine-side mirroring.
  • applyReserveTokens warn message references both reserveTokens and reserveTokensFloor keys.
  • Empty pressureTiers: [] array now correctly falls back to canonical defaults at the engine level (was treating as valid → silent 1-pass-everywhere).

Skipped (deliberate):

  • Misleading legacyParams: asRecord(params.runtimeContext) duplicate in maintain() (LOW/LOW) — works correctly, removing might cause regression if executeCompactionCore's runtimeContext ?? legacyParams precedence ever changes.

850 tests passing (15+ new across rounds 2 and 3). CI green.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/engine.ts:6211

  • In the afterTurn fallback path, fallbackBudget may be reserve-adjusted (e.g., 128k default minus runtimeContext.reserveTokens), but the warning log still says it is using the raw default 128000. This makes logs inaccurate when reserve alignment is active. Consider logging the effective budget actually used (or include both raw and adjusted values) so operators can reconcile thresholds/pressure with observed behavior.
    // When neither params.tokenBudget nor runtimeContext.tokenBudget is
    // supplied, resolveTokenBudget returns undefined and we fall back to the
    // default. Apply reserve adjustment to the fallback too so percentages
    // compute against the EFFECTIVE budget — matches the maintain() pattern
    // and prevents reserve-aware alignment from being silently bypassed when
    // a host calls afterTurn with reserveTokens but no tokenBudget.
    const fallbackBudget = this.applyReserveTokens(
      DEFAULT_AFTER_TURN_TOKEN_BUDGET,
      asRecord(params.runtimeContext) ?? {},
    );
    const tokenBudget = this.applyAssemblyBudgetCap(resolvedTokenBudget ?? fallbackBudget);
    if (resolvedTokenBudget === undefined) {
      this.deps.log.warn(
        `[lcm] afterTurn: tokenBudget not provided; using default ${DEFAULT_AFTER_TURN_TOKEN_BUDGET}`,
      );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md Outdated
Comment thread README.md Outdated
…t alignment

Layered four-band compaction pressure architecture:

  effective prompt budget = tokenBudget − reserveTokens
  ┌────────────────────────────────────────────────────────────┐
  0%   60%/trigger  70%/tier-1  80%/tier-2  91%/sweep   100%/overflow
  ├────┼───────────┼───────────┼───────────┼───────────────────┤
  │ low│ normal    │ tier-1    │ tier-2    │ SWEEP             │
  │    │ 1 pass/   │ 2 passes/ │ 3 passes/ │ unlimited passes  │
  │    │ dispatch  │ dispatch  │ dispatch  │ target 50%        │
  │    │ exit @60% │ exit @60% │ exit @60% │ exit @ 50% budget │
  └────┴───────────┴───────────┴───────────┴───────────────────┘

Three new capabilities:

1. `sweepTriggerThreshold` (default 0.91) — separate from contextThreshold,
   controls when dispatched compaction switches into deep SWEEP mode. Below
   this, dispatched compaction targets contextThreshold (gentle, doesn't
   overshoot). At/above, runs unlimited passes targeting sweepTargetThreshold.

2. `pressureTiers` (default [{ratio:0.70,maxPasses:2},{ratio:0.80,maxPasses:3}])
   — pressure-tiered pass cap ladder for dispatched compaction below sweep
   mode. Multi-pass amortizes prefix-cache invalidation: every pass in a
   single dispatch invalidates the SAME cache prefix, so 3 passes/dispatch
   cost the same cache-wise as 1 but reduce 3× as many tokens. That's why
   higher pressure → more passes per dispatch is the right shape rather
   than "fire more often" (which would multiply cache invalidations).

3. `sweepTargetThreshold` (default 0.50) — fraction of token budget that
   SWEEP targets when it fires. Decouples sweep stopping point from
   contextThreshold. With default sweep target 0.50 and trigger 0.91, when
   sweep fires it creates ~40% headroom (~5+ turns of runway).

Reserve-aware budget alignment:
LCM now reads runtimeContext.reserveTokens (or the legacy reserveTokensFloor
key) and subtracts it from the resolved tokenBudget before computing
percentages. Every threshold computes against the EFFECTIVE prompt budget —
the same number the runtime actually overflows at — instead of the raw
context window. Plugins/runtimes that don't pass a reserve get legacy
behavior unchanged.

Behavior change: `contextThreshold` default lowered from 0.75 → 0.60. The
lower trigger gives the cache-aware deferral system more room to operate
(defer when cache hot, fire when cold) and feeds the new pressure-tier
ladder cleanly. Operators wanting the legacy 0.75 trigger can set it
explicitly.

New env overrides: LCM_SWEEP_TARGET_THRESHOLD, LCM_SWEEP_TRIGGER_THRESHOLD,
LCM_PRESSURE_TIERS (JSON array). New manifest entries + uiHints + configSchema
for all three new fields.

Tests: 846 passing (820 baseline + 26 new in
test/sweep-target-and-reserve-aware-budget.test.ts covering config resolution,
budget alignment, and the resolvePressureDispatchPolicy tier ladder).

README: new "Compaction pressure architecture" section with layered ASCII
diagram, pressure-band table, cache-invalidation efficiency math, and
scenario walkthrough showing 6 emergency truncations → 0.

Recommended companion: PR Martian-Engineering#557. PR Martian-Engineering#557's criticalBudgetPressureRatio
default 0.70 lines up with this PR's tier-1 ratio so dispatched work fires
reliably the moment the system enters tier-1 instead of being cache-throttled.
@100yenadmin 100yenadmin force-pushed the feat/sweep-target-and-reserve-aware-budget branch from 4a5955f to e86c96b Compare May 3, 2026 13:08
@100yenadmin 100yenadmin requested a review from Copilot May 3, 2026 17:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/engine.ts:6211

  • In afterTurn, when tokenBudget is missing you log that you’re using the default 128000, but fallbackBudget may have been reserve-adjusted via applyReserveTokens(...). This can make logs misleading for operators (they’ll see 128k even if an effective smaller budget was actually used). Log the effective fallback/token budget being applied (and optionally the reserve) instead of the raw default constant.
    const tokenBudget = this.applyAssemblyBudgetCap(resolvedTokenBudget ?? fallbackBudget);
    if (resolvedTokenBudget === undefined) {
      this.deps.log.warn(
        `[lcm] afterTurn: tokenBudget not provided; using default ${DEFAULT_AFTER_TURN_TOKEN_BUDGET}`,
      );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/engine.ts
// documented "empty/malformed → defaults" semantics in the resolver.
const tiers =
Array.isArray(this.config.pressureTiers) && this.config.pressureTiers.length > 0
? [...this.config.pressureTiers].sort((a, b) => a.ratio - b.ratio)
Comment thread src/compaction.ts
Comment on lines +639 to +644
* the sweep loop continues until `currentTokens <= targetRatio * tokenBudget`,
* decoupling the sweep stopping point from `contextThreshold`. When omitted,
* the legacy behavior applies (sweep exits at `contextThreshold`).
*
* The trigger condition is still evaluated against `contextThreshold` —
* `targetRatio` only affects when the loop STOPS, not whether it starts.
Comment thread src/compaction.ts
Comment on lines +669 to +675
const targetThreshold =
typeof input.targetRatio === "number"
&& Number.isFinite(input.targetRatio)
&& input.targetRatio >= 0
&& input.targetRatio <= 1
? Math.min(triggerThreshold, Math.floor(input.targetRatio * tokenBudget))
: triggerThreshold;
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.

3 participants