Skip to content

fix(agent-runtime): calibrate the context estimate against what requests cost - #748

Closed
zhangqingkun976 wants to merge 1 commit into
vastsa:mainfrom
zhangqingkun976:fix/context-estimate-calibration-r2
Closed

zhangqingkun976 wants to merge 1 commit into
vastsa:mainfrom
zhangqingkun976:fix/context-estimate-calibration-r2

Conversation

@zhangqingkun976

Copy link
Copy Markdown
Contributor

This reopens #683 with the four points from your review addressed. Thank you for the specific diagnosis — the asymmetry of the lower clamp and the fixed offset were both real defects in the first version.

1. Anomalous usage is handled conservatively

The correction is asymmetric now, because this number gates compaction:

direction when it applies bound
upward as soon as three observations exist up to CONTEXT_CALIBRATION_FACTOR_MAX (6×)
downward only after CONTEXT_CALIBRATION_DOWNWARD_CONSECUTIVE (3) agreeing samples ≤ CONTEXT_CALIBRATION_DOWNWARD_STEP_MAX (15 %) per step, and never below CONTEXT_CALIBRATION_FACTOR_MIN (0.85) of the raw estimate

Consequences that are now asserted in tests rather than argued: a projection at CONTEXT_CALIBRATION_BOUNDARY_GUARD_RATIO (1 / 0.85 ≈ 1.18×) of the hard limit still compacts, and how far a correction may defer the boundary is bounded by 1 − FACTOR_MIN. A report outside 0.5×–3× of what the calibration predicted is treated as a misreport: it moves the value in neither direction and is counted, and CONTEXT_CALIBRATION_ANOMALY_FREEZE (2) consecutive ones freeze the downward direction until a usable report arrives.

2. Ratio and fixed offset are separate quantities

  • The per-character bias is a ratio over the guessed tail — scale-free by construction, so the same correction applies at 2k or 200k tokens.
  • An unanchored residual is split. The ratio form is used only for observations taken at a comparable scale (CONTEXT_CALIBRATION_SCALE_BAND_*, 0.5×–2× of the estimate being corrected). Out of band, only the fixed part is added — the observed overhead, capped at CONTEXT_CALIBRATION_OVERHEAD_CAP (32,000 tokens) so it stays an overhead.
  • A 100k-scale sample therefore cannot be applied as a ratio to a 1M projection, and once the 1M scale has been observed the correction becomes proportional instead of staying at the small session's fixed offset.

3. Regression coverage

packages/agent-runtime/src/context-calibration.test.ts (13 cases) covers the four areas you named:

  • Under-reporting — a full window of low reports cannot carry the value below the floor; no downward move happens before agreeing samples; upward applies immediately; two consecutive misreports freeze the direction and a usable report unfreezes it.
  • Different context scales — ratio in band, capped overhead out of band, and the correction becoming proportional after observing the large scale.
  • Real CJK text — a real Chinese paragraph: the corrected tail matches the measured cost within ±5 % and the ratio lands inside the documented 2–4 band.
  • Compaction boundary — the guard ratio still compacts; the deferral is bounded by 1 − FACTOR_MIN; a wild report moves nothing.

4. Rebase and validation

Rebased onto main (79cd7ae8). The only conflict was the budget-formula extraction (#733): contextBudgetFor now owns the body, and the calibration is applied on top of that budget.

Local, on this branch: pnpm --filter @pi-desktop/agent-runtime build 0; pnpm --filter @pi-desktop/agent-runtime test 47/48 files — the single failure is the pre-existing native-pi-session case that fails identically on pristine main; node scripts/check-architecture.mjs passed; pnpm lint clean; pnpm docs:check (78 EN/zh pairs, 495 pages) exit 0.

E2E gate: NOT RUN. The scenario is written (E2E-CONTEXT-estimate-calibration-stays-safe) but no desktop E2E suite was executed: it needs a scripted-usage provider fixture that does not exist yet. Alternative validation: the module is pure arithmetic and fully unit-covered, including the CJK and boundary cases. Remaining risk: the calibrated number as it appears in the live occupancy ring has not been observed against a real provider's usage reports.

Specification and decisions

…sts cost

Reopens vastsa#683 with the four points from the review addressed.

1. Conservative handling of anomalous usage. The correction is asymmetric now:
   upward applies once three observations exist, while downward needs
   `CONTEXT_CALIBRATION_DOWNWARD_CONSECUTIVE` agreeing samples, is capped at
   `CONTEXT_CALIBRATION_DOWNWARD_STEP_MAX` per step, and can never take the
   value below `CONTEXT_CALIBRATION_FACTOR_MIN` (0.85) of the raw estimate. A
   projection at `CONTEXT_CALIBRATION_BOUNDARY_GUARD_RATIO` (1.18x) of the hard
   limit therefore still compacts. A report outside 0.5x-3x of what the
   calibration predicted is a misreport: it is discarded and moves nothing, and
   two consecutive ones (`CONTEXT_CALIBRATION_ANOMALY_FREEZE`) freeze the
   downward direction until a usable report arrives.

2. Ratio and fixed offset are separated. The per-character bias stays a
   scale-free ratio over the guessed tail. An unanchored residual is applied as
   a ratio only for observations at a comparable scale
   (`CONTEXT_CALIBRATION_SCALE_BAND_*`, 0.5x-2x of the estimate); otherwise only
   the observed overhead is added, capped by `CONTEXT_CALIBRATION_OVERHEAD_CAP`.
   A 100k-scale sample can no longer be applied as a ratio to a 1M projection,
   and once the large scale is observed the correction becomes proportional
   instead of staying at the small-scale offset.

3. Regression coverage for the four areas the review named: consecutive
   under-reporting (the floor holds; a downward move needs agreeing samples),
   different context scales (ratio in band, capped overhead out of band,
   proportional once observed), real CJK text (the tail is corrected to the
   measured cost, ratio inside the documented 2-4 band), and the compaction
   boundary (the guard ratio still compacts; the deferral is bounded).

4. Rebased onto current main (79cd7ae) with `contextBudgetFor` from the budget
   formula extraction (vastsa#733), and the full agent-runtime suite re-run.

C:\Users\10470\.pi-desktop\scratch\cb9e2d41-8a55-4a18-899d-92ca2791ab51\commit-683-r.txt
@zhangqingkun976
zhangqingkun976 force-pushed the fix/context-estimate-calibration-r2 branch from 42f8dba to fc6a5d7 Compare September 21, 2026 04:48
@vastsa

vastsa commented Sep 21, 2026

Copy link
Copy Markdown
Owner

I verified that the calibration problem is real, but this follow-up still violates its safety invariant. recordResidual counts an anomalous sample and can freeze calibration, while recordUnanchored and recordAnchored still append that same sample to the calibration window.

A direct repro in this PR worktree records two 4x anomalous samples, then one valid sample. The calibration unfreezes, but the stored anomaly makes correct(...) return 4,000,000 for a 1,000,000-token estimate (ratio 4). Thus a sample described as discarded still affects correction after recovery, and the tests do not cover this path.

This is not a root-safe fix. I am closing this PR; the already-closed #683 is not being reopened.

@vastsa vastsa closed this Sep 21, 2026
@zhangqingkun976

Copy link
Copy Markdown
Contributor Author

Rebased onto main (ab39a9b4) so the new Head contains latest base gate passes. Head is now fc6a5d73.

The only conflicts were append-vs-append — the E2E scenario catalog and the decisions log, where main and this branch each added an entry — and both sides are kept. The identifier bands are still free: upstream's newest ADR is 0299 and its newest decisions-log entry is D607 (the plugin crash report, which is this repository's own fix for issue #747 built on my #756).

@zhangqingkun976

Copy link
Copy Markdown
Contributor Author

Closed by accident and GitHub will not reopen it: an API-side ref update to rebase the branch reads as a force-push, and reopening is blocked for such a branch. The same content continues in #779.

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.

2 participants