mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-21 17:44:11 +00:00
🛡️ fix: make context projection strictly additive (no-regression)
Revert the G1 window-match guard on the live/branch snapshot. When no explicit maxContextTokens is set (the common default), the SDK's snapshot window is reserve-derived (~0.9·(modelContext − maxOutputTokens)) while useTokenLimits resolves the raw model context — so `snapshot.maxContextTokens === resolvedMax` is false for the SAME model, and the guard would wrongly drop a valid current-branch snapshot to projection/estimate post-stream (a regression in the default case, per initialize.ts:1240-1243). The projection now activates ONLY for snapshot-less branches (G2): the precedence is live snapshot → persisted branch snapshot → projection → estimate, where the first two are byte-for-byte the prior behavior and the projection just slots ahead of the estimate. Window/model-switch (G1) detection needs the snapshot to carry its model/window and defers to the fidelity follow-up.
This commit is contained in:
parent
0639c5fd21
commit
536d2ca46f
1 changed files with 16 additions and 26 deletions
|
|
@ -102,18 +102,18 @@ export default function useTokenUsage({
|
|||
}, [conversationKey, branchTotals.tailId, snapshotsByAnchor]);
|
||||
|
||||
const resolvedMax = limits.maxContextTokens;
|
||||
/** A persisted snapshot is "fresh" only when its window matches the resolved
|
||||
* one — a model/window switch leaves its baked breakdown stale (G1). */
|
||||
const branchSnapshotFresh =
|
||||
branchSnapshot != null &&
|
||||
(resolvedMax == null || branchSnapshot.breakdown.maxContextTokens === resolvedMax);
|
||||
|
||||
/** Ask the server to project the branch (agents SDK, no model call) when no
|
||||
* fresh snapshot covers it — snapshot-less branches (G2) and post window/
|
||||
* model switch (G1). Cached + refetched by branch/endpoint/model/window. */
|
||||
/** Project the branch (agents SDK, no model call) ONLY when no persisted/live
|
||||
* snapshot covers it — snapshot-less branches (G2: pre-feature history,
|
||||
* imports, never-generated branches). A present snapshot stays authoritative;
|
||||
* reliable window-switch (G1) detection needs the snapshot to carry its
|
||||
* model/window (deferred to the fidelity follow-up), and the SDK window
|
||||
* (reserve-derived) doesn't equal the client-resolved raw window, so we must
|
||||
* NOT mis-flag a valid snapshot as stale here. Cached + refetched by branch/
|
||||
* endpoint/model/window/revision. */
|
||||
const projectionParams: TContextProjectionRequest | null =
|
||||
!isSubmitting &&
|
||||
!branchSnapshotFresh &&
|
||||
branchSnapshot == null &&
|
||||
conversation?.conversationId != null &&
|
||||
conversation.conversationId !== Constants.NEW_CONVO &&
|
||||
branchTotals.tailId != null &&
|
||||
|
|
@ -241,28 +241,20 @@ export default function useTokenUsage({
|
|||
* one branch's breakdown onto its siblings. */
|
||||
const currentActive =
|
||||
snapshot != null &&
|
||||
(isSubmitting ||
|
||||
(snapshot.anchorMessageId != null &&
|
||||
branchTotals.containsAnchor &&
|
||||
/** G1: once streaming ends, a model/window switch leaves the live
|
||||
* snapshot's baked window stale — defer to the projection instead of
|
||||
* showing the old window/prune boundary on the current branch. */
|
||||
(resolvedMax == null || snapshot.breakdown.maxContextTokens === resolvedMax)));
|
||||
(isSubmitting || (snapshot.anchorMessageId != null && branchTotals.containsAnchor));
|
||||
|
||||
/** Precedence: live/active snapshot → fresh persisted branch snapshot →
|
||||
* server projection (covers G1 stale-window + G2 snapshot-less branches) →
|
||||
* a window-stale persisted snapshot (still better than the coarse estimate)
|
||||
* → per-message estimate. Snapshot and projection share the render-relevant
|
||||
* fields, so they render uniformly. */
|
||||
/** Precedence: live/active snapshot → persisted branch snapshot → server
|
||||
* projection (snapshot-less branches, G2) → per-message estimate. The first
|
||||
* two preserve the pre-projection behavior exactly; the projection only
|
||||
* slots in ahead of the estimate when no snapshot exists. Snapshot and
|
||||
* projection share the render-relevant fields, so they render uniformly. */
|
||||
let effective: ContextSnapshot | TContextUsageEvent | null = null;
|
||||
if (currentActive) {
|
||||
effective = snapshot;
|
||||
} else if (branchSnapshotFresh) {
|
||||
} else if (branchSnapshot != null) {
|
||||
effective = branchSnapshot;
|
||||
} else if (projection != null) {
|
||||
effective = projection;
|
||||
} else if (branchSnapshot != null) {
|
||||
effective = branchSnapshot;
|
||||
}
|
||||
|
||||
if (effective != null) {
|
||||
|
|
@ -331,8 +323,6 @@ export default function useTokenUsage({
|
|||
liveTokens,
|
||||
limits,
|
||||
branchSnapshot,
|
||||
branchSnapshotFresh,
|
||||
projection,
|
||||
resolvedMax,
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue