Scope: follow-up to #4345 (auto-compaction three-tier ladder).
Several integers from upstream sources can be hostile (provider bug, OpenAI-compat proxy returning null/NaN, misconfigured override) and poison the gate arithmetic:
Failure modes
-
usageMetadata.{prompt,candidates,cached,total}TokenCount can be NaN / Infinity / negative on hostile providers. The streaming response handler captures these unguarded. Subsequent lastPromptTokenCount + NaN >= hard is always false → hard-rescue silently disabled; Infinity >= hard always true → hard-rescue fires every send.
-
computeThresholds(window) has no input validation. If contextWindowSize: NaN (proxy returning null), NaN - SUMMARY_RESERVE = NaN, all four thresholds become NaN, every tokens >= NaN is false → the entire three-tier ladder silently disables.
Both are catastrophic (silent compression disable) but require non-default provider misbehavior.
Proposed fix
1. Coerce helper for API usage fields
function coerceUsageCount(value: unknown): number {
return typeof value === 'number' && Number.isFinite(value) && value >= 0
? value
: 0;
}
Route all 4 API-capture sites in geminiChat.ts through it:
usageMetadata.promptTokenCount
usageMetadata.totalTokenCount
usageMetadata.candidatesTokenCount
usageMetadata.cachedContentTokenCount
Number.isFinite(-1) is true, so the >= 0 is also needed (not just isFinite).
2. computeThresholds input guard
export function computeThresholds(window: number): CompactionThresholds {
if (!Number.isFinite(window) || window <= 0) {
return {
warn: Number.POSITIVE_INFINITY,
auto: Number.POSITIVE_INFINITY,
hard: Number.POSITIVE_INFINITY,
effectiveWindow: 0,
};
}
// ... existing math
}
Returning Infinity (rather than 0) means tokens < Infinity always true → gate falls through to NOOP-equivalent path, instead of tokens < 0 always false latching at fired-state.
Related
Worked out in R11.1 + R12.1 + R12.2 of PR #4168 (archived at tag pr-4168-archive-pre-revert). Pure follow-up — both are defensive guards on edge-case inputs, no behavioral change for any provider returning sane values.
Scope: follow-up to #4345 (auto-compaction three-tier ladder).
Several integers from upstream sources can be hostile (provider bug, OpenAI-compat proxy returning
null/NaN, misconfigured override) and poison the gate arithmetic:Failure modes
usageMetadata.{prompt,candidates,cached,total}TokenCountcan be NaN / Infinity / negative on hostile providers. The streaming response handler captures these unguarded. SubsequentlastPromptTokenCount + NaN >= hardis always false → hard-rescue silently disabled;Infinity >= hardalways true → hard-rescue fires every send.computeThresholds(window)has no input validation. IfcontextWindowSize: NaN(proxy returningnull),NaN - SUMMARY_RESERVE = NaN, all four thresholds become NaN, everytokens >= NaNis false → the entire three-tier ladder silently disables.Both are catastrophic (silent compression disable) but require non-default provider misbehavior.
Proposed fix
1. Coerce helper for API usage fields
Route all 4 API-capture sites in
geminiChat.tsthrough it:usageMetadata.promptTokenCountusageMetadata.totalTokenCountusageMetadata.candidatesTokenCountusageMetadata.cachedContentTokenCountNumber.isFinite(-1)is true, so the>= 0is also needed (not justisFinite).2. computeThresholds input guard
Returning
Infinity(rather than 0) meanstokens < Infinityalways true → gate falls through to NOOP-equivalent path, instead oftokens < 0always false latching at fired-state.Related
Worked out in R11.1 + R12.1 + R12.2 of PR #4168 (archived at tag
pr-4168-archive-pre-revert). Pure follow-up — both are defensive guards on edge-case inputs, no behavioral change for any provider returning sane values.