Skip to content

Commit 1055911

Browse files
committed
take-2
1 parent dcfbf87 commit 1055911

10 files changed

Lines changed: 35 additions & 37 deletions

File tree

packages/core/src/context/config/profiles.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export const generalistProfile: ContextProfile = {
7878
budget: {
7979
retainedTokens: 65000,
8080
maxTokens: 150000,
81+
coalescingThresholdTokens: 5000,
8182
},
8283
},
8384

@@ -117,14 +118,14 @@ export const generalistProfile: ContextProfile = {
117118
'NodeDistillation',
118119
env,
119120
resolveProcessorOptions(config, 'NodeDistillation', {
120-
nodeThresholdTokens: 1000,
121+
nodeThresholdTokens: 3000,
121122
}),
122123
),
123124
createNodeTruncationProcessor(
124125
'NodeTruncation',
125126
env,
126127
resolveProcessorOptions(config, 'NodeTruncation', {
127-
maxTokensPerNode: 1200,
128+
maxTokensPerNode: 4000,
128129
}),
129130
),
130131
],

packages/core/src/context/config/schema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export function getContextManagementConfigSchema(
4242
description:
4343
'The absolute maximum token count allowed before synchronous truncation kicks in.',
4444
},
45+
coalescingThresholdTokens: {
46+
type: 'number',
47+
description:
48+
'Only trigger background consolidation (snapshots) when at least this many tokens have aged out. Prevents "turn-by-turn" utility model churn.',
49+
},
4550
},
4651
},
4752
processorOptions: {

packages/core/src/context/config/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ export interface AsyncPipelineDef {
2929
export interface ContextBudget {
3030
retainedTokens: number;
3131
maxTokens: number;
32+
/**
33+
* Only trigger background consolidation (snapshots) when at least this many
34+
* tokens have aged out. Prevents "turn-by-turn" utility model churn.
35+
*/
36+
coalescingThresholdTokens?: number;
3237
}
3338

3439
/**

packages/core/src/context/contextManager.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,23 @@ export class ContextManager {
141141
}
142142

143143
if (agedOutNodes.size > 0) {
144-
this.env.tokenCalculator.garbageCollectCache(
145-
new Set(this.buffer.nodes.map((n) => n.id)),
146-
);
147-
this.eventBus.emitConsolidationNeeded({
148-
nodes: this.buffer.nodes,
149-
targetDeficit:
150-
currentTokens - this.sidecar.config.budget.retainedTokens,
151-
targetNodeIds: agedOutNodes,
152-
});
144+
const targetDeficit =
145+
currentTokens - this.sidecar.config.budget.retainedTokens;
146+
147+
// Respect coalescing threshold for background work
148+
const threshold =
149+
this.sidecar.config.budget.coalescingThresholdTokens || 0;
150+
151+
if (targetDeficit >= threshold) {
152+
this.env.tokenCalculator.garbageCollectCache(
153+
new Set(this.buffer.nodes.map((n) => n.id)),
154+
);
155+
this.eventBus.emitConsolidationNeeded({
156+
nodes: this.buffer.nodes,
157+
targetDeficit,
158+
targetNodeIds: agedOutNodes,
159+
});
160+
}
153161
}
154162
}
155163
}

packages/core/src/context/processors/nodeDistillationProcessor.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ export function createNodeDistillationProcessor(
9797
]);
9898

9999
if (newTokens < oldTokens) {
100-
console.error(
101-
`[NodeDistillationProcessor] Distilled text node ${node.id} (${oldTokens} -> ${newTokens} tokens)`,
102-
);
103100
const distilledPayload = updatePart(payload, { text: summary });
104101

105102
returnedNodes.push({
@@ -154,9 +151,6 @@ export function createNodeDistillationProcessor(
154151
);
155152

156153
if (newObsTokens < oldObsTokens) {
157-
console.error(
158-
`[NodeDistillationProcessor] Distilled tool observation for ${payload.functionResponse.name} in node ${node.id} (${oldObsTokens} -> ${newObsTokens} tokens)`,
159-
);
160154
const newFR = cloneFunctionResponse(payload.functionResponse);
161155
newFR.response = newObsObject;
162156

packages/core/src/context/processors/stateSnapshotAsyncProcessor.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,6 @@ export function createStateSnapshotAsyncProcessor(
9292
options.systemInstruction,
9393
);
9494

95-
console.error(
96-
`[StateSnapshotAsyncProcessor] Generated async snapshot of ${nodesToSummarize.length} nodes (${snapshotText.length} chars).`,
97-
);
98-
9995
const newConsumedIds = [
10096
...previousConsumedIds,
10197
...targets.map((t) => t.id),

packages/core/src/context/processors/stateSnapshotProcessor.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,6 @@ export function createStateSnapshotProcessor(
146146
nodesToSummarize,
147147
options.systemInstruction,
148148
);
149-
150-
console.error(
151-
`[StateSnapshotProcessor] Generated sync snapshot of ${nodesToSummarize.length} nodes (${snapshotText.length} chars).`,
152-
);
153149
const newId = randomUUID();
154150
const snapshotNode: Snapshot = {
155151
id: newId,

packages/core/src/context/utils/snapshotGenerator.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ export class SnapshotGenerator {
1919
`You are an expert Context Memory Manager. You will be provided with a raw transcript of older conversation turns between a user and an AI assistant.
2020
Your task is to synthesize these turns into a single, dense, factual snapshot that preserves all critical context, preferences, active tasks, and factual knowledge.
2121
22-
CRITICAL: You must explicitly preserve the assistant's "Current Operating Mode". If the assistant has entered "Plan Mode" or any other specialized state, this must be clearly stated in the snapshot.
23-
2422
Discard conversational filler, pleasantries, and redundant back-and-forth iterations. Output ONLY the raw factual snapshot, formatted compactly. Do not include markdown wrappers, prefixes like "Here is the snapshot", or conversational elements.`;
2523

2624
let userPromptText = 'TRANSCRIPT TO SNAPSHOT:\n\n';

packages/core/src/core/client.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ describe('Gemini Client (client.ts)', () => {
289289
resetTurn: vi.fn(),
290290

291291
isAutoDistillationEnabled: vi.fn().mockReturnValue(false),
292+
isContextManagementEnabled: vi.fn().mockReturnValue(false),
292293
getContextManagementConfig: vi.fn().mockReturnValue({ enabled: false }),
293294
getModelAvailabilityService: vi
294295
.fn()

packages/core/src/core/geminiChat.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -769,23 +769,17 @@ export class GeminiChat {
769769
*
770770
* @param curated - whether to return the curated history or the comprehensive
771771
* history.
772-
* @param skipScrubbing - if true, returns the raw history without removing internal metadata.
773772
* @return History contents alternating between user and model for the entire
774773
* chat session.
775774
*/
776-
getHistory(
777-
curated: boolean = false,
778-
skipScrubbing: boolean = false,
779-
): readonly Content[] {
775+
getHistory(curated: boolean = false): readonly Content[] {
780776
const history = curated
781777
? extractCuratedHistory([...this.agentHistory.get()])
782778
: this.agentHistory.get();
783779

784-
if (skipScrubbing) {
785-
return [...history];
786-
}
787-
788-
return scrubHistory([...history]);
780+
return this.context.config.isContextManagementEnabled()
781+
? scrubHistory([...history])
782+
: [...history];
789783
}
790784

791785
/**

0 commit comments

Comments
 (0)