mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-20 16:53:12 -07:00
fix(context): make incremental GC purely node-based instead of token-based
This commit is contained in:
@@ -23,13 +23,24 @@ export function createHistoryTruncationProcessor(
|
||||
id,
|
||||
name: 'HistoryTruncationProcessor',
|
||||
process: async ({ targets }: ProcessArgs) => {
|
||||
// Calculate how many tokens we need to remove based on the configured knob
|
||||
let targetTokensToRemove = 0;
|
||||
const strategy = options.target ?? 'max';
|
||||
const keptNodes: ConcreteNode[] = [];
|
||||
|
||||
if (strategy === 'incremental') {
|
||||
targetTokensToRemove = Infinity;
|
||||
} else if (strategy === 'freeNTokens') {
|
||||
// 'incremental' simply drops the single oldest node in the targets, ignoring tokens.
|
||||
let removedNodes = 0;
|
||||
for (const node of targets) {
|
||||
if (removedNodes < 1) {
|
||||
removedNodes++;
|
||||
continue;
|
||||
}
|
||||
keptNodes.push(node);
|
||||
}
|
||||
return keptNodes;
|
||||
}
|
||||
|
||||
let targetTokensToRemove = 0;
|
||||
if (strategy === 'freeNTokens') {
|
||||
targetTokensToRemove = options.freeTokensTarget ?? 0;
|
||||
if (targetTokensToRemove <= 0) return targets;
|
||||
} else if (strategy === 'max') {
|
||||
@@ -38,7 +49,6 @@ export function createHistoryTruncationProcessor(
|
||||
}
|
||||
|
||||
let removedTokens = 0;
|
||||
const keptNodes: ConcreteNode[] = [];
|
||||
|
||||
// The targets are sequentially ordered from oldest to newest.
|
||||
// We want to delete the oldest targets first.
|
||||
|
||||
@@ -66,35 +66,36 @@ export function createRollingSummaryProcessor(
|
||||
if (targets.length === 0) return targets;
|
||||
|
||||
const strategy = options.target ?? 'max';
|
||||
let targetTokensToRemove = 0;
|
||||
|
||||
if (strategy === 'incremental') {
|
||||
// A rolling summary should target a small chunk. For now, since state isn't passed,
|
||||
// we'll default to a fixed threshold, like 10000 tokens, to avoid eating the whole history.
|
||||
// Ideally, the orchestrator should pass `tokensToRemove` explicitly.
|
||||
targetTokensToRemove = 10000;
|
||||
} else if (strategy === 'freeNTokens') {
|
||||
targetTokensToRemove = options.freeTokensTarget ?? Infinity;
|
||||
} else if (strategy === 'max') {
|
||||
targetTokensToRemove = Infinity;
|
||||
}
|
||||
|
||||
if (targetTokensToRemove <= 0) return targets;
|
||||
|
||||
let deficitAccumulator = 0;
|
||||
const nodesToSummarize: ConcreteNode[] = [];
|
||||
|
||||
// Scan oldest to newest to find the oldest block that exceeds the token requirement
|
||||
for (const node of targets) {
|
||||
if (node.id === targets[0].id && node.type === 'USER_PROMPT') {
|
||||
// Keep system prompt if it's the very first node
|
||||
continue;
|
||||
if (strategy === 'incremental') {
|
||||
// 'incremental' simply summarizes the minimum viable chunk (the oldest 2 nodes), ignoring token math.
|
||||
for (const node of targets) {
|
||||
if (node.id === targets[0].id && node.type === 'USER_PROMPT') {
|
||||
continue; // Keep system prompt
|
||||
}
|
||||
nodesToSummarize.push(node);
|
||||
if (nodesToSummarize.length >= 2) break; // We have enough for a minimum rolling summary
|
||||
}
|
||||
} else {
|
||||
let targetTokensToRemove = 0;
|
||||
if (strategy === 'freeNTokens') {
|
||||
targetTokensToRemove = options.freeTokensTarget ?? Infinity;
|
||||
} else if (strategy === 'max') {
|
||||
targetTokensToRemove = Infinity;
|
||||
}
|
||||
|
||||
nodesToSummarize.push(node);
|
||||
deficitAccumulator += env.tokenCalculator.getTokenCost(node);
|
||||
|
||||
if (deficitAccumulator >= targetTokensToRemove) break;
|
||||
if (targetTokensToRemove > 0) {
|
||||
let deficitAccumulator = 0;
|
||||
for (const node of targets) {
|
||||
if (node.id === targets[0].id && node.type === 'USER_PROMPT') {
|
||||
continue; // Keep system prompt
|
||||
}
|
||||
nodesToSummarize.push(node);
|
||||
deficitAccumulator += env.tokenCalculator.getTokenCost(node);
|
||||
if (deficitAccumulator >= targetTokensToRemove) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nodesToSummarize.length < 2) return targets; // Not enough context to summarize
|
||||
|
||||
Reference in New Issue
Block a user