Skip to content

[pull] main from danny-avila:main - #209

Merged
pull[bot] merged 4 commits into
innFactory:mainfrom
danny-avila:main
Sep 3, 2026
Merged

[pull] main from danny-avila:main#209
pull[bot] merged 4 commits into
innFactory:mainfrom
danny-avila:main

Conversation

@pull

@pull pull Bot commented Sep 3, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

danny-avila and others added 4 commits September 2, 2026 20:03
#497)

* 🧊 fix: Keep Historical Tool Result Truncation Byte-Stable Across Turns

Pre-flight truncation and observation masking recomputed every historical
tool result's character cap on every call from quantities that move from
turn to turn: the number of tool results (`0.2 + 0.8 * t / (n - 1)` recency
weighting and per-count budget shares), the calibration ratio
(`effectiveMaxTokens / calibrationRatio`) and the instruction overhead.
Once a conversation crossed the fading threshold — or, with summarization
enabled, from the first oversized result onward — the same stored tool
output was truncated to a slightly different length on nearly every
request. Anthropic's prompt cache is prefix-based, so each such change
invalidated the cached prefix for everything after it and forced a full
cache write per turn for the rest of the conversation's life.

- Derive every fading cap from the fixed context window scaled by the
  discrete pressure band (`resolveFadingBudgetTokens`), independent of
  calibration, instruction overhead and tool-result count
- Apply one flat cap per pre-flight pass instead of position weighting
- Mask consumed results to a fixed fraction of the fresh-result cap
  (`calculateMaskedResultMaxChars`) instead of count-weighted budget shares
- Cap fit-to-budget truncation (summarization on) at the window-derived
  ingestion cap rather than the calibrated effective budget
- Add stability tests covering position drift, count drift and calibration
  drift through `createPruneMessages`, within a run and across runs

Within a pressure band a historical tool result now maps to identical
bytes on every call; only band transitions (at most three per
conversation) and summarization rewrite the prefix.

Fixes danny-avila/LibreChat#15499

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* 🧊 refactor: Latch Context Fading on a Quantized Cap Ladder

Review of the first pass found the window-derived flat cap dropped the
fit guarantee: with summarization on, a tool result under the ingestion
cap but over the effective budget was no longer pre-truncated, so a small
window with large instruction overhead yielded an empty first context and
sent everything to the summarizer after one tool call. The fallback and
emergency paths also still derived caps from `effectiveMaxTokens`, and
band selection had no hysteresis, so pressure near a threshold flipped
bands between runs and rewrote every historical result each flip.

Replace the per-call cap derivations with one latched tier:

- Add `messages/fading.ts`: a pure cap ladder that halves the window per
  rung. `resolveFadingTier` deepens the rung to the shallowest one whose
  fresh-result cap fits half the effective budget (the fit guarantee),
  adds pressure-band rungs when summarization is off, and latches
  masking at 80 %. The tier only ever deepens, which is the hysteresis
- Derive every cap (`resolveFadingCaps`) from `(window, rung, masked)`
  alone, so a historical tool result maps to identical bytes on every
  call; only escalation rewrites the prefix
- Apply caps in one pass (`applyFadingCaps`) with watermarks, so an
  unchanged tier only visits messages that arrived since the last call;
  masking and pre-flight truncation become thin wrappers over it
- Drop fallback fading, subsumed by the fit rung, and make emergency
  truncation deepen the latched tier on the live messages instead of
  re-deriving count-proportional caps on a clone each call
- Thread `fadingTier` through `createPruneMessages`, `AgentContext`,
  `StandardGraph` and `Run` (`RunConfig.fadingTier`, `Run.getFadingTier()`)
  so hosts can persist it beside `calibrationRatio` and seed the next run;
  an invalid or foreign-window tier starts fresh
- Move `calculateMaxToolCallInputChars` next to its sibling in
  `utils/truncation.ts` and re-export it from `messages/prune`

Tests cover the ladder, band hysteresis, tier validation and seeding, the
fit guarantee on a 32k window with 21k of instructions, byte stability
across runs with and without a seeded tier, and within a run under
recalibration.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* 🧊 fix: Persist Fading Budget, Keep Emergency Truncation Transient

Address the second review pass on the latched fading tier:

- Persist an absolute `budgetTokens` instead of `(window, rung)`. A tier
  keyed by window was discarded by a mid-run budget correction and again
  on the next run's return to the normal window, rewriting the prefix
  twice; the budget is now only clamped to the current window and never
  grows, so both transitions keep the same bytes
- Make emergency truncation transient again. It derives a temporary
  deeper tier from a per-message share of the effective budget and
  applies it to a clone, restoring token counts afterwards; latching that
  count-dependent share pinned every future result to one transient event
- Reset `messagesToRefine` to the retry outcome after an emergency
  recovery, so messages in the recovered context are not also summarized
- Share `hasNonEmptyTextContent` from `messages/core` between the consumed
  boundary scan and the preempt gate instead of a second copy
- Update `docs/summarization-behavior.md` for the tier, the fit rung, the
  band rungs, the removed fallback stage and the transient emergency path

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* 🧊 fix: Expose Only Informative Fading Tiers to Hosts

`Run.getFadingTier()` returned the fresh tier too, so a host comparing it
against its own context window (which can differ from the pruner's after
the reserve ratio is applied) misclassified an untouched conversation as
faded and persisted a tier that would pin later runs to a smaller budget.
Decide it where the pruner's window is known: `Graph.getFadingTier()` now
returns the tier only once masking has activated or the budget sits below
`maxContextTokens`, via `isInformativeFadingTier`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* fix: Preserve fading state across agent boundaries

* fix: Rebuild fading inputs from canonical calls

* 🧊 test: Derive Emergency Caps From Canonical Stores, Cover Summarizer Snapshot

The emergency pass now reads the same canonical stores as the tier pass so
its clone derives from original bytes, and a test proves the summarizer
snapshot captures the true original when a fresh-capped result is masked
on a later call.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* fix: Bound canonical fading state

* fix: Clone fading tier snapshots

* fix: Preserve fading state across sessions

* fix: Bound fading state across histories

* refactor: project fading from canonical graph history

* fix: preserve projected fading state

* perf: keep projection sync append-only

* fix: invalidate rewritten provider projections

* fix: invalidate projections from reducer updates

* fix: preserve conservative counts on projection rebuild

* fix: honor result caps during fading selection

* fix: fit complete tool exchanges within fading budget

* fix: bound parallel fading and session restore

* fix: preserve fading across graph lifecycle edges

* fix: retain canonical replacements and failed-run tiers

* test: verify Anthropic fading across fresh runs

* perf: update tool width sources incrementally

* fix: close fading integration gaps

* fix: align fading boundary state

* fix: invalidate rewritten fading history

* fix: normalize reducer update typing

* fix: bound routing and preserve replay caches

* fix: respect scoped fading budgets

* fix: reset fading state with compacted history

* test: measure scoped routing budget

* fix: close fading reset lifecycle gaps

* fix: preserve routing and tier edge cases

* fix: reject stale fading captures

* 🧊 fix: Keep Re-seeded Fresh Tiers Fresh, Validate Restored Fading State

- `seedFadingTier` latches a seed only when it was tightened, masked, already
  latched, or clamped, so a fresh tier re-seeded through a pruner rebuild is
  never reported as informative and cannot pin later runs to the current
  window; a sub-floor budget clamps up to the ladder floor so every cap stays
  positive.
- Restored tiers are validated at every boundary (`Run`, `StandardGraph`, the
  `AgentSession` merge and its store restore), per-agent tiers are read as own
  properties so an agent ID such as `constructor` persists, and a
  `session_state` line carrying null data no longer breaks `JsonlSessionStore`.
- The provider projection's fallback rebuild discards the index-keyed
  original-content sidecar, so a shifted prefix cannot restore one tool's bytes
  onto another message before summarization.
- Emergency truncation derives its rung from the whole tool exchange, so a
  small configured result cap cannot satisfy the target while call inputs stay
  uncapped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* 🧊 fix: Bound Handoff Instructions, Isolate Fading Reset Generations

- Handoff instructions are bounded by the receiving agent's routing cap
  before they become a HumanMessage, through the same destination-derived
  budget that direct-edge routing prompts use, since fading can never shrink
  a human message later.
- `AgentSession` advances a rewrite epoch on branch, compact and restore, so
  a run that started before an explicit history rewrite cannot re-persist
  tiers learned on the pre-rewrite history when it completes.
- Reset generations are tracked per scope and per tier (the default tier and
  each agent), so one agent's compaction rejects only that agent's stale
  captures and a concurrent, valid escalation of another agent still lands.
- `hasNonEmptyTextContent` scans content blocks by index through own data
  descriptors and requires an array, so a hostile iterator or accessor-backed
  element can no longer abort pruning.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNbgMeR2aZDyhsqAy4L8gF

* 📝 docs: Describe the Fit Rung, Canonical History and Emergency Exchange

The fading section still described the fit rung as a single result fitting
half the effective budget and the emergency tier as a per-message result
share. The fit rung now sizes the widest observed parallel exchange (inputs
plus results) against the effective budget, the emergency tier is the rung
at which one complete exchange fits the per-message share, the tier shape
carries its version, and hosts read compaction resets through
`Run.didResetFadingTier()`. Also notes that graph history stays canonical
behind a per-Run provider projection and that restored tiers are validated
at every boundary.
* 🛡️ fix: Require Context Pressure for Numberless Overflow Recovery

* fix: narrow ambiguous overflow guard

* fix: carry completion pressure through fallbacks

* fix: bound blind recovery by output reserve

* fix: scope completion pressure to request semantics

* fix: centralize provider window semantics

* fix: prefer provider facts over ambiguous wrappers

* fix: preserve overflow recovery evidence across retries

* fix: keep overflow budgets provider scoped

* fix: keep overflow pressure in provider token space

* fix: reject ambiguous overflow recovery

* fix: reject ambiguous loose overflow matches
@pull pull Bot locked and limited conversation to collaborators Sep 3, 2026
@pull pull Bot added the ⤵️ pull label Sep 3, 2026
@pull
pull Bot merged commit 4649cef into innFactory:main Sep 3, 2026
2 checks passed
@pull
pull Bot deployed to publish September 3, 2026 04:44 Active
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants