@myagentroam/agent 0.11.55 → 0.11.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ import { retainedCodeInputs } from '../../session/context-gc-observations.js';
2
2
  import { contextGcTargetKey } from '../../session/context-gc-checkpoint.js';
3
3
  import { codeCellCompletionSequence, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, hasGenericContextGcPreview, normalizeContextGcCodeModeInput } from '../../session/context-gc-replacements.js';
4
4
  import { CONTEXT_GC_POLICY } from './gc-economics.js';
5
+ import { contextGcProtectionMature } from '../../session/context-gc-protection.js';
5
6
  import { targetFor, isRecord } from './gc-candidates.js';
6
7
  export function collectCodeModeCandidates(input, groups, existingTargets, candidateSavings) {
7
8
  const eligible = [];
@@ -41,8 +42,7 @@ export function collectCodeModeCandidates(input, groups, existingTargets, candid
41
42
  const reclaimedTokens = candidateSavings(candidate);
42
43
  if (reclaimedTokens <= 0)
43
44
  continue;
44
- if (candidate.observedRollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts &&
45
- protection.thinking >= 3)
45
+ if (contextGcProtectionMature(protection))
46
46
  eligible.push(candidate);
47
47
  else if (candidate.observedRollouts < CONTEXT_GC_POLICY.largeExecProtectionRollouts) {
48
48
  protectedTokens += reclaimedTokens;
@@ -74,12 +74,12 @@ export function collectCodeModeCandidates(input, groups, existingTargets, candid
74
74
  replacementArguments: contextGcCodeModeInputReplacement(code, group.result.message.observations
75
75
  ? retainedCodeInputs(input.records, group.callId, (original, successor) => {
76
76
  const maturity = input.protection.after(Math.max(evidenceSequence, completionSequence, original.sequence, successor.sequence));
77
- return maturity.rollouts >= 6 && maturity.thinking >= 3;
77
+ return contextGcProtectionMature(maturity);
78
78
  }, {
79
79
  activeProcessIds: input.activeProcessIds,
80
80
  evidenceMature: (sequence) => {
81
81
  const maturity = input.protection.after(Math.max(evidenceSequence, completionSequence, sequence));
82
- return maturity.rollouts >= 6 && maturity.thinking >= 3;
82
+ return contextGcProtectionMature(maturity);
83
83
  }
84
84
  })
85
85
  : []),
@@ -105,8 +105,7 @@ export function collectCodeModeCandidates(input, groups, existingTargets, candid
105
105
  const reclaimedTokens = candidateSavings(candidate);
106
106
  if (reclaimedTokens <= 0)
107
107
  continue;
108
- if (observedRollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts &&
109
- protection.thinking >= 3)
108
+ if (contextGcProtectionMature(protection))
110
109
  eligible.push(candidate);
111
110
  else if (observedRollouts < CONTEXT_GC_POLICY.largeExecProtectionRollouts) {
112
111
  protectedTokens += reclaimedTokens;
@@ -1,6 +1,7 @@
1
1
  import { contextGcTargetKey } from '../../session/context-gc-checkpoint.js';
2
2
  import { contextGcExecInputReplacement, contextGcExecOutputReplacement, normalizeContextGcExecResult } from '../../session/context-gc-replacements.js';
3
3
  import { CONTEXT_GC_POLICY } from './gc-economics.js';
4
+ import { contextGcProtectionMature } from '../../session/context-gc-protection.js';
4
5
  import { targetFor, isRecord } from './gc-candidates.js';
5
6
  import { terminalExecLifecycles } from '../../session/context-gc-exec-lifecycle.js';
6
7
  export function collectExecCandidates(input, groups, existingTargets, candidateSavings) {
@@ -80,8 +81,7 @@ export function collectExecCandidates(input, groups, existingTargets, candidateS
80
81
  let observedRollouts = Infinity;
81
82
  for (const replacement of replacements) {
82
83
  const protection = input.protection.after(Math.max(evidenceSequence, replacement.target.sequence));
83
- if (protection.rollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts &&
84
- protection.thinking >= 3) {
84
+ if (contextGcProtectionMature(protection)) {
85
85
  mature.push(replacement);
86
86
  observedRollouts = Math.min(observedRollouts, protection.rollouts);
87
87
  }
@@ -2,6 +2,7 @@ import { contextGcLogicalPathKey, contextGcTargetKey } from '../../session/conte
2
2
  import { contextGcApplyPatchInputReplacement, contextGcPatchResultFromCompletedPayload, contextGcPatchResultFromFailedPayload, contextGcStaleReadReplacement, contextGcReadRangeCovers, contextGcCoveredReadReplacement } from '../../session/context-gc-replacements.js';
3
3
  import { parseReadContextOutput } from '../../prompts/read-context.js';
4
4
  import { CONTEXT_GC_POLICY } from './gc-economics.js';
5
+ import { contextGcProtectionMature } from '../../session/context-gc-protection.js';
5
6
  import { targetFor } from './gc-candidates.js';
6
7
  export function collectDeterministicCandidates(input, groups, existingReplacements, existingTargets, candidateSavings) {
7
8
  const eligible = [];
@@ -103,8 +104,7 @@ export function collectDeterministicCandidates(input, groups, existingReplacemen
103
104
  let observedRollouts = Infinity;
104
105
  for (const replacement of replacements) {
105
106
  const protection = input.protection.after(Math.max(evidenceSequence, replacement.target.sequence));
106
- if (protection.rollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts &&
107
- protection.thinking >= 3) {
107
+ if (contextGcProtectionMature(protection)) {
108
108
  mature.push(replacement);
109
109
  observedRollouts = Math.min(observedRollouts, protection.rollouts);
110
110
  }
@@ -162,7 +162,7 @@ export function collectDeterministicCandidates(input, groups, existingReplacemen
162
162
  ?.items.some((prior) => prior.index === candidate.index)));
163
163
  const successor = later.findLast((entry) => {
164
164
  const count = input.protection.after(entry.target.sequence);
165
- return count.rollouts >= 6 && count.thinking >= 3;
165
+ return contextGcProtectionMature(count);
166
166
  });
167
167
  if (!successor)
168
168
  continue;
@@ -2,6 +2,7 @@ import { contextGcTargetKey } from '../../session/context-gc-checkpoint.js';
2
2
  import { completedTodoWrite, todoInputReplacement, todoSnapshotReplacement, visibleTodoSnapshot } from '../../session/context-gc-todo.js';
3
3
  import { contextGcWebOutputReplacement, contextGcToolOutputReplacement, contextGcSkillOutputReplacement, hasGenericContextGcPreview, isGenericContextGcTool } from '../../session/context-gc-replacements.js';
4
4
  import { CONTEXT_GC_POLICY } from './gc-economics.js';
5
+ import { contextGcProtectionMature } from '../../session/context-gc-protection.js';
5
6
  import { targetFor, isRecord } from './gc-candidates.js';
6
7
  export function collectWebCandidates(input, groups, existingTargets, candidateSavings) {
7
8
  const eligible = [];
@@ -46,8 +47,7 @@ export function collectWebCandidates(input, groups, existingTargets, candidateSa
46
47
  const reclaimedTokens = candidateSavings(candidate);
47
48
  if (reclaimedTokens <= 0)
48
49
  continue;
49
- if (observedRollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts &&
50
- protection.thinking >= 3)
50
+ if (contextGcProtectionMature(protection))
51
51
  eligible.push(candidate);
52
52
  else if (observedRollouts < CONTEXT_GC_POLICY.largeExecProtectionRollouts) {
53
53
  protectedTokens += reclaimedTokens;
@@ -82,7 +82,7 @@ export function collectToolOutputCandidates(input, groups, existingTargets, cand
82
82
  candidate.result.message.toolSearchTools.some((item) => item.name === tool.name) &&
83
83
  (() => {
84
84
  const count = input.protection.after(Math.max(target.sequence, candidate.result.record.sequence));
85
- return count.rollouts >= 6 && count.thinking >= 3;
85
+ return contextGcProtectionMature(count);
86
86
  })());
87
87
  if (successor)
88
88
  evidence.push(successor.result.record.sequence);
@@ -133,8 +133,7 @@ export function collectToolOutputCandidates(input, groups, existingTargets, cand
133
133
  continue;
134
134
  const successor = writes
135
135
  .filter((write) => write.revision > currentRevision &&
136
- input.protection.after(Math.max(target.sequence, group.completed.sequence, write.record.sequence)).rollouts >= 6 &&
137
- input.protection.after(Math.max(target.sequence, group.completed.sequence, write.record.sequence)).thinking >= 3)
136
+ contextGcProtectionMature(input.protection.after(Math.max(target.sequence, group.completed.sequence, write.record.sequence))))
138
137
  .sort((a, b) => b.revision - a.revision)[0];
139
138
  if (!successor)
140
139
  continue;
@@ -196,7 +195,7 @@ export function collectToolOutputCandidates(input, groups, existingTargets, cand
196
195
  });
197
196
  const successor = later.findLast((candidate) => {
198
197
  const count = input.protection.after(Math.max(target.sequence, candidate.result.record.sequence));
199
- return count.rollouts >= 6 && count.thinking >= 3;
198
+ return contextGcProtectionMature(count);
200
199
  });
201
200
  if (!successor)
202
201
  continue;
@@ -259,8 +258,7 @@ export function collectToolOutputCandidates(input, groups, existingTargets, cand
259
258
  const reclaimedTokens = candidateSavings(candidate);
260
259
  if (reclaimedTokens <= 0)
261
260
  continue;
262
- if (observedRollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts &&
263
- protection.thinking >= 3)
261
+ if (contextGcProtectionMature(protection))
264
262
  eligible.push(candidate);
265
263
  else if (observedRollouts < CONTEXT_GC_POLICY.largeExecProtectionRollouts) {
266
264
  protectedTokens += reclaimedTokens;
@@ -1,7 +1,16 @@
1
1
  import type { ModelUsage } from '../../model/contracts.js';
2
- import { type ContextGcEconomicsPolicy } from '../../session/context-gc-checkpoint.js';
3
- export declare const CONTEXT_GC_POLICY: ContextGcEconomicsPolicy;
4
- export declare const COMPACT_CREDIT_ACTIVATION_RATIO = 0.8;
2
+ export declare const CONTEXT_GC_POLICY: {
3
+ version: 1;
4
+ minimumPaybackRollouts: number;
5
+ maximumPaybackRollouts: number;
6
+ contextGrowthSampleWindow: number;
7
+ minimumContextGrowthSamples: number;
8
+ minimumObservationRollouts: number;
9
+ stageAProtectionRollouts: number;
10
+ largeExecProtectionRollouts: number;
11
+ normalInputCostRate: number;
12
+ cacheReadCostRate: number;
13
+ };
5
14
  export declare const COMPACT_THRESHOLD_RATIO: number;
6
15
  interface ContextGcEconomicsInput {
7
16
  readonly contextUsageTokens: number;
@@ -10,11 +19,6 @@ interface ContextGcEconomicsInput {
10
19
  readonly reclaimedCachedTokens: number;
11
20
  readonly cacheReadTokens: number;
12
21
  readonly preservedCachedPrefixTokens: number;
13
- readonly compactDeferralCreditCostUnits: number;
14
- readonly projectedRolloutsUntilCompactAfterGc: number;
15
- readonly contextGrowthSampleCount: number;
16
- readonly minimumGrossReductionRate?: number;
17
- readonly minimumReclaimedTokens?: number;
18
22
  }
19
23
  export interface ContextGcEconomicsResult {
20
24
  readonly cacheRebuildPenaltyCostUnits: number;
@@ -24,18 +28,8 @@ export interface ContextGcEconomicsResult {
24
28
  readonly passes: boolean;
25
29
  }
26
30
  export declare function evaluateContextGcEconomics(input: ContextGcEconomicsInput): ContextGcEconomicsResult;
27
- export declare function contextGcMinimumGrossReductionRate(usageRatio: number): number;
28
- export declare function contextGcMinimumReclaimedTokens(contextUsageTokens: number, contextWindowTokens: number): number;
31
+ export declare function contextGcMinimumReclaimedTokens(contextWindowTokens: number): number;
29
32
  export declare function contextGcEligibleUsage(usage: ModelUsage, contextWindowTokens: number): number | undefined;
30
- export declare function contextGcImminentCompactAvoidanceCredit(input: {
31
- readonly contextUsageTokens: number;
32
- readonly contextWindowTokens: number;
33
- readonly compactThresholdTokens: number;
34
- readonly projectedTokensBeforeGc: number;
35
- readonly projectedTokensAfterGc: number;
36
- readonly contextGrowthP75Tokens: number;
37
- }): number;
38
- export declare function contextGcAppliedCompactCreditCostUnits(compactDeferralCreditCostUnits: number, imminentCompactAvoidanceCreditCostUnits: number): number;
39
33
  export declare function modelContextUsage(value: ModelUsage | Record<string, unknown>): number | undefined;
40
34
  export declare function clamp(value: number, minimum: number, maximum: number): number;
41
35
  export {};
@@ -1,25 +1,19 @@
1
1
  import { AGENT_EXECUTION_POLICY } from '../execution-policy.js';
2
+ import { CONTEXT_GC_TEXT_PROTECTION_ROLLOUTS } from '../../session/context-gc-protection.js';
2
3
  export const CONTEXT_GC_POLICY = {
3
4
  version: 1,
4
- immediatePaybackRollouts: 3,
5
- maximumPaybackRollouts: 20,
5
+ minimumPaybackRollouts: 30,
6
+ maximumPaybackRollouts: 60,
6
7
  contextGrowthSampleWindow: 16,
7
8
  minimumContextGrowthSamples: 6,
8
9
  minimumObservationRollouts: 1,
9
- stageAProtectionRollouts: 6,
10
- largeExecProtectionRollouts: 6,
10
+ stageAProtectionRollouts: CONTEXT_GC_TEXT_PROTECTION_ROLLOUTS,
11
+ largeExecProtectionRollouts: CONTEXT_GC_TEXT_PROTECTION_ROLLOUTS,
11
12
  normalInputCostRate: 1,
12
- cacheReadCostRate: 0.05,
13
- outputCostRate: 1,
14
- minimumGrossReductionRate: 0.2
13
+ cacheReadCostRate: 0.05
15
14
  };
16
15
  const CONTEXT_GC_START_RATIO = 0.5;
17
- const HIGH_WATER_GROSS_REDUCTION_START_RATIO = 0.7;
18
- const HIGH_WATER_MINIMUM_GROSS_REDUCTION_RATE = 0.1;
19
- const MINIMUM_CONTEXT_WINDOW_REDUCTION_RATIO = 0.05;
20
- export const COMPACT_CREDIT_ACTIVATION_RATIO = 0.8;
21
16
  export const COMPACT_THRESHOLD_RATIO = AGENT_EXECUTION_POLICY.backgroundCompactionPercent / 100;
22
- const IMMINENT_COMPACT_CREDIT_DISCOUNT = 0.8;
23
17
  export function evaluateContextGcEconomics(input) {
24
18
  const reclaimedTokens = Math.max(0, input.reclaimedTokens);
25
19
  const cacheReadTokens = Math.max(0, input.cacheReadTokens);
@@ -34,16 +28,13 @@ export function evaluateContextGcEconomics(input) {
34
28
  const reclaimedUncachedTokens = Math.max(0, reclaimedTokens - reclaimedCachedTokens);
35
29
  const firstRolloutSavings = reclaimedCachedTokens + reclaimedUncachedTokens * unitsPerNormalInput;
36
30
  const steadyRolloutSavings = reclaimedTokens;
37
- const netAt = (rollouts) => (rollouts <= 0
31
+ const netAt = (rollouts) => rollouts <= 0
38
32
  ? -cacheRebuildPenalty
39
33
  : firstRolloutSavings +
40
34
  Math.max(0, rollouts - 1) * steadyRolloutSavings -
41
- cacheRebuildPenalty) +
42
- input.compactDeferralCreditCostUnits / CONTEXT_GC_POLICY.cacheReadCostRate;
35
+ cacheRebuildPenalty;
43
36
  let requiredPositiveNetRollouts;
44
- if (netAt(0) > 0)
45
- requiredPositiveNetRollouts = 0;
46
- else if (netAt(1) > 0)
37
+ if (netAt(1) > 0)
47
38
  requiredPositiveNetRollouts = 1;
48
39
  else if (steadyRolloutSavings <= 0)
49
40
  requiredPositiveNetRollouts = null;
@@ -56,23 +47,17 @@ export function evaluateContextGcEconomics(input) {
56
47
  }
57
48
  const expectedNetSavedCostUnits = netAt(requiredPositiveNetRollouts ?? 0) * CONTEXT_GC_POLICY.cacheReadCostRate;
58
49
  const grossReductionRate = reclaimedTokens / Math.max(1, Math.max(0, input.contextUsageTokens));
59
- const minimumGrossReductionRate = Math.max(0, input.minimumGrossReductionRate ?? CONTEXT_GC_POLICY.minimumGrossReductionRate);
60
- const minimumReclaimedTokens = Math.max(0, input.minimumReclaimedTokens ??
61
- Math.ceil(Math.max(0, input.contextUsageTokens) * minimumGrossReductionRate));
50
+ const minimumReclaimedTokens = contextGcMinimumReclaimedTokens(input.contextWindowTokens);
62
51
  const usageRatio = input.contextUsageTokens / input.contextWindowTokens;
63
- const thresholdPercent = AGENT_EXECUTION_POLICY.backgroundCompactionPercent;
64
- const activationPercent = COMPACT_CREDIT_ACTIVATION_RATIO * 100;
65
- const withinWindow = requiredPositiveNetRollouts !== null &&
66
- (usageRatio <= COMPACT_CREDIT_ACTIVATION_RATIO
67
- ? requiredPositiveNetRollouts <= CONTEXT_GC_POLICY.maximumPaybackRollouts
68
- : requiredPositiveNetRollouts *
69
- (thresholdPercent * input.contextWindowTokens - 100 * input.contextUsageTokens) <=
70
- CONTEXT_GC_POLICY.maximumPaybackRollouts *
71
- (thresholdPercent - activationPercent) *
72
- input.contextWindowTokens);
52
+ const progress = clamp((usageRatio - CONTEXT_GC_START_RATIO) / (COMPACT_THRESHOLD_RATIO - CONTEXT_GC_START_RATIO), 0, 1);
53
+ const paybackWindow = CONTEXT_GC_POLICY.minimumPaybackRollouts +
54
+ progress *
55
+ (CONTEXT_GC_POLICY.maximumPaybackRollouts - CONTEXT_GC_POLICY.minimumPaybackRollouts);
56
+ const withinWindow = requiredPositiveNetRollouts !== null && requiredPositiveNetRollouts <= paybackWindow;
73
57
  const passes = reclaimedTokens > 0 &&
74
58
  reclaimedTokens >= minimumReclaimedTokens &&
75
59
  Number.isFinite(usageRatio) &&
60
+ usageRatio >= CONTEXT_GC_START_RATIO &&
76
61
  usageRatio < COMPACT_THRESHOLD_RATIO &&
77
62
  withinWindow;
78
63
  return {
@@ -83,26 +68,8 @@ export function evaluateContextGcEconomics(input) {
83
68
  passes
84
69
  };
85
70
  }
86
- export function contextGcMinimumGrossReductionRate(usageRatio) {
87
- if (!Number.isFinite(usageRatio) || usageRatio <= HIGH_WATER_GROSS_REDUCTION_START_RATIO)
88
- return CONTEXT_GC_POLICY.minimumGrossReductionRate;
89
- if (usageRatio >= COMPACT_THRESHOLD_RATIO)
90
- return HIGH_WATER_MINIMUM_GROSS_REDUCTION_RATE;
91
- const progress = (usageRatio - HIGH_WATER_GROSS_REDUCTION_START_RATIO) /
92
- (COMPACT_THRESHOLD_RATIO - HIGH_WATER_GROSS_REDUCTION_START_RATIO);
93
- return (CONTEXT_GC_POLICY.minimumGrossReductionRate -
94
- progress *
95
- (CONTEXT_GC_POLICY.minimumGrossReductionRate - HIGH_WATER_MINIMUM_GROSS_REDUCTION_RATE));
96
- }
97
- export function contextGcMinimumReclaimedTokens(contextUsageTokens, contextWindowTokens) {
98
- if (!Number.isFinite(contextUsageTokens) ||
99
- contextUsageTokens < 0 ||
100
- !Number.isFinite(contextWindowTokens) ||
101
- contextWindowTokens <= 0)
102
- return 0;
103
- const usageRatio = contextUsageTokens / contextWindowTokens;
104
- const required = Math.max(contextUsageTokens * contextGcMinimumGrossReductionRate(usageRatio), contextWindowTokens * MINIMUM_CONTEXT_WINDOW_REDUCTION_RATIO);
105
- return Math.ceil(required - 1e-9);
71
+ export function contextGcMinimumReclaimedTokens(contextWindowTokens) {
72
+ return Math.ceil(contextWindowTokens / 20);
106
73
  }
107
74
  export function contextGcEligibleUsage(usage, contextWindowTokens) {
108
75
  const contextUsageTokens = modelContextUsage(usage);
@@ -115,21 +82,6 @@ export function contextGcEligibleUsage(usage, contextWindowTokens) {
115
82
  return undefined;
116
83
  return contextUsageTokens;
117
84
  }
118
- export function contextGcImminentCompactAvoidanceCredit(input) {
119
- if (input.contextUsageTokens >= input.compactThresholdTokens ||
120
- input.contextGrowthP75Tokens <= 0 ||
121
- input.projectedTokensBeforeGc < input.compactThresholdTokens)
122
- return 0;
123
- const safetyMarginTokens = Math.max(input.contextWindowTokens * MINIMUM_CONTEXT_WINDOW_REDUCTION_RATIO, input.contextGrowthP75Tokens * CONTEXT_GC_POLICY.immediatePaybackRollouts);
124
- if (input.projectedTokensAfterGc > input.compactThresholdTokens - safetyMarginTokens)
125
- return 0;
126
- return (input.contextUsageTokens *
127
- CONTEXT_GC_POLICY.normalInputCostRate *
128
- IMMINENT_COMPACT_CREDIT_DISCOUNT);
129
- }
130
- export function contextGcAppliedCompactCreditCostUnits(compactDeferralCreditCostUnits, imminentCompactAvoidanceCreditCostUnits) {
131
- return Math.max(0, compactDeferralCreditCostUnits, imminentCompactAvoidanceCreditCostUnits);
132
- }
133
85
  export function modelContextUsage(value) {
134
86
  const context = value.contextInputTokens ?? value.inputTokens;
135
87
  return typeof context === 'number' && Number.isSafeInteger(context) && context >= 0
@@ -1,5 +1,5 @@
1
1
  import { type ContextGcPlan, type ContextGcInspection, type ContextGcPlannerInput } from './gc-contracts.js';
2
- export { CONTEXT_GC_POLICY, type ContextGcEconomicsResult, evaluateContextGcEconomics, contextGcMinimumGrossReductionRate, contextGcMinimumReclaimedTokens, contextGcEligibleUsage, contextGcImminentCompactAvoidanceCredit, contextGcAppliedCompactCreditCostUnits } from './gc-economics.js';
2
+ export { CONTEXT_GC_POLICY, type ContextGcEconomicsResult, evaluateContextGcEconomics, contextGcMinimumReclaimedTokens, contextGcEligibleUsage } from './gc-economics.js';
3
3
  export { type ContextGcPlan, type ContextGcInspection, type ContextGcPlannerInput } from './gc-contracts.js';
4
4
  export declare function planContextGc(input: ContextGcPlannerInput): ContextGcPlan | undefined;
5
5
  export declare function inspectContextGc(input: ContextGcPlannerInput): ContextGcInspection;
@@ -2,13 +2,13 @@ import { ContextGcCheckpointCache, contextGcBaseFromRecords, contextGcCheckpoint
2
2
  import { buildContextGcProtection } from '../../session/context-gc-protection.js';
3
3
  import { CONTEXT_GC_TOKEN_ESTIMATOR, contextGcCacheImpact, contextGcMessageTokens, contextGcPrefixTokens, contextGcReclaimedTokens } from './gc-tokens.js';
4
4
  import { applyContextGcReplacementsToMessages, providerToolCallId } from './projection.js';
5
- import { CONTEXT_GC_POLICY, COMPACT_CREDIT_ACTIVATION_RATIO, COMPACT_THRESHOLD_RATIO, evaluateContextGcEconomics, contextGcMinimumGrossReductionRate, contextGcMinimumReclaimedTokens, contextGcEligibleUsage, contextGcImminentCompactAvoidanceCredit, contextGcAppliedCompactCreditCostUnits, modelContextUsage, clamp } from './gc-economics.js';
5
+ import { CONTEXT_GC_POLICY, COMPACT_THRESHOLD_RATIO, evaluateContextGcEconomics, contextGcMinimumReclaimedTokens, contextGcEligibleUsage, modelContextUsage } from './gc-economics.js';
6
6
  import { buildToolGroups, countSuccessfulNormalRollouts, isRecord } from './gc-candidates.js';
7
7
  import { collectCodeModeCandidates } from './gc-candidates-code.js';
8
8
  import { collectDeterministicCandidates } from './gc-candidates-read-patch.js';
9
9
  import { collectExecCandidates } from './gc-candidates-exec.js';
10
10
  import { collectToolOutputCandidates, collectWebCandidates } from './gc-candidates-web.js';
11
- export { CONTEXT_GC_POLICY, evaluateContextGcEconomics, contextGcMinimumGrossReductionRate, contextGcMinimumReclaimedTokens, contextGcEligibleUsage, contextGcImminentCompactAvoidanceCredit, contextGcAppliedCompactCreditCostUnits } from './gc-economics.js';
11
+ export { CONTEXT_GC_POLICY, evaluateContextGcEconomics, contextGcMinimumReclaimedTokens, contextGcEligibleUsage } from './gc-economics.js';
12
12
  export function planContextGc(input) {
13
13
  return inspectContextGc(input).plan;
14
14
  }
@@ -31,7 +31,6 @@ export function inspectContextGc(input) {
31
31
  const state = {
32
32
  stage: text.plan?.stage ?? 'INLINE_MEDIA',
33
33
  contextUsageTokens,
34
- usageRatio: contextUsageTokens / input.contextWindowTokens,
35
34
  usageRecord,
36
35
  normalRolloutOrdinal: countSuccessfulNormalRollouts(input.records, input.modelId, input.contextWindowTokens),
37
36
  protectedCandidateTokens: text.plan?.metrics.protectedCandidateTokens ?? 0
@@ -73,7 +72,6 @@ function inspectTextGc(input) {
73
72
  checkpointCache: input.checkpointCache ?? new ContextGcCheckpointCache(),
74
73
  protection: buildContextGcProtection(input.records, input.modelId, input.contextWindowTokens)
75
74
  };
76
- const usageRatio = contextUsageTokens / input.contextWindowTokens;
77
75
  const usageRecord = latestUsageRecord(input.records, input.modelId);
78
76
  if (!usageRecord)
79
77
  return {};
@@ -129,7 +127,6 @@ function inspectTextGc(input) {
129
127
  ], {
130
128
  stage: 'UNIFIED',
131
129
  contextUsageTokens,
132
- usageRatio,
133
130
  usageRecord,
134
131
  normalRolloutOrdinal,
135
132
  protectedCandidateTokens
@@ -148,8 +145,7 @@ function inspectTextGc(input) {
148
145
  }
149
146
  return protectedCandidateTokens > 0 &&
150
147
  (combined?.economics.passes ||
151
- protectedCandidateTokens >=
152
- contextGcMinimumReclaimedTokens(contextUsageTokens, input.contextWindowTokens)) &&
148
+ protectedCandidateTokens >= contextGcMinimumReclaimedTokens(input.contextWindowTokens)) &&
153
149
  Number.isFinite(retryAfterRollouts)
154
150
  ? { retryAfterRollouts }
155
151
  : {};
@@ -175,12 +171,8 @@ function finalizePlan(input, evaluated, includeMedia = false) {
175
171
  afterTokens: evaluated.afterTokens,
176
172
  reclaimedTokens: evaluated.reclaimedTokens,
177
173
  grossReductionRate: evaluated.economics.grossReductionRate,
178
- effectiveMinimumGrossReductionRate: evaluated.minimumGrossReductionRate,
179
174
  minimumRequiredReclaimedTokens: evaluated.minimumReclaimedTokens,
180
175
  cacheRebuildPenaltyCostUnits: evaluated.economics.cacheRebuildPenaltyCostUnits,
181
- compactDeferralCreditCostUnits: evaluated.compactDeferralCreditCostUnits,
182
- imminentCompactAvoidanceCreditCostUnits: evaluated.imminentCompactAvoidanceCreditCostUnits,
183
- appliedCompactCreditCostUnits: evaluated.appliedCompactCreditCostUnits,
184
176
  requiredPositiveNetRollouts: evaluated.economics.requiredPositiveNetRollouts,
185
177
  projectedRolloutsUntilCompactAfterGc: evaluated.projectedRolloutsUntilCompactAfterGc,
186
178
  projectedTokensBeforeGc: evaluated.projectedTokensBeforeGc,
@@ -231,8 +223,7 @@ function evaluateCandidateSet(input, existing, candidates, state, mediaProjectio
231
223
  const projected = applyContextGcReplacementsToMessages(input.messages, input.messageSources, replacements);
232
224
  const projectedMessages = mediaProjection?.(projected.messages) ?? projected.messages;
233
225
  const reclaimedTokens = contextGcReclaimedTokens(input, input.messages, projectedMessages);
234
- const minimumGrossReductionRate = contextGcMinimumGrossReductionRate(state.usageRatio);
235
- const minimumReclaimedTokens = contextGcMinimumReclaimedTokens(state.contextUsageTokens, input.contextWindowTokens);
226
+ const minimumReclaimedTokens = contextGcMinimumReclaimedTokens(input.contextWindowTokens);
236
227
  if (!state.mediaOnly && reclaimedTokens < minimumReclaimedTokens)
237
228
  return undefined;
238
229
  const beforeTokens = contextGcPrefixTokens(input) + contextGcMessageTokens(input, input.messages);
@@ -251,30 +242,13 @@ function evaluateCandidateSet(input, existing, candidates, state, mediaProjectio
251
242
  const projectedRolloutsUntilCompactAfterGc = contextGrowthP75Tokens <= 0
252
243
  ? 0
253
244
  : Math.max(0, Math.floor((compactThresholdTokens - projectedTokensAfterGc) / Math.max(1, contextGrowthP75Tokens)));
254
- const compactDeferralCreditCostUnits = state.usageRatio >= COMPACT_CREDIT_ACTIVATION_RATIO
255
- ? compactDeferralCredit(input, reclaimedTokens, compactThresholdTokens)
256
- : 0;
257
- const imminentCompactAvoidanceCreditCostUnits = contextGcImminentCompactAvoidanceCredit({
258
- contextUsageTokens: state.contextUsageTokens,
259
- contextWindowTokens: input.contextWindowTokens,
260
- compactThresholdTokens,
261
- projectedTokensBeforeGc,
262
- projectedTokensAfterGc,
263
- contextGrowthP75Tokens
264
- });
265
- const appliedCompactCreditCostUnits = contextGcAppliedCompactCreditCostUnits(compactDeferralCreditCostUnits, imminentCompactAvoidanceCreditCostUnits);
266
245
  const economics = evaluateContextGcEconomics({
267
246
  contextUsageTokens: state.contextUsageTokens,
268
247
  contextWindowTokens: input.contextWindowTokens,
269
248
  reclaimedTokens,
270
249
  reclaimedCachedTokens: cache.reclaimedCachedTokens,
271
250
  cacheReadTokens: input.usage.cacheReadTokens ?? 0,
272
- preservedCachedPrefixTokens: cache.preservedCachedPrefixTokens,
273
- compactDeferralCreditCostUnits: appliedCompactCreditCostUnits,
274
- projectedRolloutsUntilCompactAfterGc,
275
- contextGrowthSampleCount: growthSamples.length,
276
- minimumGrossReductionRate,
277
- minimumReclaimedTokens
251
+ preservedCachedPrefixTokens: cache.preservedCachedPrefixTokens
278
252
  });
279
253
  return {
280
254
  ...state,
@@ -286,14 +260,10 @@ function evaluateCandidateSet(input, existing, candidates, state, mediaProjectio
286
260
  reclaimedTokens,
287
261
  contextGrowthSamples: growthSamples,
288
262
  contextGrowthP75Tokens,
289
- minimumGrossReductionRate,
290
263
  minimumReclaimedTokens,
291
264
  projectedRolloutsUntilCompactAfterGc,
292
265
  projectedTokensBeforeGc,
293
266
  projectedTokensAfterGc,
294
- compactDeferralCreditCostUnits,
295
- imminentCompactAvoidanceCreditCostUnits,
296
- appliedCompactCreditCostUnits,
297
267
  boundarySequence: input.records.at(-1)?.sequence ?? state.usageRecord.sequence,
298
268
  minimumObservedRollouts: Math.min(...candidates.map((candidate) => candidate.observedRollouts)),
299
269
  eligibleCandidateCount: candidates.length
@@ -361,59 +331,6 @@ function collectContextGrowthSamples(records, modelId, contextWindowTokens, chec
361
331
  }
362
332
  return samples.slice(-CONTEXT_GC_POLICY.contextGrowthSampleWindow);
363
333
  }
364
- function compactDeferralCredit(input, reclaimedTokens, compactThresholdTokens) {
365
- const base = contextGcBaseFromRecords(input.records);
366
- if (base?.type !== 'COMPACT')
367
- return 0;
368
- const compact = input.records.find((record) => record.sequence === base.sequence);
369
- if (!compact || !isRecord(compact.payload))
370
- return 0;
371
- if (compact.payload.modelId !== input.modelId ||
372
- compact.payload.contextWindowTokens !== input.contextWindowTokens ||
373
- !isRecord(compact.payload.usage))
374
- return 0;
375
- const usage = compact.payload.usage;
376
- const contextInput = modelContextUsage(usage);
377
- const cacheRead = nonnegativeNumber(usage.cacheReadTokens);
378
- const output = nonnegativeNumber(usage.outputTokens);
379
- if (contextInput === undefined || cacheRead === undefined || output === undefined)
380
- return 0;
381
- const baseline = firstMatchingUsageAfter(input.records, compact.sequence, input.modelId, input.contextWindowTokens);
382
- if (baseline === undefined || baseline >= compactThresholdTokens)
383
- return 0;
384
- const fresh = Math.max(0, contextInput - cacheRead);
385
- const compactCost = fresh * CONTEXT_GC_POLICY.normalInputCostRate +
386
- cacheRead * CONTEXT_GC_POLICY.cacheReadCostRate +
387
- output * CONTEXT_GC_POLICY.outputCostRate;
388
- const cycleCapacity = Math.max(1, compactThresholdTokens - baseline);
389
- return compactCost * clamp(reclaimedTokens / cycleCapacity, 0, 1);
390
- }
391
- function firstMatchingUsageAfter(records, sequence, modelId, contextWindowTokens) {
392
- let activeModelId = modelId;
393
- let activeContextWindowTokens = contextWindowTokens;
394
- for (const record of records) {
395
- if (record.sequence <= sequence)
396
- continue;
397
- if (record.type === 'execution.header' && isRecord(record.payload)) {
398
- if (typeof record.payload.modelId === 'string')
399
- activeModelId = record.payload.modelId;
400
- if (typeof record.payload.contextWindowTokens === 'number' &&
401
- Number.isSafeInteger(record.payload.contextWindowTokens) &&
402
- record.payload.contextWindowTokens > 0)
403
- activeContextWindowTokens = record.payload.contextWindowTokens;
404
- continue;
405
- }
406
- if (activeModelId !== modelId ||
407
- activeContextWindowTokens !== contextWindowTokens ||
408
- !isRecord(record.payload) ||
409
- record.payload.type !== 'usage.updated')
410
- continue;
411
- const usage = modelContextUsage(record.payload);
412
- if (usage !== undefined)
413
- return usage;
414
- }
415
- return undefined;
416
- }
417
334
  /** Measure only affected call families, retaining native aliases for provider lowering. */
418
335
  function createCandidateSavingsEstimator(input, existing) {
419
336
  const byCall = new Map();
@@ -466,6 +383,3 @@ function percentile75(values) {
466
383
  const sorted = [...values].sort((left, right) => left - right);
467
384
  return sorted[Math.max(0, Math.ceil(sorted.length * 0.75) - 1)];
468
385
  }
469
- function nonnegativeNumber(value) {
470
- return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
471
- }
@@ -1,7 +1,7 @@
1
1
  import { posix, win32 } from 'node:path';
2
2
  import { isDeepStrictEqual } from 'node:util';
3
3
  import { inlineMediaGcAnchored, parseInlineMediaGc } from './inline-media.js';
4
- import { buildContextGcProtection } from './context-gc-protection.js';
4
+ import { buildContextGcProtection, contextGcProtectionMature } from './context-gc-protection.js';
5
5
  import { completedTodoWrite, todoInputReplacement, todoSnapshotReplacement, visibleTodoSnapshot } from './context-gc-todo.js';
6
6
  import { contextGcRetainedInputMarkup } from './context-gc-markup.js';
7
7
  import { codeCallEvidence, codePartialPatchCallEvidence, callsFromRecord, codeObservationEvidence, observationsFromRecord, retainedCodeInputs } from './context-gc-observations.js';
@@ -239,7 +239,7 @@ export function validateContextGcCheckpoint(records, record, workspace = session
239
239
  }
240
240
  if (anchors.some((anchor) => {
241
241
  const count = protection.after(anchor);
242
- return count.rollouts < 6 || count.thinking < 3;
242
+ return !contextGcProtectionMature(count);
243
243
  }))
244
244
  return undefined;
245
245
  if (!replacementMatchesRecords(replacement, records, recordsBySequence, workspace, payload.trigger.platform, payload.replacements, protection, committed.get(contextGcReplacementKey(replacement))))
@@ -408,12 +408,12 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
408
408
  isDeepStrictEqual(replacement.replacementArguments, contextGcCodeModeInputReplacement(input, observationsFromRecord(evidence.result)
409
409
  ? retainedCodeInputs(records, replacement.callId, (original, successor) => {
410
410
  const count = protection.after(Math.max(replacement.target.sequence, replacement.evidenceSequence, codeCellCompletionSequence(records, evidence.completed) ?? 0, original.sequence, successor.sequence));
411
- return count.rollouts >= 6 && count.thinking >= 3;
411
+ return contextGcProtectionMature(count);
412
412
  }, {
413
413
  activeProcessIds: new Set(),
414
414
  evidenceMature: (sequence) => {
415
415
  const count = protection.after(Math.max(replacement.target.sequence, replacement.evidenceSequence, codeCellCompletionSequence(records, evidence.completed) ?? 0, sequence));
416
- return count.rollouts >= 6 && count.thinking >= 3;
416
+ return contextGcProtectionMature(count);
417
417
  },
418
418
  selected: (callId, toolName, summary) => {
419
419
  const argument = replacement.replacementArguments;
@@ -1102,7 +1102,6 @@ function isContextGcEconomicsPolicy(value) {
1102
1102
  return (isRecord(value) &&
1103
1103
  value.version === 1 &&
1104
1104
  [
1105
- 'immediatePaybackRollouts',
1106
1105
  'maximumPaybackRollouts',
1107
1106
  'contextGrowthSampleWindow',
1108
1107
  'minimumContextGrowthSamples',
@@ -1110,13 +1109,14 @@ function isContextGcEconomicsPolicy(value) {
1110
1109
  'stageAProtectionRollouts',
1111
1110
  'largeExecProtectionRollouts'
1112
1111
  ].every((key) => isNonnegativeInteger(value[key])) &&
1112
+ ['minimumPaybackRollouts', 'immediatePaybackRollouts'].every((key) => value[key] === undefined || isNonnegativeInteger(value[key])) &&
1113
+ ['normalInputCostRate', 'cacheReadCostRate'].every((key) => isNonnegativeFinite(value[key])) &&
1113
1114
  [
1114
- 'normalInputCostRate',
1115
- 'cacheReadCostRate',
1116
- 'outputCostRate',
1117
- 'minimumGrossReductionRate'
1118
- ].every((key) => isNonnegativeFinite(value[key])) &&
1119
- ['cacheWriteCostRate', 'minimumCacheInvestmentRoi'].every((key) => value[key] === undefined || isNonnegativeFinite(value[key])));
1115
+ 'cacheWriteCostRate',
1116
+ 'minimumCacheInvestmentRoi',
1117
+ 'minimumGrossReductionRate',
1118
+ 'outputCostRate'
1119
+ ].every((key) => value[key] === undefined || isNonnegativeFinite(value[key])));
1120
1120
  }
1121
1121
  function isContextGcMetrics(value) {
1122
1122
  if (!isRecord(value) ||
@@ -1131,7 +1131,6 @@ function isContextGcMetrics(value) {
1131
1131
  'reclaimedTokens',
1132
1132
  'grossReductionRate',
1133
1133
  'cacheRebuildPenaltyCostUnits',
1134
- 'compactDeferralCreditCostUnits',
1135
1134
  'projectedRolloutsUntilCompactAfterGc',
1136
1135
  'contextGrowthSampleCount',
1137
1136
  'contextGrowthP75Tokens',
@@ -1142,6 +1141,7 @@ function isContextGcMetrics(value) {
1142
1141
  ];
1143
1142
  const optionalNonnegative = [
1144
1143
  'effectiveMinimumGrossReductionRate',
1144
+ 'compactDeferralCreditCostUnits',
1145
1145
  'minimumRequiredReclaimedTokens',
1146
1146
  'imminentCompactAvoidanceCreditCostUnits',
1147
1147
  'appliedCompactCreditCostUnits',
@@ -4,7 +4,8 @@ export type ContextGcSubagentToolName = 'agent_start' | 'agent_wait' | 'agent_me
4
4
  export type ContextGcPlatform = 'linux' | 'darwin' | 'win32';
5
5
  export interface ContextGcEconomicsPolicy {
6
6
  readonly version: 1;
7
- readonly immediatePaybackRollouts: number;
7
+ readonly immediatePaybackRollouts?: number;
8
+ readonly minimumPaybackRollouts?: number;
8
9
  readonly maximumPaybackRollouts: number;
9
10
  readonly contextGrowthSampleWindow: number;
10
11
  readonly minimumContextGrowthSamples: number;
@@ -14,8 +15,8 @@ export interface ContextGcEconomicsPolicy {
14
15
  readonly normalInputCostRate: number;
15
16
  readonly cacheReadCostRate: number;
16
17
  readonly cacheWriteCostRate?: number;
17
- readonly outputCostRate: number;
18
- readonly minimumGrossReductionRate: number;
18
+ readonly outputCostRate?: number;
19
+ readonly minimumGrossReductionRate?: number;
19
20
  readonly minimumCacheInvestmentRoi?: number;
20
21
  }
21
22
  export type ContextGcBase = {
@@ -108,7 +109,7 @@ export interface ContextGcMetrics {
108
109
  readonly effectiveMinimumGrossReductionRate?: number;
109
110
  readonly minimumRequiredReclaimedTokens?: number;
110
111
  readonly cacheRebuildPenaltyCostUnits: number;
111
- readonly compactDeferralCreditCostUnits: number;
112
+ readonly compactDeferralCreditCostUnits?: number;
112
113
  readonly imminentCompactAvoidanceCreditCostUnits?: number;
113
114
  readonly appliedCompactCreditCostUnits?: number;
114
115
  readonly requiredPositiveNetRollouts: number | null;
@@ -1,4 +1,9 @@
1
1
  import type { SessionRecord } from './record-contract.js';
2
+ export declare const CONTEXT_GC_TEXT_PROTECTION_ROLLOUTS = 10;
3
+ export declare function contextGcProtectionMature(count: {
4
+ readonly rollouts: number;
5
+ readonly thinking: number;
6
+ }): boolean;
2
7
  /** One immutable boundary index, shared by all candidate anchors in this evaluation. */
3
8
  export declare function buildContextGcProtection(records: readonly SessionRecord[], modelId: string, contextWindowTokens: number): {
4
9
  after(anchor: number): {