@bastani/atomic 0.9.5-alpha.4 → 0.9.5-alpha.6

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.
Files changed (115) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/builtin/cursor/package.json +2 -2
  3. package/dist/builtin/intercom/package.json +1 -1
  4. package/dist/builtin/mcp/package.json +1 -1
  5. package/dist/builtin/subagents/CHANGELOG.md +7 -0
  6. package/dist/builtin/subagents/agents/debugger.md +2 -2
  7. package/dist/builtin/subagents/package.json +1 -1
  8. package/dist/builtin/web-access/package.json +1 -1
  9. package/dist/builtin/workflows/CHANGELOG.md +17 -0
  10. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +5 -5
  11. package/dist/builtin/workflows/builtin/goal-runner.ts +5 -5
  12. package/dist/builtin/workflows/builtin/goal-types.ts +1 -0
  13. package/dist/builtin/workflows/builtin/goal.d.ts +2 -0
  14. package/dist/builtin/workflows/builtin/goal.ts +9 -0
  15. package/dist/builtin/workflows/builtin/index.d.ts +2 -0
  16. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +5 -5
  17. package/dist/builtin/workflows/builtin/ralph-models.ts +25 -25
  18. package/dist/builtin/workflows/package.json +1 -1
  19. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +8 -0
  20. package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +2 -0
  21. package/dist/builtin/workflows/src/runs/foreground/stage-tool-execution-buffer.ts +47 -0
  22. package/dist/builtin/workflows/src/tui/stage-chat-view-pending-tools.ts +9 -0
  23. package/dist/builtin/workflows/src/tui/stage-chat-view-render-settings.ts +27 -0
  24. package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +5 -6
  25. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  26. package/dist/core/agent-session-auto-compaction.js +3 -2
  27. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  28. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  29. package/dist/core/agent-session-compaction.js +25 -4
  30. package/dist/core/agent-session-compaction.js.map +1 -1
  31. package/dist/core/compaction/context-compaction-critical.d.ts +15 -0
  32. package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -0
  33. package/dist/core/compaction/context-compaction-critical.js +57 -0
  34. package/dist/core/compaction/context-compaction-critical.js.map +1 -0
  35. package/dist/core/compaction/context-compaction-eviction.d.ts +4 -0
  36. package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -0
  37. package/dist/core/compaction/context-compaction-eviction.js +172 -0
  38. package/dist/core/compaction/context-compaction-eviction.js.map +1 -0
  39. package/dist/core/compaction/context-compaction-runner.d.ts +7 -1
  40. package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
  41. package/dist/core/compaction/context-compaction-runner.js +97 -21
  42. package/dist/core/compaction/context-compaction-runner.js.map +1 -1
  43. package/dist/core/compaction/context-transcript-analysis.d.ts +3 -0
  44. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
  45. package/dist/core/compaction/context-transcript-analysis.js +3 -3
  46. package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
  47. package/dist/core/extensions/loader-core.d.ts.map +1 -1
  48. package/dist/core/extensions/loader-core.js +6 -0
  49. package/dist/core/extensions/loader-core.js.map +1 -1
  50. package/dist/core/model-resolver-scope.d.ts +9 -0
  51. package/dist/core/model-resolver-scope.d.ts.map +1 -1
  52. package/dist/core/model-resolver-scope.js +12 -4
  53. package/dist/core/model-resolver-scope.js.map +1 -1
  54. package/dist/core/model-resolver.d.ts +3 -2
  55. package/dist/core/model-resolver.d.ts.map +1 -1
  56. package/dist/core/model-resolver.js +1 -1
  57. package/dist/core/model-resolver.js.map +1 -1
  58. package/dist/core/resource-loader-extensions.d.ts.map +1 -1
  59. package/dist/core/resource-loader-extensions.js +4 -0
  60. package/dist/core/resource-loader-extensions.js.map +1 -1
  61. package/dist/core/resource-loader-reload.d.ts.map +1 -1
  62. package/dist/core/resource-loader-reload.js +11 -0
  63. package/dist/core/resource-loader-reload.js.map +1 -1
  64. package/dist/core/settings-manager-core.d.ts.map +1 -1
  65. package/dist/core/settings-manager-core.js +3 -2
  66. package/dist/core/settings-manager-core.js.map +1 -1
  67. package/dist/core/settings-storage.d.ts.map +1 -1
  68. package/dist/core/settings-storage.js +2 -1
  69. package/dist/core/settings-storage.js.map +1 -1
  70. package/dist/core/trust-manager.d.ts +9 -0
  71. package/dist/core/trust-manager.d.ts.map +1 -1
  72. package/dist/core/trust-manager.js +44 -2
  73. package/dist/core/trust-manager.js.map +1 -1
  74. package/dist/index.d.ts +1 -1
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/main-deferred-startup.d.ts +19 -0
  79. package/dist/main-deferred-startup.d.ts.map +1 -0
  80. package/dist/main-deferred-startup.js +21 -0
  81. package/dist/main-deferred-startup.js.map +1 -0
  82. package/dist/main.d.ts.map +1 -1
  83. package/dist/main.js +24 -22
  84. package/dist/main.js.map +1 -1
  85. package/dist/modes/interactive/interactive-deferred-startup.d.ts +2 -1
  86. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  87. package/dist/modes/interactive/interactive-deferred-startup.js +34 -1
  88. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  89. package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
  90. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  91. package/dist/modes/interactive/interactive-mode-deps.js +2 -2
  92. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  93. package/dist/modes/interactive/interactive-mode-types.d.ts +5 -1
  94. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  95. package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
  96. package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
  97. package/dist/modes/interactive/interactive-session-routing.js +2 -2
  98. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  99. package/dist/utils/child-process.d.ts +8 -1
  100. package/dist/utils/child-process.d.ts.map +1 -1
  101. package/dist/utils/child-process.js +39 -6
  102. package/dist/utils/child-process.js.map +1 -1
  103. package/dist/utils/event-loop.d.ts +7 -0
  104. package/dist/utils/event-loop.d.ts.map +1 -0
  105. package/dist/utils/event-loop.js +14 -0
  106. package/dist/utils/event-loop.js.map +1 -0
  107. package/dist/utils/json.d.ts +4 -0
  108. package/dist/utils/json.d.ts.map +1 -1
  109. package/dist/utils/json.js +8 -0
  110. package/dist/utils/json.js.map +1 -1
  111. package/docs/compaction.md +45 -27
  112. package/docs/settings.md +5 -1
  113. package/docs/workflows.md +6 -2
  114. package/npm-shrinkwrap.json +23 -23
  115. package/package.json +2 -2
@@ -0,0 +1,172 @@
1
+ import { validateContextDeletionRequest } from "./context-deletion-application.js";
2
+ import { canDeleteTarget, deletionRequestFromTargets, isTaskBearingEntry } from "./context-deletion-targets.js";
3
+ import { relaxTranscriptForCriticalEviction } from "./context-compaction-critical.js";
4
+ import { assistantEntryHasThinkingContentBlock } from "./context-transcript-analysis.js";
5
+ export const CONTEXT_COMPACTION_MAX_EVICTION_PASSES = 50;
6
+ function terminalDeterministicEvictionError(reason, lastValidated, tokenBudget) {
7
+ const statsText = lastValidated
8
+ ? `achieved tokensAfter=${lastValidated.stats.tokensAfter}, reduction=${lastValidated.stats.percentReduction}%, deletionTargets=${lastValidated.deletedTargets.length}`
9
+ : "achieved no validated deletion targets";
10
+ return new Error(`Context deterministic overflow eviction failed: ${reason}; ${statsText}; budget=${tokenBudget}; nothing more was safely deletable`);
11
+ }
12
+ function hasFitBudget(result, tokenBudget) {
13
+ return result !== undefined && result.deletedTargets.length > 0 && result.stats.tokensAfter <= tokenBudget;
14
+ }
15
+ function isThinkingAssistantEntryTarget(transcript, target) {
16
+ if (target.kind !== "entry")
17
+ return false;
18
+ const entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);
19
+ return entry?.role === "assistant" && assistantEntryHasThinkingContentBlock(entry);
20
+ }
21
+ function isTaskBearingEntryTarget(transcript, target) {
22
+ if (target.kind !== "entry")
23
+ return false;
24
+ const entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);
25
+ return entry !== undefined && isTaskBearingEntry(entry);
26
+ }
27
+ function targetSignature(targets) {
28
+ return targets
29
+ .map((target) => `${target.kind}:${target.entryId}:${target.kind === "content_block" ? target.blockIndex : ""}`)
30
+ .join("|");
31
+ }
32
+ function entryOrder(transcript, entryId) {
33
+ const index = transcript.entries.findIndex((entry) => entry.entryId === entryId);
34
+ return index < 0 ? Number.MAX_SAFE_INTEGER : index;
35
+ }
36
+ function entryTokenEstimate(transcript, entryId) {
37
+ return transcript.entries.find((entry) => entry.entryId === entryId)?.tokenEstimate ?? 0;
38
+ }
39
+ function smallestTaskTarget(transcript, targets) {
40
+ return [...targets]
41
+ .filter((target) => isTaskBearingEntryTarget(transcript, target))
42
+ .sort((left, right) => {
43
+ const tokenDelta = entryTokenEstimate(transcript, left.entryId) - entryTokenEstimate(transcript, right.entryId);
44
+ if (tokenDelta !== 0)
45
+ return tokenDelta;
46
+ return entryOrder(transcript, left.entryId) - entryOrder(transcript, right.entryId);
47
+ })[0];
48
+ }
49
+ function newestThinkingTarget(transcript, targets) {
50
+ return [...targets]
51
+ .filter((target) => isThinkingAssistantEntryTarget(transcript, target))
52
+ .sort((left, right) => entryOrder(transcript, right.entryId) - entryOrder(transcript, left.entryId))[0];
53
+ }
54
+ const THINKING_EXCHANGES = ["keep-all", "drop-all", "retain-newest"];
55
+ const TASK_EXCHANGES = ["keep-all", "drop-all", "retain-smallest"];
56
+ function shouldDeleteTarget(transcript, target, thinkingExchange, taskExchange, retainedThinking, retainedTask) {
57
+ if (thinkingExchange === "drop-all" && isThinkingAssistantEntryTarget(transcript, target))
58
+ return false;
59
+ if (thinkingExchange === "retain-newest" && retainedThinking !== undefined && targetSignature([target]) === targetSignature([retainedThinking]))
60
+ return false;
61
+ if (taskExchange === "drop-all" && isTaskBearingEntryTarget(transcript, target))
62
+ return false;
63
+ if (taskExchange === "retain-smallest" && retainedTask !== undefined && targetSignature([target]) === targetSignature([retainedTask]))
64
+ return false;
65
+ return true;
66
+ }
67
+ function buildExchangePlan(transcript, withCandidate, thinkingExchange, taskExchange) {
68
+ const retainedThinking = thinkingExchange === "retain-newest" ? newestThinkingTarget(transcript, withCandidate) : undefined;
69
+ const retainedTask = taskExchange === "retain-smallest" ? smallestTaskTarget(transcript, withCandidate) : undefined;
70
+ return withCandidate.filter((target) => shouldDeleteTarget(transcript, target, thinkingExchange, taskExchange, retainedThinking, retainedTask));
71
+ }
72
+ function shouldBuildExchangePlan(withCandidate, thinkingExchange, taskExchange) {
73
+ if (thinkingExchange === "keep-all" && taskExchange === "keep-all")
74
+ return false;
75
+ if (thinkingExchange === "retain-newest" && withCandidate.filter((target) => target.kind === "entry").length === 0)
76
+ return false;
77
+ return true;
78
+ }
79
+ function addExchangePlan(plans, seen, originalTargets, targets) {
80
+ if (targetSignature(targets) === targetSignature(originalTargets))
81
+ return;
82
+ const signature = targetSignature(targets);
83
+ if (seen.has(signature))
84
+ return;
85
+ seen.add(signature);
86
+ plans.push([...targets]);
87
+ }
88
+ function exchangePlans(transcript, planned, entryId) {
89
+ const currentTarget = { kind: "entry", entryId };
90
+ const withCandidate = [...planned, currentTarget];
91
+ const plans = [];
92
+ const seen = new Set();
93
+ // Deterministic cross-product order: thinking handling outermost, then task handling.
94
+ // Variants are keep/drop-all/retain-one for each non-monotone category, minus the
95
+ // keep-all/keep-all no-op; signature dedup collapses degenerate variants.
96
+ for (const thinkingExchange of THINKING_EXCHANGES) {
97
+ for (const taskExchange of TASK_EXCHANGES) {
98
+ if (!shouldBuildExchangePlan(withCandidate, thinkingExchange, taskExchange))
99
+ continue;
100
+ addExchangePlan(plans, seen, withCandidate, buildExchangePlan(transcript, withCandidate, thinkingExchange, taskExchange));
101
+ }
102
+ }
103
+ return plans;
104
+ }
105
+ function validatedExchange(transcript, planned, entryId, lastValidated) {
106
+ let best;
107
+ for (const retryTargets of exchangePlans(transcript, planned, entryId)) {
108
+ try {
109
+ const result = validateContextDeletionRequest(deletionRequestFromTargets(retryTargets), transcript);
110
+ if (lastValidated !== undefined && result.stats.tokensAfter >= lastValidated.stats.tokensAfter)
111
+ continue;
112
+ if (best === undefined || result.stats.tokensAfter < best.stats.tokensAfter)
113
+ best = result;
114
+ }
115
+ catch {
116
+ // Try the next deterministic exchange variant.
117
+ }
118
+ }
119
+ return best;
120
+ }
121
+ export function runDeterministicContextEviction(transcript, tokenBudget) {
122
+ const relaxed = relaxTranscriptForCriticalEviction(transcript);
123
+ const latestAssistant = [...relaxed.entries].reverse().find((entry) => entry.role === "assistant");
124
+ const protectedThinkingAssistant = latestAssistant && assistantEntryHasThinkingContentBlock(latestAssistant) ? latestAssistant.entryId : undefined;
125
+ const candidates = relaxed.entries
126
+ .filter((entry) => entry.entryId !== protectedThinkingAssistant)
127
+ .filter((entry) => canDeleteTarget(relaxed, { kind: "entry", entryId: entry.entryId }))
128
+ .map((entry) => entry.entryId);
129
+ const planned = [];
130
+ const excluded = new Set();
131
+ let lastValidated;
132
+ // Hard iteration cap required by the compaction-ladder design: every compaction loop must be
133
+ // bounded (max 50) so no tier can spin indefinitely. Non-monotone validation rules can require
134
+ // local exchange: a prior thinking-bearing or task-bearing deletion can make a newer candidate
135
+ // invalid, even though replacing the prior deletion with that candidate is safe and fits better.
136
+ // Exchanges are deterministic and adopted only when validation succeeds and tokensAfter strictly
137
+ // decreases; exclusions grow monotonically, so no oscillation is possible, and the pass cap remains
138
+ // the terminal safety belt.
139
+ for (let pass = 0; pass < CONTEXT_COMPACTION_MAX_EVICTION_PASSES; pass++) {
140
+ if (hasFitBudget(lastValidated, tokenBudget))
141
+ return lastValidated;
142
+ let changed = false;
143
+ for (const entryId of candidates) {
144
+ if (hasFitBudget(lastValidated, tokenBudget))
145
+ return lastValidated;
146
+ if (planned.some((target) => target.entryId === entryId) || excluded.has(entryId))
147
+ continue;
148
+ const nextPlanned = [...planned, { kind: "entry", entryId }];
149
+ try {
150
+ lastValidated = validateContextDeletionRequest(deletionRequestFromTargets(nextPlanned), relaxed);
151
+ planned.splice(0, planned.length, ...lastValidated.deletedTargets);
152
+ changed = true;
153
+ }
154
+ catch {
155
+ const exchanged = validatedExchange(relaxed, planned, entryId, lastValidated);
156
+ if (exchanged !== undefined) {
157
+ lastValidated = exchanged;
158
+ planned.splice(0, planned.length, ...lastValidated.deletedTargets);
159
+ changed = true;
160
+ continue;
161
+ }
162
+ excluded.add(entryId);
163
+ changed = true;
164
+ }
165
+ }
166
+ if (!changed) {
167
+ throw terminalDeterministicEvictionError("candidate sweep exhausted", lastValidated, tokenBudget);
168
+ }
169
+ }
170
+ throw terminalDeterministicEvictionError(`reached ${CONTEXT_COMPACTION_MAX_EVICTION_PASSES} eviction pass cap`, lastValidated, tokenBudget);
171
+ }
172
+ //# sourceMappingURL=context-compaction-eviction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-compaction-eviction.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-eviction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAChH,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,qCAAqC,EAAE,MAAM,kCAAkC,CAAC;AAEzF,MAAM,CAAC,MAAM,sCAAsC,GAAG,EAAE,CAAC;AAEzD,SAAS,kCAAkC,CAC1C,MAAc,EACd,aAAyD,EACzD,WAAmB;IAEnB,MAAM,SAAS,GAAG,aAAa;QAC9B,CAAC,CAAC,wBAAwB,aAAa,CAAC,KAAK,CAAC,WAAW,eAAe,aAAa,CAAC,KAAK,CAAC,gBAAgB,sBAAsB,aAAa,CAAC,cAAc,CAAC,MAAM,EAAE;QACvK,CAAC,CAAC,wCAAwC,CAAC;IAC5C,OAAO,IAAI,KAAK,CACf,mDAAmD,MAAM,KAAK,SAAS,YAAY,WAAW,qCAAqC,CACnI,CAAC;AACH,CAAC;AAGD,SAAS,YAAY,CAAC,MAAkD,EAAE,WAAmB;IAC5F,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,WAAW,CAAC;AAC5G,CAAC;AAED,SAAS,8BAA8B,CAAC,UAAiC,EAAE,MAA6B;IACvG,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3F,OAAO,KAAK,EAAE,IAAI,KAAK,WAAW,IAAI,qCAAqC,CAAC,KAAK,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,wBAAwB,CAAC,UAAiC,EAAE,MAA6B;IACjG,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3F,OAAO,KAAK,KAAK,SAAS,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,eAAe,CAAC,OAAyC;IACjE,OAAO,OAAO;SACZ,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;SAC/G,IAAI,CAAC,GAAG,CAAC,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,UAAiC,EAAE,OAAe;IACrE,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;IACjF,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC;AACpD,CAAC;AAED,SAAS,kBAAkB,CAAC,UAAiC,EAAE,OAAe;IAC7E,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,aAAa,IAAI,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,kBAAkB,CAAC,UAAiC,EAAE,OAAyC;IACvG,OAAO,CAAC,GAAG,OAAO,CAAC;SACjB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;SAChE,IAAI,CAAC,CAAC,IAA2B,EAAE,KAA4B,EAAE,EAAE;QACnE,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAChH,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QACxC,OAAO,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACR,CAAC;AAED,SAAS,oBAAoB,CAAC,UAAiC,EAAE,OAAyC;IACzG,OAAO,CAAC,GAAG,OAAO,CAAC;SACjB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,8BAA8B,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;SACtE,IAAI,CAAC,CAAC,IAA2B,EAAE,KAA4B,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxJ,CAAC;AAKD,MAAM,kBAAkB,GAAgC,CAAC,UAAU,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AAClG,MAAM,cAAc,GAA4B,CAAC,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;AAE5F,SAAS,kBAAkB,CAC1B,UAAiC,EACjC,MAA6B,EAC7B,gBAAkC,EAClC,YAA0B,EAC1B,gBAAmD,EACnD,YAA+C;IAE/C,IAAI,gBAAgB,KAAK,UAAU,IAAI,8BAA8B,CAAC,UAAU,EAAE,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACxG,IAAI,gBAAgB,KAAK,eAAe,IAAI,gBAAgB,KAAK,SAAS,IAAI,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,gBAAgB,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9J,IAAI,YAAY,KAAK,UAAU,IAAI,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9F,IAAI,YAAY,KAAK,iBAAiB,IAAI,YAAY,KAAK,SAAS,IAAI,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,YAAY,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpJ,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,iBAAiB,CACzB,UAAiC,EACjC,aAA+C,EAC/C,gBAAkC,EAClC,YAA0B;IAE1B,MAAM,gBAAgB,GAAG,gBAAgB,KAAK,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5H,MAAM,YAAY,GAAG,YAAY,KAAK,iBAAiB,CAAC,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpH,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CACtC,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,CAAC,CACtG,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAC/B,aAA+C,EAC/C,gBAAkC,EAClC,YAA0B;IAE1B,IAAI,gBAAgB,KAAK,UAAU,IAAI,YAAY,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC;IACjF,IAAI,gBAAgB,KAAK,eAAe,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACjI,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,eAAe,CACvB,KAAgC,EAChC,IAAiB,EACjB,eAAiD,EACjD,OAAyC;IAEzC,IAAI,eAAe,CAAC,OAAO,CAAC,KAAK,eAAe,CAAC,eAAe,CAAC;QAAE,OAAO;IAC1E,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO;IAChC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpB,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,aAAa,CACrB,UAAiC,EACjC,OAAyC,EACzC,OAAe;IAEf,MAAM,aAAa,GAA0B,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACxE,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,EAAE,aAAa,CAAC,CAAC;IAClD,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,sFAAsF;IACtF,kFAAkF;IAClF,0EAA0E;IAC1E,KAAK,MAAM,gBAAgB,IAAI,kBAAkB,EAAE,CAAC;QACnD,KAAK,MAAM,YAAY,IAAI,cAAc,EAAE,CAAC;YAC3C,IAAI,CAAC,uBAAuB,CAAC,aAAa,EAAE,gBAAgB,EAAE,YAAY,CAAC;gBAAE,SAAS;YACtF,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,iBAAiB,CAAC,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC;QAC3H,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,iBAAiB,CACzB,UAAiC,EACjC,OAAyC,EACzC,OAAe,EACf,aAAyD;IAEzD,IAAI,IAAgD,CAAC;IACrD,KAAK,MAAM,YAAY,IAAI,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,8BAA8B,CAAC,0BAA0B,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,CAAC;YACpG,IAAI,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,aAAa,CAAC,KAAK,CAAC,WAAW;gBAAE,SAAS;YACzG,IAAI,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;gBAAE,IAAI,GAAG,MAAM,CAAC;QAC5F,CAAC;QAAC,MAAM,CAAC;YACR,+CAA+C;QAChD,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC9C,UAAiC,EACjC,WAAmB;IAEnB,MAAM,OAAO,GAAG,kCAAkC,CAAC,UAAU,CAAC,CAAC;IAC/D,MAAM,eAAe,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IACnG,MAAM,0BAA0B,GAAG,eAAe,IAAI,qCAAqC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACnJ,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO;SAChC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,0BAA0B,CAAC;SAC/D,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;SACtF,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,IAAI,aAAyD,CAAC;IAE9D,6FAA6F;IAC7F,+FAA+F;IAC/F,+FAA+F;IAC/F,iGAAiG;IACjG,iGAAiG;IACjG,oGAAoG;IACpG,4BAA4B;IAC5B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,sCAAsC,EAAE,IAAI,EAAE,EAAE,CAAC;QAC1E,IAAI,YAAY,CAAC,aAAa,EAAE,WAAW,CAAC;YAAE,OAAO,aAAa,CAAC;QACnE,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;YAClC,IAAI,YAAY,CAAC,aAAa,EAAE,WAAW,CAAC;gBAAE,OAAO,aAAa,CAAC;YACnE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YAC5F,MAAM,WAAW,GAA4B,CAAC,GAAG,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACtF,IAAI,CAAC;gBACJ,aAAa,GAAG,8BAA8B,CAAC,0BAA0B,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;gBACjG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;gBACnE,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;YAAC,MAAM,CAAC;gBACR,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;gBAC9E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;oBAC7B,aAAa,GAAG,SAAS,CAAC;oBAC1B,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;oBACnE,OAAO,GAAG,IAAI,CAAC;oBACf,SAAS;gBACV,CAAC;gBACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACtB,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;QACF,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,kCAAkC,CAAC,2BAA2B,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;QACnG,CAAC;IACF,CAAC;IACD,MAAM,kCAAkC,CACvC,WAAW,sCAAsC,oBAAoB,EACrE,aAAa,EACb,WAAW,CACX,CAAC;AACH,CAAC","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript, ValidatedContextDeletionResult } from \"./context-compaction-types.ts\";\nimport { validateContextDeletionRequest } from \"./context-deletion-application.ts\";\nimport { canDeleteTarget, deletionRequestFromTargets, isTaskBearingEntry } from \"./context-deletion-targets.ts\";\nimport { relaxTranscriptForCriticalEviction } from \"./context-compaction-critical.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\n\nexport const CONTEXT_COMPACTION_MAX_EVICTION_PASSES = 50;\n\nfunction terminalDeterministicEvictionError(\n\treason: string,\n\tlastValidated: ValidatedContextDeletionResult | undefined,\n\ttokenBudget: number,\n): Error {\n\tconst statsText = lastValidated\n\t\t? `achieved tokensAfter=${lastValidated.stats.tokensAfter}, reduction=${lastValidated.stats.percentReduction}%, deletionTargets=${lastValidated.deletedTargets.length}`\n\t\t: \"achieved no validated deletion targets\";\n\treturn new Error(\n\t\t`Context deterministic overflow eviction failed: ${reason}; ${statsText}; budget=${tokenBudget}; nothing more was safely deletable`,\n\t);\n}\n\n\nfunction hasFitBudget(result: ValidatedContextDeletionResult | undefined, tokenBudget: number): result is ValidatedContextDeletionResult {\n\treturn result !== undefined && result.deletedTargets.length > 0 && result.stats.tokensAfter <= tokenBudget;\n}\n\nfunction isThinkingAssistantEntryTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tif (target.kind !== \"entry\") return false;\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\treturn entry?.role === \"assistant\" && assistantEntryHasThinkingContentBlock(entry);\n}\n\nfunction isTaskBearingEntryTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tif (target.kind !== \"entry\") return false;\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\treturn entry !== undefined && isTaskBearingEntry(entry);\n}\n\nfunction targetSignature(targets: readonly ContextDeletionTarget[]): string {\n\treturn targets\n\t\t.map((target) => `${target.kind}:${target.entryId}:${target.kind === \"content_block\" ? target.blockIndex : \"\"}`)\n\t\t.join(\"|\");\n}\n\nfunction entryOrder(transcript: CompactableTranscript, entryId: string): number {\n\tconst index = transcript.entries.findIndex((entry) => entry.entryId === entryId);\n\treturn index < 0 ? Number.MAX_SAFE_INTEGER : index;\n}\n\nfunction entryTokenEstimate(transcript: CompactableTranscript, entryId: string): number {\n\treturn transcript.entries.find((entry) => entry.entryId === entryId)?.tokenEstimate ?? 0;\n}\n\nfunction smallestTaskTarget(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): ContextDeletionTarget | undefined {\n\treturn [...targets]\n\t\t.filter((target) => isTaskBearingEntryTarget(transcript, target))\n\t\t.sort((left: ContextDeletionTarget, right: ContextDeletionTarget) => {\n\t\t\tconst tokenDelta = entryTokenEstimate(transcript, left.entryId) - entryTokenEstimate(transcript, right.entryId);\n\t\t\tif (tokenDelta !== 0) return tokenDelta;\n\t\t\treturn entryOrder(transcript, left.entryId) - entryOrder(transcript, right.entryId);\n\t\t})[0];\n}\n\nfunction newestThinkingTarget(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): ContextDeletionTarget | undefined {\n\treturn [...targets]\n\t\t.filter((target) => isThinkingAssistantEntryTarget(transcript, target))\n\t\t.sort((left: ContextDeletionTarget, right: ContextDeletionTarget) => entryOrder(transcript, right.entryId) - entryOrder(transcript, left.entryId))[0];\n}\n\ntype ThinkingExchange = \"keep-all\" | \"drop-all\" | \"retain-newest\";\ntype TaskExchange = \"keep-all\" | \"drop-all\" | \"retain-smallest\";\n\nconst THINKING_EXCHANGES: readonly ThinkingExchange[] = [\"keep-all\", \"drop-all\", \"retain-newest\"];\nconst TASK_EXCHANGES: readonly TaskExchange[] = [\"keep-all\", \"drop-all\", \"retain-smallest\"];\n\nfunction shouldDeleteTarget(\n\ttranscript: CompactableTranscript,\n\ttarget: ContextDeletionTarget,\n\tthinkingExchange: ThinkingExchange,\n\ttaskExchange: TaskExchange,\n\tretainedThinking: ContextDeletionTarget | undefined,\n\tretainedTask: ContextDeletionTarget | undefined,\n): boolean {\n\tif (thinkingExchange === \"drop-all\" && isThinkingAssistantEntryTarget(transcript, target)) return false;\n\tif (thinkingExchange === \"retain-newest\" && retainedThinking !== undefined && targetSignature([target]) === targetSignature([retainedThinking])) return false;\n\tif (taskExchange === \"drop-all\" && isTaskBearingEntryTarget(transcript, target)) return false;\n\tif (taskExchange === \"retain-smallest\" && retainedTask !== undefined && targetSignature([target]) === targetSignature([retainedTask])) return false;\n\treturn true;\n}\n\nfunction buildExchangePlan(\n\ttranscript: CompactableTranscript,\n\twithCandidate: readonly ContextDeletionTarget[],\n\tthinkingExchange: ThinkingExchange,\n\ttaskExchange: TaskExchange,\n): ContextDeletionTarget[] {\n\tconst retainedThinking = thinkingExchange === \"retain-newest\" ? newestThinkingTarget(transcript, withCandidate) : undefined;\n\tconst retainedTask = taskExchange === \"retain-smallest\" ? smallestTaskTarget(transcript, withCandidate) : undefined;\n\treturn withCandidate.filter((target) =>\n\t\tshouldDeleteTarget(transcript, target, thinkingExchange, taskExchange, retainedThinking, retainedTask),\n\t);\n}\n\nfunction shouldBuildExchangePlan(\n\twithCandidate: readonly ContextDeletionTarget[],\n\tthinkingExchange: ThinkingExchange,\n\ttaskExchange: TaskExchange,\n): boolean {\n\tif (thinkingExchange === \"keep-all\" && taskExchange === \"keep-all\") return false;\n\tif (thinkingExchange === \"retain-newest\" && withCandidate.filter((target) => target.kind === \"entry\").length === 0) return false;\n\treturn true;\n}\n\nfunction addExchangePlan(\n\tplans: ContextDeletionTarget[][],\n\tseen: Set<string>,\n\toriginalTargets: readonly ContextDeletionTarget[],\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tif (targetSignature(targets) === targetSignature(originalTargets)) return;\n\tconst signature = targetSignature(targets);\n\tif (seen.has(signature)) return;\n\tseen.add(signature);\n\tplans.push([...targets]);\n}\n\nfunction exchangePlans(\n\ttranscript: CompactableTranscript,\n\tplanned: readonly ContextDeletionTarget[],\n\tentryId: string,\n): ContextDeletionTarget[][] {\n\tconst currentTarget: ContextDeletionTarget = { kind: \"entry\", entryId };\n\tconst withCandidate = [...planned, currentTarget];\n\tconst plans: ContextDeletionTarget[][] = [];\n\tconst seen = new Set<string>();\n\t// Deterministic cross-product order: thinking handling outermost, then task handling.\n\t// Variants are keep/drop-all/retain-one for each non-monotone category, minus the\n\t// keep-all/keep-all no-op; signature dedup collapses degenerate variants.\n\tfor (const thinkingExchange of THINKING_EXCHANGES) {\n\t\tfor (const taskExchange of TASK_EXCHANGES) {\n\t\t\tif (!shouldBuildExchangePlan(withCandidate, thinkingExchange, taskExchange)) continue;\n\t\t\taddExchangePlan(plans, seen, withCandidate, buildExchangePlan(transcript, withCandidate, thinkingExchange, taskExchange));\n\t\t}\n\t}\n\treturn plans;\n}\n\nfunction validatedExchange(\n\ttranscript: CompactableTranscript,\n\tplanned: readonly ContextDeletionTarget[],\n\tentryId: string,\n\tlastValidated: ValidatedContextDeletionResult | undefined,\n): ValidatedContextDeletionResult | undefined {\n\tlet best: ValidatedContextDeletionResult | undefined;\n\tfor (const retryTargets of exchangePlans(transcript, planned, entryId)) {\n\t\ttry {\n\t\t\tconst result = validateContextDeletionRequest(deletionRequestFromTargets(retryTargets), transcript);\n\t\t\tif (lastValidated !== undefined && result.stats.tokensAfter >= lastValidated.stats.tokensAfter) continue;\n\t\t\tif (best === undefined || result.stats.tokensAfter < best.stats.tokensAfter) best = result;\n\t\t} catch {\n\t\t\t// Try the next deterministic exchange variant.\n\t\t}\n\t}\n\treturn best;\n}\n\nexport function runDeterministicContextEviction(\n\ttranscript: CompactableTranscript,\n\ttokenBudget: number,\n): ValidatedContextDeletionResult {\n\tconst relaxed = relaxTranscriptForCriticalEviction(transcript);\n\tconst latestAssistant = [...relaxed.entries].reverse().find((entry) => entry.role === \"assistant\");\n\tconst protectedThinkingAssistant = latestAssistant && assistantEntryHasThinkingContentBlock(latestAssistant) ? latestAssistant.entryId : undefined;\n\tconst candidates = relaxed.entries\n\t\t.filter((entry) => entry.entryId !== protectedThinkingAssistant)\n\t\t.filter((entry) => canDeleteTarget(relaxed, { kind: \"entry\", entryId: entry.entryId }))\n\t\t.map((entry) => entry.entryId);\n\tconst planned: ContextDeletionTarget[] = [];\n\tconst excluded = new Set<string>();\n\tlet lastValidated: ValidatedContextDeletionResult | undefined;\n\n\t// Hard iteration cap required by the compaction-ladder design: every compaction loop must be\n\t// bounded (max 50) so no tier can spin indefinitely. Non-monotone validation rules can require\n\t// local exchange: a prior thinking-bearing or task-bearing deletion can make a newer candidate\n\t// invalid, even though replacing the prior deletion with that candidate is safe and fits better.\n\t// Exchanges are deterministic and adopted only when validation succeeds and tokensAfter strictly\n\t// decreases; exclusions grow monotonically, so no oscillation is possible, and the pass cap remains\n\t// the terminal safety belt.\n\tfor (let pass = 0; pass < CONTEXT_COMPACTION_MAX_EVICTION_PASSES; pass++) {\n\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t\tlet changed = false;\n\t\tfor (const entryId of candidates) {\n\t\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t\t\tif (planned.some((target) => target.entryId === entryId) || excluded.has(entryId)) continue;\n\t\t\tconst nextPlanned: ContextDeletionTarget[] = [...planned, { kind: \"entry\", entryId }];\n\t\t\ttry {\n\t\t\t\tlastValidated = validateContextDeletionRequest(deletionRequestFromTargets(nextPlanned), relaxed);\n\t\t\t\tplanned.splice(0, planned.length, ...lastValidated.deletedTargets);\n\t\t\t\tchanged = true;\n\t\t\t} catch {\n\t\t\t\tconst exchanged = validatedExchange(relaxed, planned, entryId, lastValidated);\n\t\t\t\tif (exchanged !== undefined) {\n\t\t\t\t\tlastValidated = exchanged;\n\t\t\t\t\tplanned.splice(0, planned.length, ...lastValidated.deletedTargets);\n\t\t\t\t\tchanged = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\texcluded.add(entryId);\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\tif (!changed) {\n\t\t\tthrow terminalDeterministicEvictionError(\"candidate sweep exhausted\", lastValidated, tokenBudget);\n\t\t}\n\t}\n\tthrow terminalDeterministicEvictionError(\n\t\t`reached ${CONTEXT_COMPACTION_MAX_EVICTION_PASSES} eviction pass cap`,\n\t\tlastValidated,\n\t\ttokenBudget,\n\t);\n}\n"]}
@@ -1,5 +1,11 @@
1
1
  import { type ThinkingLevel } from "@earendil-works/pi-agent-core";
2
2
  import type { Api, Model } from "@earendil-works/pi-ai/compat";
3
3
  import type { ContextCompactionPreparation, ValidatedContextDeletionResult } from "./context-compaction-types.ts";
4
- export declare function contextCompact(preparation: ContextCompactionPreparation, model: Model<Api>, apiKey: string, headers?: Record<string, string>, signal?: AbortSignal, thinkingLevel?: ThinkingLevel): Promise<ValidatedContextDeletionResult>;
4
+ export declare const CONTEXT_COMPACTION_MAX_TURNS = 50;
5
+ export declare const CONTEXT_COMPACTION_MAX_PLANNER_NUDGES = 50;
6
+ export interface ContextCompactionLadderOptions {
7
+ acceptanceTokenBudget?: number;
8
+ criticalEvictionTokenBudget?: number;
9
+ }
10
+ export declare function contextCompact(preparation: ContextCompactionPreparation, model: Model<Api>, apiKey: string, headers?: Record<string, string>, signal?: AbortSignal, thinkingLevel?: ThinkingLevel, ladder?: ContextCompactionLadderOptions): Promise<ValidatedContextDeletionResult>;
5
11
  //# sourceMappingURL=context-compaction-runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-runner.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,KAAK,EAAE,GAAG,EAAoB,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAGjF,OAAO,KAAK,EAGX,4BAA4B,EAC5B,8BAA8B,EAC9B,MAAM,+BAA+B,CAAC;AAoOvC,wBAAsB,cAAc,CACnC,WAAW,EAAE,4BAA4B,EACzC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,MAAM,CAAC,EAAE,WAAW,EACpB,aAAa,GAAE,aAAqB,GAClC,OAAO,CAAC,8BAA8B,CAAC,CAoBzC","sourcesContent":["import { Agent, type AgentMessage, type ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, AssistantMessage, Model } from \"@earendil-works/pi-ai/compat\";\nimport { createAssistantMessageEventStream, isContextOverflow, streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport { formatCopilotProviderError } from \"../copilot-errors.ts\";\nimport type {\n\tCompactableTranscript,\n\tContextCompactionParameters,\n\tContextCompactionPreparation,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { CONTEXT_COMPACTION_AUTO_QUERY } from \"./context-compaction-types.ts\";\nimport {\n\tcreateContextCompactionBudgetDetails,\n\tcontextCompactionProgressKey,\n\tcontextCompactionProgressPercent,\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetMet,\n\tformatErrorMessage,\n} from \"./context-compaction-metrics.ts\";\nimport {\n\tgetTranscriptCompactionParameters,\n\tnormalizeContextCompactionParameters,\n} from \"./context-compaction-strategy.ts\";\nimport {\n\tCONTEXT_COMPACTION_BUDGET_TOOL_NAME,\n\tCONTEXT_DELETE_TOOL_NAME,\n\tCONTEXT_GREP_DELETE_TOOL_NAME,\n\tCONTEXT_READ_ENTRY_TOOL_NAME,\n\tCONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { createContextDeletionTool } from \"./context-deletion-tools.ts\";\nimport {\n\tbuildContextCompactionPrompt,\n\tCONTEXT_COMPACTION_SYSTEM_PROMPT,\n\twriteContextCompactionTranscriptFile,\n} from \"./context-compaction-prompt.ts\";\n\nfunction createContextCompactionTargetNudgeMessage(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tparameters: ContextCompactionParameters,\n): AgentMessage {\n\tconst currentReductionPercent = contextCompactionProgressPercent(result);\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tconst tokensToDelete = result\n\t\t? createContextCompactionBudgetDetails(result.stats, 0, undefined, parameters, 0, 0).tokensToDeleteForTarget\n\t\t: undefined;\n\tconst remainingText = tokensToDelete !== undefined ? ` Delete about ${tokensToDelete} more token(s) if safe candidates exist.` : \"\";\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `The strict ${targetLabel} context-reduction requirement is not met yet; current validated reduction is ${currentReductionPercent}%.${remainingText} Continue removing low-value message entries or message content blocks using ${CONTEXT_DELETE_TOOL_NAME} or ${CONTEXT_GREP_DELETE_TOOL_NAME}. Use the focus query ${JSON.stringify(parameters.query)} to preserve relevant context. Call ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME} to verify progress, and do not provide a final answer until the validated reduction is at least ${targetLabel}.`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.now(),\n\t};\n}\nfunction createContextCompactionAssistantMessage(\n\tmodel: Model<Api>,\n\tcontent: AssistantMessage[\"content\"],\n\tstopReason: AssistantMessage[\"stopReason\"],\n\terrorMessage?: string,\n): AssistantMessage {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: {\n\t\t\tinput: 0,\n\t\t\toutput: 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t},\n\t\tstopReason,\n\t\t...(errorMessage !== undefined ? { errorMessage } : {}),\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createContextCompactionStopStream(model: Model<Api>, text: string) {\n\tconst stream = createAssistantMessageEventStream();\n\tqueueMicrotask(() => {\n\t\tconst message = createContextCompactionAssistantMessage(model, [{ type: \"text\", text }], \"stop\");\n\t\tstream.push({ type: \"done\", reason: \"stop\", message });\n\t\tstream.end(message);\n\t});\n\treturn stream;\n}\n\nfunction isContextCompactionOverflowError(model: Model<Api>, errorMessage: string): boolean {\n\treturn isContextOverflow(\n\t\tcreateContextCompactionAssistantMessage(model, [], \"error\", errorMessage),\n\t\tmodel.contextWindow,\n\t);\n}\n\ninterface ContextDeletionRun {\n\tvalidatedResult: ValidatedContextDeletionResult | undefined;\n\tlastToolError: string | undefined;\n\tproviderError: string | undefined;\n}\n\nasync function runContextDeletionAssistant(\n\tinputTranscript: CompactableTranscript,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(inputTranscript),\n): Promise<ContextDeletionRun> {\n\tconst transcript: CompactableTranscript = { ...inputTranscript, parameters };\n\tconst maxTokens = model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY;\n\tif (signal?.aborted) {\n\t\tthrow new Error(\"Context compaction failed: Request was aborted\");\n\t}\n\tconst transcriptFile = writeContextCompactionTranscriptFile(transcript);\n\tconst promptMessage: AgentMessage = {\n\t\trole: \"user\",\n\t\tcontent: [{ type: \"text\", text: buildContextCompactionPrompt(transcript, transcriptFile.path, parameters) }],\n\t\ttimestamp: Date.now(),\n\t};\n\tconst deletionTool = createContextDeletionTool(transcript, { contextWindow: model.contextWindow, ...parameters });\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: CONTEXT_COMPACTION_SYSTEM_PROMPT,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: deletionTool.tools,\n\t\t},\n\t\ttoolExecution: \"parallel\",\n\t\tstreamFn: async (requestModel, context, streamOptions) => {\n\t\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\t\tif (contextCompactionTargetMet(currentResult, parameters)) {\n\t\t\t\treturn createContextCompactionStopStream(\n\t\t\t\t\trequestModel,\n\t\t\t\t\t`Reached the strict ${contextCompactionTargetLabel(parameters)} context-reduction requirement (${currentResult.stats.percentReduction}%); using the validated deletions recorded so far.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn streamSimple(requestModel, context, {\n\t\t\t\t...streamOptions,\n\t\t\t\tmaxTokens,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers ?? streamOptions?.headers,\n\t\t\t});\n\t\t},\n\t});\n\n\tlet lastNudgedProgressKey: string | undefined;\n\tconst unsubscribeNudge = agent.subscribe((event, eventSignal) => {\n\t\tif (event.type !== \"turn_end\" || signal?.aborted || eventSignal.aborted) return;\n\t\tif (event.message.role !== \"assistant\") return;\n\t\tif (event.message.stopReason === \"error\" || event.message.stopReason === \"aborted\") return;\n\t\tif (event.message.content.some((content) => content.type === \"toolCall\")) return;\n\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\tif (contextCompactionTargetMet(currentResult, parameters)) return;\n\t\tconst progressKey = contextCompactionProgressKey(currentResult);\n\t\tif (progressKey === lastNudgedProgressKey) return;\n\t\tlastNudgedProgressKey = progressKey;\n\t\tagent.followUp(createContextCompactionTargetNudgeMessage(currentResult, parameters));\n\t});\n\n\tconst abortOnSignal = () => agent.abort();\n\tsignal?.addEventListener(\"abort\", abortOnSignal, { once: true });\n\ttry {\n\t\tawait agent.prompt(promptMessage);\n\t} catch (error) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Context compaction failed: Request was aborted\");\n\t\t}\n\t\tthrow new Error(`Context compaction failed: ${formatCopilotProviderError(model.provider, formatErrorMessage(error))}`);\n\t} finally {\n\t\tsignal?.removeEventListener(\"abort\", abortOnSignal);\n\t\tunsubscribeNudge();\n\t\ttranscriptFile.cleanup();\n\t}\n\n\tif (signal?.aborted) {\n\t\tthrow new Error(\"Context compaction failed: Request was aborted\");\n\t}\n\tif (agent.state.errorMessage) {\n\t\tconst formattedErrorMessage = formatCopilotProviderError(model.provider, agent.state.errorMessage);\n\t\tif (isContextCompactionOverflowError(model, agent.state.errorMessage)) {\n\t\t\treturn {\n\t\t\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\t\t\tlastToolError: deletionTool.getLastError(),\n\t\t\t\tproviderError: formattedErrorMessage === agent.state.errorMessage ? undefined : formattedErrorMessage,\n\t\t\t};\n\t\t}\n\t\tthrow new Error(`Context compaction failed: ${formattedErrorMessage}`);\n\t}\n\tif (deletionTool.getCallCount() === 0) {\n\t\tthrow new Error(\n\t\t\t`Context compaction did not call any transcript inspection, budget, or deletion tools (${CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME}, ${CONTEXT_READ_ENTRY_TOOL_NAME}, ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME}, ${CONTEXT_DELETE_TOOL_NAME}, or ${CONTEXT_GREP_DELETE_TOOL_NAME})`,\n\t\t);\n\t}\n\treturn {\n\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\tlastToolError: deletionTool.getLastError(),\n\t\tproviderError: undefined,\n\t};\n}\n\nfunction hasMetContextCompactionTarget(\n\trun: ContextDeletionRun,\n\tparameters: ContextCompactionParameters,\n): run is ContextDeletionRun & { validatedResult: ValidatedContextDeletionResult } {\n\treturn contextCompactionTargetMet(run.validatedResult, parameters);\n}\n\nfunction formatContextCompactionTargetFailureMessage(\n\tattempts: readonly ContextDeletionRunAttempt[],\n\tparameters: ContextCompactionParameters,\n): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tif (attempts.length === 0) {\n\t\treturn `Context compaction did not meet the strict ${targetLabel} reduction requirement`;\n\t}\n\tconst attemptDetails = attempts\n\t\t.map((attempt) => {\n\t\t\tconst reduction = contextCompactionProgressPercent(attempt.validatedResult);\n\t\t\tconst deletionCount = attempt.validatedResult?.deletedTargets.length ?? 0;\n\t\t\tconst toolErrorText = attempt.lastToolError ? `; last deletion tool error: ${attempt.lastToolError}` : \"\";\n\t\t\tconst providerErrorText = attempt.providerError ? `; provider error: ${attempt.providerError}` : \"\";\n\t\t\treturn `attempt reached ${reduction}% with ${deletionCount} validated deletion target(s)${toolErrorText}${providerErrorText}`;\n\t\t})\n\t\t.join(\"; \");\n\treturn `Context compaction did not meet the strict ${targetLabel} reduction requirement; ${attemptDetails}`;\n}\n\ninterface ContextDeletionRunAttempt extends ContextDeletionRun {}\n\nexport async function contextCompact(\n\tpreparation: ContextCompactionPreparation,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n): Promise<ValidatedContextDeletionResult> {\n\tconst parameters = normalizeContextCompactionParameters(\n\t\tpreparation.parameters ?? preparation.transcript.parameters,\n\t\tpreparation.parameters?.query ?? preparation.transcript.parameters?.query ?? CONTEXT_COMPACTION_AUTO_QUERY,\n\t);\n\tconst transcript: CompactableTranscript = { ...preparation.transcript, parameters };\n\tconst attempts: ContextDeletionRunAttempt[] = [];\n\tconst standardRun = await runContextDeletionAssistant(\n\t\ttranscript,\n\t\tmodel,\n\t\tapiKey,\n\t\theaders,\n\t\tsignal,\n\t\tthinkingLevel,\n\t\tparameters,\n\t);\n\tif (hasMetContextCompactionTarget(standardRun, parameters)) return standardRun.validatedResult;\n\tattempts.push({ ...standardRun });\n\n\tthrow new Error(formatContextCompactionTargetFailureMessage(attempts, parameters));\n}\n"]}
1
+ {"version":3,"file":"context-compaction-runner.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,KAAK,EAAE,GAAG,EAAoB,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAGjF,OAAO,KAAK,EAGX,4BAA4B,EAC5B,8BAA8B,EAC9B,MAAM,+BAA+B,CAAC;AA+BvC,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAC/C,eAAO,MAAM,qCAAqC,KAAK,CAAC;AAExD,MAAM,WAAW,8BAA8B;IAC9C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACrC;AA4PD,wBAAsB,cAAc,CACnC,WAAW,EAAE,4BAA4B,EACzC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,MAAM,CAAC,EAAE,WAAW,EACpB,aAAa,GAAE,aAAqB,EACpC,MAAM,CAAC,EAAE,8BAA8B,GACrC,OAAO,CAAC,8BAA8B,CAAC,CAqDzC","sourcesContent":["import { Agent, type AgentMessage, type ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, AssistantMessage, Model } from \"@earendil-works/pi-ai/compat\";\nimport { createAssistantMessageEventStream, isContextOverflow, streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport { formatCopilotProviderError } from \"../copilot-errors.ts\";\nimport type {\n\tCompactableTranscript,\n\tContextCompactionParameters,\n\tContextCompactionPreparation,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { CONTEXT_COMPACTION_AUTO_QUERY } from \"./context-compaction-types.ts\";\nimport {\n\tcreateContextCompactionBudgetDetails,\n\tcontextCompactionProgressKey,\n\tcontextCompactionProgressPercent,\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetMet,\n\tformatErrorMessage,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters, normalizeContextCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport {\n\tCONTEXT_COMPACTION_BUDGET_TOOL_NAME,\n\tCONTEXT_DELETE_TOOL_NAME,\n\tCONTEXT_GREP_DELETE_TOOL_NAME,\n\tCONTEXT_READ_ENTRY_TOOL_NAME,\n\tCONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { createContextDeletionTool } from \"./context-deletion-tools.ts\";\nimport {\n\tbuildContextCompactionPrompt,\n\tCONTEXT_COMPACTION_SYSTEM_PROMPT,\n\twriteContextCompactionTranscriptFile,\n} from \"./context-compaction-prompt.ts\";\nimport {\n\tCONTEXT_COMPACTION_CRITICAL_OVERFLOW_PROMPT,\n\tcriticalCompactionParameters,\n\trelaxTranscriptForCriticalEviction,\n} from \"./context-compaction-critical.ts\";\nimport { runDeterministicContextEviction } from \"./context-compaction-eviction.ts\";\n\nexport const CONTEXT_COMPACTION_MAX_TURNS = 50;\nexport const CONTEXT_COMPACTION_MAX_PLANNER_NUDGES = 50;\n\nexport interface ContextCompactionLadderOptions {\n\tacceptanceTokenBudget?: number;\n\tcriticalEvictionTokenBudget?: number;\n}\n\ninterface ContextDeletionAssistantOptions {\n\tpromptSuffix?: string;\n\tacceptanceTokenBudget?: number;\n}\n\nfunction createContextCompactionTargetNudgeMessage(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tparameters: ContextCompactionParameters,\n): AgentMessage {\n\tconst currentReductionPercent = contextCompactionProgressPercent(result);\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tconst tokensToDelete = result\n\t\t? createContextCompactionBudgetDetails(result.stats, 0, undefined, parameters, 0, 0).tokensToDeleteForTarget\n\t\t: undefined;\n\tconst remainingText = tokensToDelete !== undefined ? ` Delete about ${tokensToDelete} more token(s) if safe candidates exist.` : \"\";\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `The strict ${targetLabel} context-reduction requirement is not met yet; current validated reduction is ${currentReductionPercent}%.${remainingText} Continue removing low-value message entries or message content blocks using ${CONTEXT_DELETE_TOOL_NAME} or ${CONTEXT_GREP_DELETE_TOOL_NAME}. Use the focus query ${JSON.stringify(parameters.query)} to preserve relevant context. Call ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME} to verify progress, and do not provide a final answer until the validated reduction is at least ${targetLabel}.`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createContextCompactionAssistantMessage(\n\tmodel: Model<Api>,\n\tcontent: AssistantMessage[\"content\"],\n\tstopReason: AssistantMessage[\"stopReason\"],\n\terrorMessage?: string,\n): AssistantMessage {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: {\n\t\t\tinput: 0,\n\t\t\toutput: 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t},\n\t\tstopReason,\n\t\t...(errorMessage !== undefined ? { errorMessage } : {}),\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createContextCompactionStopStream(model: Model<Api>, text: string) {\n\tconst stream = createAssistantMessageEventStream();\n\tqueueMicrotask(() => {\n\t\tconst message = createContextCompactionAssistantMessage(model, [{ type: \"text\", text }], \"stop\");\n\t\tstream.push({ type: \"done\", reason: \"stop\", message });\n\t\tstream.end(message);\n\t});\n\treturn stream;\n}\n\nfunction isContextCompactionOverflowError(model: Model<Api>, errorMessage: string): boolean {\n\treturn isContextOverflow(createContextCompactionAssistantMessage(model, [], \"error\", errorMessage), model.contextWindow);\n}\n\nfunction feasibleAccepted(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tacceptanceTokenBudget: number | undefined,\n): result is ValidatedContextDeletionResult {\n\treturn (\n\t\tacceptanceTokenBudget !== undefined &&\n\t\tresult !== undefined &&\n\t\tresult.deletedTargets.length > 0 &&\n\t\tresult.stats.tokensAfter <= acceptanceTokenBudget\n\t);\n}\n\nfunction acceptedWithinRun(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tparameters: ContextCompactionParameters,\n\tacceptanceTokenBudget: number | undefined,\n): result is ValidatedContextDeletionResult {\n\tif (acceptanceTokenBudget !== undefined) return feasibleAccepted(result, acceptanceTokenBudget);\n\treturn contextCompactionTargetMet(result, parameters);\n}\n\nfunction targetMetAcceptedForLadder(\n\trun: ContextDeletionRun,\n\tparameters: ContextCompactionParameters,\n\tladder: ContextCompactionLadderOptions | undefined,\n): run is ContextDeletionRun & { validatedResult: ValidatedContextDeletionResult } {\n\tif (!hasMetContextCompactionTarget(run, parameters)) return false;\n\tconst overflowBudget = ladder?.criticalEvictionTokenBudget;\n\treturn overflowBudget === undefined || run.validatedResult.stats.tokensAfter <= overflowBudget;\n}\n\ninterface ContextDeletionRun {\n\tvalidatedResult: ValidatedContextDeletionResult | undefined;\n\tlastToolError: string | undefined;\n\tproviderError: string | undefined;\n}\n\nasync function runContextDeletionAssistant(\n\tinputTranscript: CompactableTranscript,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(inputTranscript),\n\toptions: ContextDeletionAssistantOptions = {},\n): Promise<ContextDeletionRun> {\n\tconst transcript: CompactableTranscript = { ...inputTranscript, parameters };\n\tconst maxTokens = model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY;\n\tif (signal?.aborted) throw new Error(\"Context compaction failed: Request was aborted\");\n\tconst transcriptFile = writeContextCompactionTranscriptFile(transcript);\n\tconst promptText = buildContextCompactionPrompt(transcript, transcriptFile.path, parameters) + (options.promptSuffix ?? \"\");\n\tconst promptMessage: AgentMessage = {\n\t\trole: \"user\",\n\t\tcontent: [{ type: \"text\", text: promptText }],\n\t\ttimestamp: Date.now(),\n\t};\n\tconst deletionTool = createContextDeletionTool(transcript, { contextWindow: model.contextWindow, ...parameters });\n\tlet providerTurnCount = 0;\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: CONTEXT_COMPACTION_SYSTEM_PROMPT,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: deletionTool.tools,\n\t\t},\n\t\ttoolExecution: \"parallel\",\n\t\tstreamFn: async (requestModel, context, streamOptions) => {\n\t\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\t\tif (acceptedWithinRun(currentResult, parameters, options.acceptanceTokenBudget)) {\n\t\t\t\treturn createContextCompactionStopStream(\n\t\t\t\t\trequestModel,\n\t\t\t\t\t`Reached an acceptable context-reduction result (${currentResult.stats.percentReduction}%, ${currentResult.stats.tokensAfter} token(s) after deletion); using the validated deletions recorded so far.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (providerTurnCount >= CONTEXT_COMPACTION_MAX_TURNS) {\n\t\t\t\treturn createContextCompactionStopStream(\n\t\t\t\t\trequestModel,\n\t\t\t\t\t`Reached the context compaction turn cap (${CONTEXT_COMPACTION_MAX_TURNS}); using the validated deletions recorded so far.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tproviderTurnCount += 1;\n\t\t\treturn streamSimple(requestModel, context, {\n\t\t\t\t...streamOptions,\n\t\t\t\tmaxTokens,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers ?? streamOptions?.headers,\n\t\t\t});\n\t\t},\n\t});\n\n\tlet lastNudgedProgressKey: string | undefined;\n\tlet nudgeCount = 0;\n\tconst unsubscribeNudge = agent.subscribe((event, eventSignal) => {\n\t\tif (event.type !== \"turn_end\" || signal?.aborted || eventSignal.aborted) return;\n\t\tif (event.message.role !== \"assistant\") return;\n\t\tif (event.message.stopReason === \"error\" || event.message.stopReason === \"aborted\") return;\n\t\tif (event.message.content.some((content) => content.type === \"toolCall\")) return;\n\t\tif (nudgeCount >= CONTEXT_COMPACTION_MAX_PLANNER_NUDGES) return;\n\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\tif (acceptedWithinRun(currentResult, parameters, options.acceptanceTokenBudget)) return;\n\t\tconst progressKey = contextCompactionProgressKey(currentResult);\n\t\tif (progressKey === lastNudgedProgressKey) return;\n\t\tlastNudgedProgressKey = progressKey;\n\t\tnudgeCount += 1;\n\t\tagent.followUp(createContextCompactionTargetNudgeMessage(currentResult, parameters));\n\t});\n\n\tconst abortOnSignal = () => agent.abort();\n\tsignal?.addEventListener(\"abort\", abortOnSignal, { once: true });\n\ttry {\n\t\tawait agent.prompt(promptMessage);\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Context compaction failed: Request was aborted\");\n\t\tthrow new Error(`Context compaction failed: ${formatCopilotProviderError(model.provider, formatErrorMessage(error))}`);\n\t} finally {\n\t\tsignal?.removeEventListener(\"abort\", abortOnSignal);\n\t\tunsubscribeNudge();\n\t\ttranscriptFile.cleanup();\n\t}\n\n\tif (signal?.aborted) throw new Error(\"Context compaction failed: Request was aborted\");\n\tif (agent.state.errorMessage) {\n\t\tconst formattedErrorMessage = formatCopilotProviderError(model.provider, agent.state.errorMessage);\n\t\tif (isContextCompactionOverflowError(model, agent.state.errorMessage)) {\n\t\t\treturn {\n\t\t\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\t\t\tlastToolError: deletionTool.getLastError(),\n\t\t\t\tproviderError: formattedErrorMessage === agent.state.errorMessage ? undefined : formattedErrorMessage,\n\t\t\t};\n\t\t}\n\t\tthrow new Error(`Context compaction failed: ${formattedErrorMessage}`);\n\t}\n\tif (deletionTool.getCallCount() === 0) {\n\t\tthrow new Error(\n\t\t\t`Context compaction did not call any transcript inspection, budget, or deletion tools (${CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME}, ${CONTEXT_READ_ENTRY_TOOL_NAME}, ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME}, ${CONTEXT_DELETE_TOOL_NAME}, or ${CONTEXT_GREP_DELETE_TOOL_NAME})`,\n\t\t);\n\t}\n\treturn {\n\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\tlastToolError: deletionTool.getLastError(),\n\t\tproviderError: undefined,\n\t};\n}\n\nfunction hasMetContextCompactionTarget(\n\trun: ContextDeletionRun,\n\tparameters: ContextCompactionParameters,\n): run is ContextDeletionRun & { validatedResult: ValidatedContextDeletionResult } {\n\treturn contextCompactionTargetMet(run.validatedResult, parameters);\n}\n\nfunction formatContextCompactionTargetFailureMessage(\n\tattempts: readonly ContextDeletionRunAttempt[],\n\tparameters: ContextCompactionParameters,\n): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tif (attempts.length === 0) return `Context compaction did not meet the strict ${targetLabel} reduction requirement`;\n\tconst attemptDetails = attempts\n\t\t.map((attempt) => {\n\t\t\tconst reduction = contextCompactionProgressPercent(attempt.validatedResult);\n\t\t\tconst deletionCount = attempt.validatedResult?.deletedTargets.length ?? 0;\n\t\t\tconst tokensAfterText = attempt.validatedResult ? `; tokens after: ${attempt.validatedResult.stats.tokensAfter}` : \"\";\n\t\t\tconst toolErrorText = attempt.lastToolError ? `; last deletion tool error: ${attempt.lastToolError}` : \"\";\n\t\t\tconst providerErrorText = attempt.providerError ? `; provider error: ${attempt.providerError}` : \"\";\n\t\t\treturn `attempt reached ${reduction}% with ${deletionCount} validated deletion target(s)${tokensAfterText}${toolErrorText}${providerErrorText}`;\n\t\t})\n\t\t.join(\"; \");\n\treturn `Context compaction did not meet the strict ${targetLabel} reduction requirement; ${attemptDetails}`;\n}\n\nfunction runFailedAttempt(error: Error): ContextDeletionRunAttempt {\n\treturn { validatedResult: undefined, lastToolError: undefined, providerError: error.message };\n}\n\nfunction shouldRethrowPlannerError(error: Error, signal: AbortSignal | undefined, ladder: ContextCompactionLadderOptions | undefined): boolean {\n\tif (signal?.aborted) return true;\n\tif (error.message === \"Context compaction failed: Request was aborted\") return true;\n\treturn ladder?.criticalEvictionTokenBudget === undefined;\n}\n\ninterface ContextDeletionRunAttempt extends ContextDeletionRun {}\n\nexport async function contextCompact(\n\tpreparation: ContextCompactionPreparation,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n\tladder?: ContextCompactionLadderOptions,\n): Promise<ValidatedContextDeletionResult> {\n\tconst parameters = normalizeContextCompactionParameters(\n\t\tpreparation.parameters ?? preparation.transcript.parameters,\n\t\tpreparation.parameters?.query ?? preparation.transcript.parameters?.query ?? CONTEXT_COMPACTION_AUTO_QUERY,\n\t);\n\tconst transcript: CompactableTranscript = { ...preparation.transcript, parameters };\n\tconst attempts: ContextDeletionRunAttempt[] = [];\n\ttry {\n\t\tconst standardRun = await runContextDeletionAssistant(transcript, model, apiKey, headers, signal, thinkingLevel, parameters);\n\t\tif (targetMetAcceptedForLadder(standardRun, parameters, ladder)) return standardRun.validatedResult;\n\t\tif (feasibleAccepted(standardRun.validatedResult, ladder?.acceptanceTokenBudget)) return standardRun.validatedResult;\n\t\tattempts.push({ ...standardRun });\n\t} catch (error) {\n\t\tconst formattedError = error instanceof Error ? error : new Error(formatErrorMessage(error));\n\t\tif (shouldRethrowPlannerError(formattedError, signal, ladder)) throw formattedError;\n\t\tattempts.push(runFailedAttempt(formattedError));\n\t}\n\n\tif (ladder?.criticalEvictionTokenBudget === undefined) {\n\t\tthrow new Error(formatContextCompactionTargetFailureMessage(attempts, parameters));\n\t}\n\n\ttry {\n\t\tconst criticalParameters = criticalCompactionParameters(parameters);\n\t\tconst criticalTranscript = relaxTranscriptForCriticalEviction(transcript);\n\t\tconst criticalRun = await runContextDeletionAssistant(\n\t\t\tcriticalTranscript,\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthinkingLevel,\n\t\t\tcriticalParameters,\n\t\t\t{\n\t\t\t\tpromptSuffix: CONTEXT_COMPACTION_CRITICAL_OVERFLOW_PROMPT,\n\t\t\t\tacceptanceTokenBudget: ladder.criticalEvictionTokenBudget,\n\t\t\t},\n\t\t);\n\t\tif (targetMetAcceptedForLadder(criticalRun, parameters, ladder)) return criticalRun.validatedResult;\n\t\tif (feasibleAccepted(criticalRun.validatedResult, ladder.criticalEvictionTokenBudget)) return criticalRun.validatedResult;\n\t\tattempts.push({ ...criticalRun });\n\t} catch (error) {\n\t\tconst formattedError = error instanceof Error ? error : new Error(formatErrorMessage(error));\n\t\tif (signal?.aborted || formattedError.message === \"Context compaction failed: Request was aborted\") throw formattedError;\n\t\tattempts.push(runFailedAttempt(formattedError));\n\t}\n\n\ttry {\n\t\treturn runDeterministicContextEviction(transcript, ladder.criticalEvictionTokenBudget);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : formatErrorMessage(error);\n\t\tthrow new Error(`${formatContextCompactionTargetFailureMessage(attempts, parameters)}; ${message}`);\n\t}\n}\n"]}
@@ -3,10 +3,14 @@ import { createAssistantMessageEventStream, isContextOverflow, streamSimple } fr
3
3
  import { formatCopilotProviderError } from "../copilot-errors.js";
4
4
  import { CONTEXT_COMPACTION_AUTO_QUERY } from "./context-compaction-types.js";
5
5
  import { createContextCompactionBudgetDetails, contextCompactionProgressKey, contextCompactionProgressPercent, contextCompactionTargetLabel, contextCompactionTargetMet, formatErrorMessage, } from "./context-compaction-metrics.js";
6
- import { getTranscriptCompactionParameters, normalizeContextCompactionParameters, } from "./context-compaction-strategy.js";
6
+ import { getTranscriptCompactionParameters, normalizeContextCompactionParameters } from "./context-compaction-strategy.js";
7
7
  import { CONTEXT_COMPACTION_BUDGET_TOOL_NAME, CONTEXT_DELETE_TOOL_NAME, CONTEXT_GREP_DELETE_TOOL_NAME, CONTEXT_READ_ENTRY_TOOL_NAME, CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME, } from "./context-deletion-tool-definitions.js";
8
8
  import { createContextDeletionTool } from "./context-deletion-tools.js";
9
9
  import { buildContextCompactionPrompt, CONTEXT_COMPACTION_SYSTEM_PROMPT, writeContextCompactionTranscriptFile, } from "./context-compaction-prompt.js";
10
+ import { CONTEXT_COMPACTION_CRITICAL_OVERFLOW_PROMPT, criticalCompactionParameters, relaxTranscriptForCriticalEviction, } from "./context-compaction-critical.js";
11
+ import { runDeterministicContextEviction } from "./context-compaction-eviction.js";
12
+ export const CONTEXT_COMPACTION_MAX_TURNS = 50;
13
+ export const CONTEXT_COMPACTION_MAX_PLANNER_NUDGES = 50;
10
14
  function createContextCompactionTargetNudgeMessage(result, parameters) {
11
15
  const currentReductionPercent = contextCompactionProgressPercent(result);
12
16
  const targetLabel = contextCompactionTargetLabel(parameters);
@@ -57,19 +61,37 @@ function createContextCompactionStopStream(model, text) {
57
61
  function isContextCompactionOverflowError(model, errorMessage) {
58
62
  return isContextOverflow(createContextCompactionAssistantMessage(model, [], "error", errorMessage), model.contextWindow);
59
63
  }
60
- async function runContextDeletionAssistant(inputTranscript, model, apiKey, headers, signal, thinkingLevel = "off", parameters = getTranscriptCompactionParameters(inputTranscript)) {
64
+ function feasibleAccepted(result, acceptanceTokenBudget) {
65
+ return (acceptanceTokenBudget !== undefined &&
66
+ result !== undefined &&
67
+ result.deletedTargets.length > 0 &&
68
+ result.stats.tokensAfter <= acceptanceTokenBudget);
69
+ }
70
+ function acceptedWithinRun(result, parameters, acceptanceTokenBudget) {
71
+ if (acceptanceTokenBudget !== undefined)
72
+ return feasibleAccepted(result, acceptanceTokenBudget);
73
+ return contextCompactionTargetMet(result, parameters);
74
+ }
75
+ function targetMetAcceptedForLadder(run, parameters, ladder) {
76
+ if (!hasMetContextCompactionTarget(run, parameters))
77
+ return false;
78
+ const overflowBudget = ladder?.criticalEvictionTokenBudget;
79
+ return overflowBudget === undefined || run.validatedResult.stats.tokensAfter <= overflowBudget;
80
+ }
81
+ async function runContextDeletionAssistant(inputTranscript, model, apiKey, headers, signal, thinkingLevel = "off", parameters = getTranscriptCompactionParameters(inputTranscript), options = {}) {
61
82
  const transcript = { ...inputTranscript, parameters };
62
83
  const maxTokens = model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY;
63
- if (signal?.aborted) {
84
+ if (signal?.aborted)
64
85
  throw new Error("Context compaction failed: Request was aborted");
65
- }
66
86
  const transcriptFile = writeContextCompactionTranscriptFile(transcript);
87
+ const promptText = buildContextCompactionPrompt(transcript, transcriptFile.path, parameters) + (options.promptSuffix ?? "");
67
88
  const promptMessage = {
68
89
  role: "user",
69
- content: [{ type: "text", text: buildContextCompactionPrompt(transcript, transcriptFile.path, parameters) }],
90
+ content: [{ type: "text", text: promptText }],
70
91
  timestamp: Date.now(),
71
92
  };
72
93
  const deletionTool = createContextDeletionTool(transcript, { contextWindow: model.contextWindow, ...parameters });
94
+ let providerTurnCount = 0;
73
95
  const agent = new Agent({
74
96
  initialState: {
75
97
  systemPrompt: CONTEXT_COMPACTION_SYSTEM_PROMPT,
@@ -80,9 +102,13 @@ async function runContextDeletionAssistant(inputTranscript, model, apiKey, heade
80
102
  toolExecution: "parallel",
81
103
  streamFn: async (requestModel, context, streamOptions) => {
82
104
  const currentResult = deletionTool.getValidatedResult();
83
- if (contextCompactionTargetMet(currentResult, parameters)) {
84
- return createContextCompactionStopStream(requestModel, `Reached the strict ${contextCompactionTargetLabel(parameters)} context-reduction requirement (${currentResult.stats.percentReduction}%); using the validated deletions recorded so far.`);
105
+ if (acceptedWithinRun(currentResult, parameters, options.acceptanceTokenBudget)) {
106
+ return createContextCompactionStopStream(requestModel, `Reached an acceptable context-reduction result (${currentResult.stats.percentReduction}%, ${currentResult.stats.tokensAfter} token(s) after deletion); using the validated deletions recorded so far.`);
107
+ }
108
+ if (providerTurnCount >= CONTEXT_COMPACTION_MAX_TURNS) {
109
+ return createContextCompactionStopStream(requestModel, `Reached the context compaction turn cap (${CONTEXT_COMPACTION_MAX_TURNS}); using the validated deletions recorded so far.`);
85
110
  }
111
+ providerTurnCount += 1;
86
112
  return streamSimple(requestModel, context, {
87
113
  ...streamOptions,
88
114
  maxTokens,
@@ -92,6 +118,7 @@ async function runContextDeletionAssistant(inputTranscript, model, apiKey, heade
92
118
  },
93
119
  });
94
120
  let lastNudgedProgressKey;
121
+ let nudgeCount = 0;
95
122
  const unsubscribeNudge = agent.subscribe((event, eventSignal) => {
96
123
  if (event.type !== "turn_end" || signal?.aborted || eventSignal.aborted)
97
124
  return;
@@ -101,13 +128,16 @@ async function runContextDeletionAssistant(inputTranscript, model, apiKey, heade
101
128
  return;
102
129
  if (event.message.content.some((content) => content.type === "toolCall"))
103
130
  return;
131
+ if (nudgeCount >= CONTEXT_COMPACTION_MAX_PLANNER_NUDGES)
132
+ return;
104
133
  const currentResult = deletionTool.getValidatedResult();
105
- if (contextCompactionTargetMet(currentResult, parameters))
134
+ if (acceptedWithinRun(currentResult, parameters, options.acceptanceTokenBudget))
106
135
  return;
107
136
  const progressKey = contextCompactionProgressKey(currentResult);
108
137
  if (progressKey === lastNudgedProgressKey)
109
138
  return;
110
139
  lastNudgedProgressKey = progressKey;
140
+ nudgeCount += 1;
111
141
  agent.followUp(createContextCompactionTargetNudgeMessage(currentResult, parameters));
112
142
  });
113
143
  const abortOnSignal = () => agent.abort();
@@ -116,9 +146,8 @@ async function runContextDeletionAssistant(inputTranscript, model, apiKey, heade
116
146
  await agent.prompt(promptMessage);
117
147
  }
118
148
  catch (error) {
119
- if (signal?.aborted) {
149
+ if (signal?.aborted)
120
150
  throw new Error("Context compaction failed: Request was aborted");
121
- }
122
151
  throw new Error(`Context compaction failed: ${formatCopilotProviderError(model.provider, formatErrorMessage(error))}`);
123
152
  }
124
153
  finally {
@@ -126,9 +155,8 @@ async function runContextDeletionAssistant(inputTranscript, model, apiKey, heade
126
155
  unsubscribeNudge();
127
156
  transcriptFile.cleanup();
128
157
  }
129
- if (signal?.aborted) {
158
+ if (signal?.aborted)
130
159
  throw new Error("Context compaction failed: Request was aborted");
131
- }
132
160
  if (agent.state.errorMessage) {
133
161
  const formattedErrorMessage = formatCopilotProviderError(model.provider, agent.state.errorMessage);
134
162
  if (isContextCompactionOverflowError(model, agent.state.errorMessage)) {
@@ -154,28 +182,76 @@ function hasMetContextCompactionTarget(run, parameters) {
154
182
  }
155
183
  function formatContextCompactionTargetFailureMessage(attempts, parameters) {
156
184
  const targetLabel = contextCompactionTargetLabel(parameters);
157
- if (attempts.length === 0) {
185
+ if (attempts.length === 0)
158
186
  return `Context compaction did not meet the strict ${targetLabel} reduction requirement`;
159
- }
160
187
  const attemptDetails = attempts
161
188
  .map((attempt) => {
162
189
  const reduction = contextCompactionProgressPercent(attempt.validatedResult);
163
190
  const deletionCount = attempt.validatedResult?.deletedTargets.length ?? 0;
191
+ const tokensAfterText = attempt.validatedResult ? `; tokens after: ${attempt.validatedResult.stats.tokensAfter}` : "";
164
192
  const toolErrorText = attempt.lastToolError ? `; last deletion tool error: ${attempt.lastToolError}` : "";
165
193
  const providerErrorText = attempt.providerError ? `; provider error: ${attempt.providerError}` : "";
166
- return `attempt reached ${reduction}% with ${deletionCount} validated deletion target(s)${toolErrorText}${providerErrorText}`;
194
+ return `attempt reached ${reduction}% with ${deletionCount} validated deletion target(s)${tokensAfterText}${toolErrorText}${providerErrorText}`;
167
195
  })
168
196
  .join("; ");
169
197
  return `Context compaction did not meet the strict ${targetLabel} reduction requirement; ${attemptDetails}`;
170
198
  }
171
- export async function contextCompact(preparation, model, apiKey, headers, signal, thinkingLevel = "off") {
199
+ function runFailedAttempt(error) {
200
+ return { validatedResult: undefined, lastToolError: undefined, providerError: error.message };
201
+ }
202
+ function shouldRethrowPlannerError(error, signal, ladder) {
203
+ if (signal?.aborted)
204
+ return true;
205
+ if (error.message === "Context compaction failed: Request was aborted")
206
+ return true;
207
+ return ladder?.criticalEvictionTokenBudget === undefined;
208
+ }
209
+ export async function contextCompact(preparation, model, apiKey, headers, signal, thinkingLevel = "off", ladder) {
172
210
  const parameters = normalizeContextCompactionParameters(preparation.parameters ?? preparation.transcript.parameters, preparation.parameters?.query ?? preparation.transcript.parameters?.query ?? CONTEXT_COMPACTION_AUTO_QUERY);
173
211
  const transcript = { ...preparation.transcript, parameters };
174
212
  const attempts = [];
175
- const standardRun = await runContextDeletionAssistant(transcript, model, apiKey, headers, signal, thinkingLevel, parameters);
176
- if (hasMetContextCompactionTarget(standardRun, parameters))
177
- return standardRun.validatedResult;
178
- attempts.push({ ...standardRun });
179
- throw new Error(formatContextCompactionTargetFailureMessage(attempts, parameters));
213
+ try {
214
+ const standardRun = await runContextDeletionAssistant(transcript, model, apiKey, headers, signal, thinkingLevel, parameters);
215
+ if (targetMetAcceptedForLadder(standardRun, parameters, ladder))
216
+ return standardRun.validatedResult;
217
+ if (feasibleAccepted(standardRun.validatedResult, ladder?.acceptanceTokenBudget))
218
+ return standardRun.validatedResult;
219
+ attempts.push({ ...standardRun });
220
+ }
221
+ catch (error) {
222
+ const formattedError = error instanceof Error ? error : new Error(formatErrorMessage(error));
223
+ if (shouldRethrowPlannerError(formattedError, signal, ladder))
224
+ throw formattedError;
225
+ attempts.push(runFailedAttempt(formattedError));
226
+ }
227
+ if (ladder?.criticalEvictionTokenBudget === undefined) {
228
+ throw new Error(formatContextCompactionTargetFailureMessage(attempts, parameters));
229
+ }
230
+ try {
231
+ const criticalParameters = criticalCompactionParameters(parameters);
232
+ const criticalTranscript = relaxTranscriptForCriticalEviction(transcript);
233
+ const criticalRun = await runContextDeletionAssistant(criticalTranscript, model, apiKey, headers, signal, thinkingLevel, criticalParameters, {
234
+ promptSuffix: CONTEXT_COMPACTION_CRITICAL_OVERFLOW_PROMPT,
235
+ acceptanceTokenBudget: ladder.criticalEvictionTokenBudget,
236
+ });
237
+ if (targetMetAcceptedForLadder(criticalRun, parameters, ladder))
238
+ return criticalRun.validatedResult;
239
+ if (feasibleAccepted(criticalRun.validatedResult, ladder.criticalEvictionTokenBudget))
240
+ return criticalRun.validatedResult;
241
+ attempts.push({ ...criticalRun });
242
+ }
243
+ catch (error) {
244
+ const formattedError = error instanceof Error ? error : new Error(formatErrorMessage(error));
245
+ if (signal?.aborted || formattedError.message === "Context compaction failed: Request was aborted")
246
+ throw formattedError;
247
+ attempts.push(runFailedAttempt(formattedError));
248
+ }
249
+ try {
250
+ return runDeterministicContextEviction(transcript, ladder.criticalEvictionTokenBudget);
251
+ }
252
+ catch (error) {
253
+ const message = error instanceof Error ? error.message : formatErrorMessage(error);
254
+ throw new Error(`${formatContextCompactionTargetFailureMessage(attempts, parameters)}; ${message}`);
255
+ }
180
256
  }
181
257
  //# sourceMappingURL=context-compaction-runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-runner.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, type AgentMessage, type ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, AssistantMessage, Model } from \"@earendil-works/pi-ai/compat\";\nimport { createAssistantMessageEventStream, isContextOverflow, streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport { formatCopilotProviderError } from \"../copilot-errors.ts\";\nimport type {\n\tCompactableTranscript,\n\tContextCompactionParameters,\n\tContextCompactionPreparation,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { CONTEXT_COMPACTION_AUTO_QUERY } from \"./context-compaction-types.ts\";\nimport {\n\tcreateContextCompactionBudgetDetails,\n\tcontextCompactionProgressKey,\n\tcontextCompactionProgressPercent,\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetMet,\n\tformatErrorMessage,\n} from \"./context-compaction-metrics.ts\";\nimport {\n\tgetTranscriptCompactionParameters,\n\tnormalizeContextCompactionParameters,\n} from \"./context-compaction-strategy.ts\";\nimport {\n\tCONTEXT_COMPACTION_BUDGET_TOOL_NAME,\n\tCONTEXT_DELETE_TOOL_NAME,\n\tCONTEXT_GREP_DELETE_TOOL_NAME,\n\tCONTEXT_READ_ENTRY_TOOL_NAME,\n\tCONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { createContextDeletionTool } from \"./context-deletion-tools.ts\";\nimport {\n\tbuildContextCompactionPrompt,\n\tCONTEXT_COMPACTION_SYSTEM_PROMPT,\n\twriteContextCompactionTranscriptFile,\n} from \"./context-compaction-prompt.ts\";\n\nfunction createContextCompactionTargetNudgeMessage(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tparameters: ContextCompactionParameters,\n): AgentMessage {\n\tconst currentReductionPercent = contextCompactionProgressPercent(result);\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tconst tokensToDelete = result\n\t\t? createContextCompactionBudgetDetails(result.stats, 0, undefined, parameters, 0, 0).tokensToDeleteForTarget\n\t\t: undefined;\n\tconst remainingText = tokensToDelete !== undefined ? ` Delete about ${tokensToDelete} more token(s) if safe candidates exist.` : \"\";\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `The strict ${targetLabel} context-reduction requirement is not met yet; current validated reduction is ${currentReductionPercent}%.${remainingText} Continue removing low-value message entries or message content blocks using ${CONTEXT_DELETE_TOOL_NAME} or ${CONTEXT_GREP_DELETE_TOOL_NAME}. Use the focus query ${JSON.stringify(parameters.query)} to preserve relevant context. Call ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME} to verify progress, and do not provide a final answer until the validated reduction is at least ${targetLabel}.`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.now(),\n\t};\n}\nfunction createContextCompactionAssistantMessage(\n\tmodel: Model<Api>,\n\tcontent: AssistantMessage[\"content\"],\n\tstopReason: AssistantMessage[\"stopReason\"],\n\terrorMessage?: string,\n): AssistantMessage {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: {\n\t\t\tinput: 0,\n\t\t\toutput: 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t},\n\t\tstopReason,\n\t\t...(errorMessage !== undefined ? { errorMessage } : {}),\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createContextCompactionStopStream(model: Model<Api>, text: string) {\n\tconst stream = createAssistantMessageEventStream();\n\tqueueMicrotask(() => {\n\t\tconst message = createContextCompactionAssistantMessage(model, [{ type: \"text\", text }], \"stop\");\n\t\tstream.push({ type: \"done\", reason: \"stop\", message });\n\t\tstream.end(message);\n\t});\n\treturn stream;\n}\n\nfunction isContextCompactionOverflowError(model: Model<Api>, errorMessage: string): boolean {\n\treturn isContextOverflow(\n\t\tcreateContextCompactionAssistantMessage(model, [], \"error\", errorMessage),\n\t\tmodel.contextWindow,\n\t);\n}\n\ninterface ContextDeletionRun {\n\tvalidatedResult: ValidatedContextDeletionResult | undefined;\n\tlastToolError: string | undefined;\n\tproviderError: string | undefined;\n}\n\nasync function runContextDeletionAssistant(\n\tinputTranscript: CompactableTranscript,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(inputTranscript),\n): Promise<ContextDeletionRun> {\n\tconst transcript: CompactableTranscript = { ...inputTranscript, parameters };\n\tconst maxTokens = model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY;\n\tif (signal?.aborted) {\n\t\tthrow new Error(\"Context compaction failed: Request was aborted\");\n\t}\n\tconst transcriptFile = writeContextCompactionTranscriptFile(transcript);\n\tconst promptMessage: AgentMessage = {\n\t\trole: \"user\",\n\t\tcontent: [{ type: \"text\", text: buildContextCompactionPrompt(transcript, transcriptFile.path, parameters) }],\n\t\ttimestamp: Date.now(),\n\t};\n\tconst deletionTool = createContextDeletionTool(transcript, { contextWindow: model.contextWindow, ...parameters });\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: CONTEXT_COMPACTION_SYSTEM_PROMPT,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: deletionTool.tools,\n\t\t},\n\t\ttoolExecution: \"parallel\",\n\t\tstreamFn: async (requestModel, context, streamOptions) => {\n\t\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\t\tif (contextCompactionTargetMet(currentResult, parameters)) {\n\t\t\t\treturn createContextCompactionStopStream(\n\t\t\t\t\trequestModel,\n\t\t\t\t\t`Reached the strict ${contextCompactionTargetLabel(parameters)} context-reduction requirement (${currentResult.stats.percentReduction}%); using the validated deletions recorded so far.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn streamSimple(requestModel, context, {\n\t\t\t\t...streamOptions,\n\t\t\t\tmaxTokens,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers ?? streamOptions?.headers,\n\t\t\t});\n\t\t},\n\t});\n\n\tlet lastNudgedProgressKey: string | undefined;\n\tconst unsubscribeNudge = agent.subscribe((event, eventSignal) => {\n\t\tif (event.type !== \"turn_end\" || signal?.aborted || eventSignal.aborted) return;\n\t\tif (event.message.role !== \"assistant\") return;\n\t\tif (event.message.stopReason === \"error\" || event.message.stopReason === \"aborted\") return;\n\t\tif (event.message.content.some((content) => content.type === \"toolCall\")) return;\n\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\tif (contextCompactionTargetMet(currentResult, parameters)) return;\n\t\tconst progressKey = contextCompactionProgressKey(currentResult);\n\t\tif (progressKey === lastNudgedProgressKey) return;\n\t\tlastNudgedProgressKey = progressKey;\n\t\tagent.followUp(createContextCompactionTargetNudgeMessage(currentResult, parameters));\n\t});\n\n\tconst abortOnSignal = () => agent.abort();\n\tsignal?.addEventListener(\"abort\", abortOnSignal, { once: true });\n\ttry {\n\t\tawait agent.prompt(promptMessage);\n\t} catch (error) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Context compaction failed: Request was aborted\");\n\t\t}\n\t\tthrow new Error(`Context compaction failed: ${formatCopilotProviderError(model.provider, formatErrorMessage(error))}`);\n\t} finally {\n\t\tsignal?.removeEventListener(\"abort\", abortOnSignal);\n\t\tunsubscribeNudge();\n\t\ttranscriptFile.cleanup();\n\t}\n\n\tif (signal?.aborted) {\n\t\tthrow new Error(\"Context compaction failed: Request was aborted\");\n\t}\n\tif (agent.state.errorMessage) {\n\t\tconst formattedErrorMessage = formatCopilotProviderError(model.provider, agent.state.errorMessage);\n\t\tif (isContextCompactionOverflowError(model, agent.state.errorMessage)) {\n\t\t\treturn {\n\t\t\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\t\t\tlastToolError: deletionTool.getLastError(),\n\t\t\t\tproviderError: formattedErrorMessage === agent.state.errorMessage ? undefined : formattedErrorMessage,\n\t\t\t};\n\t\t}\n\t\tthrow new Error(`Context compaction failed: ${formattedErrorMessage}`);\n\t}\n\tif (deletionTool.getCallCount() === 0) {\n\t\tthrow new Error(\n\t\t\t`Context compaction did not call any transcript inspection, budget, or deletion tools (${CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME}, ${CONTEXT_READ_ENTRY_TOOL_NAME}, ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME}, ${CONTEXT_DELETE_TOOL_NAME}, or ${CONTEXT_GREP_DELETE_TOOL_NAME})`,\n\t\t);\n\t}\n\treturn {\n\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\tlastToolError: deletionTool.getLastError(),\n\t\tproviderError: undefined,\n\t};\n}\n\nfunction hasMetContextCompactionTarget(\n\trun: ContextDeletionRun,\n\tparameters: ContextCompactionParameters,\n): run is ContextDeletionRun & { validatedResult: ValidatedContextDeletionResult } {\n\treturn contextCompactionTargetMet(run.validatedResult, parameters);\n}\n\nfunction formatContextCompactionTargetFailureMessage(\n\tattempts: readonly ContextDeletionRunAttempt[],\n\tparameters: ContextCompactionParameters,\n): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tif (attempts.length === 0) {\n\t\treturn `Context compaction did not meet the strict ${targetLabel} reduction requirement`;\n\t}\n\tconst attemptDetails = attempts\n\t\t.map((attempt) => {\n\t\t\tconst reduction = contextCompactionProgressPercent(attempt.validatedResult);\n\t\t\tconst deletionCount = attempt.validatedResult?.deletedTargets.length ?? 0;\n\t\t\tconst toolErrorText = attempt.lastToolError ? `; last deletion tool error: ${attempt.lastToolError}` : \"\";\n\t\t\tconst providerErrorText = attempt.providerError ? `; provider error: ${attempt.providerError}` : \"\";\n\t\t\treturn `attempt reached ${reduction}% with ${deletionCount} validated deletion target(s)${toolErrorText}${providerErrorText}`;\n\t\t})\n\t\t.join(\"; \");\n\treturn `Context compaction did not meet the strict ${targetLabel} reduction requirement; ${attemptDetails}`;\n}\n\ninterface ContextDeletionRunAttempt extends ContextDeletionRun {}\n\nexport async function contextCompact(\n\tpreparation: ContextCompactionPreparation,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n): Promise<ValidatedContextDeletionResult> {\n\tconst parameters = normalizeContextCompactionParameters(\n\t\tpreparation.parameters ?? preparation.transcript.parameters,\n\t\tpreparation.parameters?.query ?? preparation.transcript.parameters?.query ?? CONTEXT_COMPACTION_AUTO_QUERY,\n\t);\n\tconst transcript: CompactableTranscript = { ...preparation.transcript, parameters };\n\tconst attempts: ContextDeletionRunAttempt[] = [];\n\tconst standardRun = await runContextDeletionAssistant(\n\t\ttranscript,\n\t\tmodel,\n\t\tapiKey,\n\t\theaders,\n\t\tsignal,\n\t\tthinkingLevel,\n\t\tparameters,\n\t);\n\tif (hasMetContextCompactionTarget(standardRun, parameters)) return standardRun.validatedResult;\n\tattempts.push({ ...standardRun });\n\n\tthrow new Error(formatContextCompactionTargetFailureMessage(attempts, parameters));\n}\n"]}
1
+ {"version":3,"file":"context-compaction-runner.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, type AgentMessage, type ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, AssistantMessage, Model } from \"@earendil-works/pi-ai/compat\";\nimport { createAssistantMessageEventStream, isContextOverflow, streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport { formatCopilotProviderError } from \"../copilot-errors.ts\";\nimport type {\n\tCompactableTranscript,\n\tContextCompactionParameters,\n\tContextCompactionPreparation,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { CONTEXT_COMPACTION_AUTO_QUERY } from \"./context-compaction-types.ts\";\nimport {\n\tcreateContextCompactionBudgetDetails,\n\tcontextCompactionProgressKey,\n\tcontextCompactionProgressPercent,\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetMet,\n\tformatErrorMessage,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters, normalizeContextCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport {\n\tCONTEXT_COMPACTION_BUDGET_TOOL_NAME,\n\tCONTEXT_DELETE_TOOL_NAME,\n\tCONTEXT_GREP_DELETE_TOOL_NAME,\n\tCONTEXT_READ_ENTRY_TOOL_NAME,\n\tCONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { createContextDeletionTool } from \"./context-deletion-tools.ts\";\nimport {\n\tbuildContextCompactionPrompt,\n\tCONTEXT_COMPACTION_SYSTEM_PROMPT,\n\twriteContextCompactionTranscriptFile,\n} from \"./context-compaction-prompt.ts\";\nimport {\n\tCONTEXT_COMPACTION_CRITICAL_OVERFLOW_PROMPT,\n\tcriticalCompactionParameters,\n\trelaxTranscriptForCriticalEviction,\n} from \"./context-compaction-critical.ts\";\nimport { runDeterministicContextEviction } from \"./context-compaction-eviction.ts\";\n\nexport const CONTEXT_COMPACTION_MAX_TURNS = 50;\nexport const CONTEXT_COMPACTION_MAX_PLANNER_NUDGES = 50;\n\nexport interface ContextCompactionLadderOptions {\n\tacceptanceTokenBudget?: number;\n\tcriticalEvictionTokenBudget?: number;\n}\n\ninterface ContextDeletionAssistantOptions {\n\tpromptSuffix?: string;\n\tacceptanceTokenBudget?: number;\n}\n\nfunction createContextCompactionTargetNudgeMessage(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tparameters: ContextCompactionParameters,\n): AgentMessage {\n\tconst currentReductionPercent = contextCompactionProgressPercent(result);\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tconst tokensToDelete = result\n\t\t? createContextCompactionBudgetDetails(result.stats, 0, undefined, parameters, 0, 0).tokensToDeleteForTarget\n\t\t: undefined;\n\tconst remainingText = tokensToDelete !== undefined ? ` Delete about ${tokensToDelete} more token(s) if safe candidates exist.` : \"\";\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `The strict ${targetLabel} context-reduction requirement is not met yet; current validated reduction is ${currentReductionPercent}%.${remainingText} Continue removing low-value message entries or message content blocks using ${CONTEXT_DELETE_TOOL_NAME} or ${CONTEXT_GREP_DELETE_TOOL_NAME}. Use the focus query ${JSON.stringify(parameters.query)} to preserve relevant context. Call ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME} to verify progress, and do not provide a final answer until the validated reduction is at least ${targetLabel}.`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createContextCompactionAssistantMessage(\n\tmodel: Model<Api>,\n\tcontent: AssistantMessage[\"content\"],\n\tstopReason: AssistantMessage[\"stopReason\"],\n\terrorMessage?: string,\n): AssistantMessage {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tusage: {\n\t\t\tinput: 0,\n\t\t\toutput: 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t},\n\t\tstopReason,\n\t\t...(errorMessage !== undefined ? { errorMessage } : {}),\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nfunction createContextCompactionStopStream(model: Model<Api>, text: string) {\n\tconst stream = createAssistantMessageEventStream();\n\tqueueMicrotask(() => {\n\t\tconst message = createContextCompactionAssistantMessage(model, [{ type: \"text\", text }], \"stop\");\n\t\tstream.push({ type: \"done\", reason: \"stop\", message });\n\t\tstream.end(message);\n\t});\n\treturn stream;\n}\n\nfunction isContextCompactionOverflowError(model: Model<Api>, errorMessage: string): boolean {\n\treturn isContextOverflow(createContextCompactionAssistantMessage(model, [], \"error\", errorMessage), model.contextWindow);\n}\n\nfunction feasibleAccepted(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tacceptanceTokenBudget: number | undefined,\n): result is ValidatedContextDeletionResult {\n\treturn (\n\t\tacceptanceTokenBudget !== undefined &&\n\t\tresult !== undefined &&\n\t\tresult.deletedTargets.length > 0 &&\n\t\tresult.stats.tokensAfter <= acceptanceTokenBudget\n\t);\n}\n\nfunction acceptedWithinRun(\n\tresult: ValidatedContextDeletionResult | undefined,\n\tparameters: ContextCompactionParameters,\n\tacceptanceTokenBudget: number | undefined,\n): result is ValidatedContextDeletionResult {\n\tif (acceptanceTokenBudget !== undefined) return feasibleAccepted(result, acceptanceTokenBudget);\n\treturn contextCompactionTargetMet(result, parameters);\n}\n\nfunction targetMetAcceptedForLadder(\n\trun: ContextDeletionRun,\n\tparameters: ContextCompactionParameters,\n\tladder: ContextCompactionLadderOptions | undefined,\n): run is ContextDeletionRun & { validatedResult: ValidatedContextDeletionResult } {\n\tif (!hasMetContextCompactionTarget(run, parameters)) return false;\n\tconst overflowBudget = ladder?.criticalEvictionTokenBudget;\n\treturn overflowBudget === undefined || run.validatedResult.stats.tokensAfter <= overflowBudget;\n}\n\ninterface ContextDeletionRun {\n\tvalidatedResult: ValidatedContextDeletionResult | undefined;\n\tlastToolError: string | undefined;\n\tproviderError: string | undefined;\n}\n\nasync function runContextDeletionAssistant(\n\tinputTranscript: CompactableTranscript,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(inputTranscript),\n\toptions: ContextDeletionAssistantOptions = {},\n): Promise<ContextDeletionRun> {\n\tconst transcript: CompactableTranscript = { ...inputTranscript, parameters };\n\tconst maxTokens = model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY;\n\tif (signal?.aborted) throw new Error(\"Context compaction failed: Request was aborted\");\n\tconst transcriptFile = writeContextCompactionTranscriptFile(transcript);\n\tconst promptText = buildContextCompactionPrompt(transcript, transcriptFile.path, parameters) + (options.promptSuffix ?? \"\");\n\tconst promptMessage: AgentMessage = {\n\t\trole: \"user\",\n\t\tcontent: [{ type: \"text\", text: promptText }],\n\t\ttimestamp: Date.now(),\n\t};\n\tconst deletionTool = createContextDeletionTool(transcript, { contextWindow: model.contextWindow, ...parameters });\n\tlet providerTurnCount = 0;\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: CONTEXT_COMPACTION_SYSTEM_PROMPT,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: deletionTool.tools,\n\t\t},\n\t\ttoolExecution: \"parallel\",\n\t\tstreamFn: async (requestModel, context, streamOptions) => {\n\t\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\t\tif (acceptedWithinRun(currentResult, parameters, options.acceptanceTokenBudget)) {\n\t\t\t\treturn createContextCompactionStopStream(\n\t\t\t\t\trequestModel,\n\t\t\t\t\t`Reached an acceptable context-reduction result (${currentResult.stats.percentReduction}%, ${currentResult.stats.tokensAfter} token(s) after deletion); using the validated deletions recorded so far.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (providerTurnCount >= CONTEXT_COMPACTION_MAX_TURNS) {\n\t\t\t\treturn createContextCompactionStopStream(\n\t\t\t\t\trequestModel,\n\t\t\t\t\t`Reached the context compaction turn cap (${CONTEXT_COMPACTION_MAX_TURNS}); using the validated deletions recorded so far.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tproviderTurnCount += 1;\n\t\t\treturn streamSimple(requestModel, context, {\n\t\t\t\t...streamOptions,\n\t\t\t\tmaxTokens,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers ?? streamOptions?.headers,\n\t\t\t});\n\t\t},\n\t});\n\n\tlet lastNudgedProgressKey: string | undefined;\n\tlet nudgeCount = 0;\n\tconst unsubscribeNudge = agent.subscribe((event, eventSignal) => {\n\t\tif (event.type !== \"turn_end\" || signal?.aborted || eventSignal.aborted) return;\n\t\tif (event.message.role !== \"assistant\") return;\n\t\tif (event.message.stopReason === \"error\" || event.message.stopReason === \"aborted\") return;\n\t\tif (event.message.content.some((content) => content.type === \"toolCall\")) return;\n\t\tif (nudgeCount >= CONTEXT_COMPACTION_MAX_PLANNER_NUDGES) return;\n\t\tconst currentResult = deletionTool.getValidatedResult();\n\t\tif (acceptedWithinRun(currentResult, parameters, options.acceptanceTokenBudget)) return;\n\t\tconst progressKey = contextCompactionProgressKey(currentResult);\n\t\tif (progressKey === lastNudgedProgressKey) return;\n\t\tlastNudgedProgressKey = progressKey;\n\t\tnudgeCount += 1;\n\t\tagent.followUp(createContextCompactionTargetNudgeMessage(currentResult, parameters));\n\t});\n\n\tconst abortOnSignal = () => agent.abort();\n\tsignal?.addEventListener(\"abort\", abortOnSignal, { once: true });\n\ttry {\n\t\tawait agent.prompt(promptMessage);\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Context compaction failed: Request was aborted\");\n\t\tthrow new Error(`Context compaction failed: ${formatCopilotProviderError(model.provider, formatErrorMessage(error))}`);\n\t} finally {\n\t\tsignal?.removeEventListener(\"abort\", abortOnSignal);\n\t\tunsubscribeNudge();\n\t\ttranscriptFile.cleanup();\n\t}\n\n\tif (signal?.aborted) throw new Error(\"Context compaction failed: Request was aborted\");\n\tif (agent.state.errorMessage) {\n\t\tconst formattedErrorMessage = formatCopilotProviderError(model.provider, agent.state.errorMessage);\n\t\tif (isContextCompactionOverflowError(model, agent.state.errorMessage)) {\n\t\t\treturn {\n\t\t\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\t\t\tlastToolError: deletionTool.getLastError(),\n\t\t\t\tproviderError: formattedErrorMessage === agent.state.errorMessage ? undefined : formattedErrorMessage,\n\t\t\t};\n\t\t}\n\t\tthrow new Error(`Context compaction failed: ${formattedErrorMessage}`);\n\t}\n\tif (deletionTool.getCallCount() === 0) {\n\t\tthrow new Error(\n\t\t\t`Context compaction did not call any transcript inspection, budget, or deletion tools (${CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME}, ${CONTEXT_READ_ENTRY_TOOL_NAME}, ${CONTEXT_COMPACTION_BUDGET_TOOL_NAME}, ${CONTEXT_DELETE_TOOL_NAME}, or ${CONTEXT_GREP_DELETE_TOOL_NAME})`,\n\t\t);\n\t}\n\treturn {\n\t\tvalidatedResult: deletionTool.getValidatedResult(),\n\t\tlastToolError: deletionTool.getLastError(),\n\t\tproviderError: undefined,\n\t};\n}\n\nfunction hasMetContextCompactionTarget(\n\trun: ContextDeletionRun,\n\tparameters: ContextCompactionParameters,\n): run is ContextDeletionRun & { validatedResult: ValidatedContextDeletionResult } {\n\treturn contextCompactionTargetMet(run.validatedResult, parameters);\n}\n\nfunction formatContextCompactionTargetFailureMessage(\n\tattempts: readonly ContextDeletionRunAttempt[],\n\tparameters: ContextCompactionParameters,\n): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\tif (attempts.length === 0) return `Context compaction did not meet the strict ${targetLabel} reduction requirement`;\n\tconst attemptDetails = attempts\n\t\t.map((attempt) => {\n\t\t\tconst reduction = contextCompactionProgressPercent(attempt.validatedResult);\n\t\t\tconst deletionCount = attempt.validatedResult?.deletedTargets.length ?? 0;\n\t\t\tconst tokensAfterText = attempt.validatedResult ? `; tokens after: ${attempt.validatedResult.stats.tokensAfter}` : \"\";\n\t\t\tconst toolErrorText = attempt.lastToolError ? `; last deletion tool error: ${attempt.lastToolError}` : \"\";\n\t\t\tconst providerErrorText = attempt.providerError ? `; provider error: ${attempt.providerError}` : \"\";\n\t\t\treturn `attempt reached ${reduction}% with ${deletionCount} validated deletion target(s)${tokensAfterText}${toolErrorText}${providerErrorText}`;\n\t\t})\n\t\t.join(\"; \");\n\treturn `Context compaction did not meet the strict ${targetLabel} reduction requirement; ${attemptDetails}`;\n}\n\nfunction runFailedAttempt(error: Error): ContextDeletionRunAttempt {\n\treturn { validatedResult: undefined, lastToolError: undefined, providerError: error.message };\n}\n\nfunction shouldRethrowPlannerError(error: Error, signal: AbortSignal | undefined, ladder: ContextCompactionLadderOptions | undefined): boolean {\n\tif (signal?.aborted) return true;\n\tif (error.message === \"Context compaction failed: Request was aborted\") return true;\n\treturn ladder?.criticalEvictionTokenBudget === undefined;\n}\n\ninterface ContextDeletionRunAttempt extends ContextDeletionRun {}\n\nexport async function contextCompact(\n\tpreparation: ContextCompactionPreparation,\n\tmodel: Model<Api>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel: ThinkingLevel = \"off\",\n\tladder?: ContextCompactionLadderOptions,\n): Promise<ValidatedContextDeletionResult> {\n\tconst parameters = normalizeContextCompactionParameters(\n\t\tpreparation.parameters ?? preparation.transcript.parameters,\n\t\tpreparation.parameters?.query ?? preparation.transcript.parameters?.query ?? CONTEXT_COMPACTION_AUTO_QUERY,\n\t);\n\tconst transcript: CompactableTranscript = { ...preparation.transcript, parameters };\n\tconst attempts: ContextDeletionRunAttempt[] = [];\n\ttry {\n\t\tconst standardRun = await runContextDeletionAssistant(transcript, model, apiKey, headers, signal, thinkingLevel, parameters);\n\t\tif (targetMetAcceptedForLadder(standardRun, parameters, ladder)) return standardRun.validatedResult;\n\t\tif (feasibleAccepted(standardRun.validatedResult, ladder?.acceptanceTokenBudget)) return standardRun.validatedResult;\n\t\tattempts.push({ ...standardRun });\n\t} catch (error) {\n\t\tconst formattedError = error instanceof Error ? error : new Error(formatErrorMessage(error));\n\t\tif (shouldRethrowPlannerError(formattedError, signal, ladder)) throw formattedError;\n\t\tattempts.push(runFailedAttempt(formattedError));\n\t}\n\n\tif (ladder?.criticalEvictionTokenBudget === undefined) {\n\t\tthrow new Error(formatContextCompactionTargetFailureMessage(attempts, parameters));\n\t}\n\n\ttry {\n\t\tconst criticalParameters = criticalCompactionParameters(parameters);\n\t\tconst criticalTranscript = relaxTranscriptForCriticalEviction(transcript);\n\t\tconst criticalRun = await runContextDeletionAssistant(\n\t\t\tcriticalTranscript,\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthinkingLevel,\n\t\t\tcriticalParameters,\n\t\t\t{\n\t\t\t\tpromptSuffix: CONTEXT_COMPACTION_CRITICAL_OVERFLOW_PROMPT,\n\t\t\t\tacceptanceTokenBudget: ladder.criticalEvictionTokenBudget,\n\t\t\t},\n\t\t);\n\t\tif (targetMetAcceptedForLadder(criticalRun, parameters, ladder)) return criticalRun.validatedResult;\n\t\tif (feasibleAccepted(criticalRun.validatedResult, ladder.criticalEvictionTokenBudget)) return criticalRun.validatedResult;\n\t\tattempts.push({ ...criticalRun });\n\t} catch (error) {\n\t\tconst formattedError = error instanceof Error ? error : new Error(formatErrorMessage(error));\n\t\tif (signal?.aborted || formattedError.message === \"Context compaction failed: Request was aborted\") throw formattedError;\n\t\tattempts.push(runFailedAttempt(formattedError));\n\t}\n\n\ttry {\n\t\treturn runDeterministicContextEviction(transcript, ladder.criticalEvictionTokenBudget);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : formatErrorMessage(error);\n\t\tthrow new Error(`${formatContextCompactionTargetFailureMessage(attempts, parameters)}; ${message}`);\n\t}\n}\n"]}