@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.
- package/CHANGELOG.md +24 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +7 -0
- package/dist/builtin/subagents/agents/debugger.md +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +17 -0
- package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +5 -5
- package/dist/builtin/workflows/builtin/goal-runner.ts +5 -5
- package/dist/builtin/workflows/builtin/goal-types.ts +1 -0
- package/dist/builtin/workflows/builtin/goal.d.ts +2 -0
- package/dist/builtin/workflows/builtin/goal.ts +9 -0
- package/dist/builtin/workflows/builtin/index.d.ts +2 -0
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +5 -5
- package/dist/builtin/workflows/builtin/ralph-models.ts +25 -25
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +8 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-tool-execution-buffer.ts +47 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-pending-tools.ts +9 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-render-settings.ts +27 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +5 -6
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +3 -2
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +25 -4
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction-critical.d.ts +15 -0
- package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-critical.js +57 -0
- package/dist/core/compaction/context-compaction-critical.js.map +1 -0
- package/dist/core/compaction/context-compaction-eviction.d.ts +4 -0
- package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-eviction.js +172 -0
- package/dist/core/compaction/context-compaction-eviction.js.map +1 -0
- package/dist/core/compaction/context-compaction-runner.d.ts +7 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +97 -21
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts +3 -0
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.js +3 -3
- package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
- package/dist/core/extensions/loader-core.d.ts.map +1 -1
- package/dist/core/extensions/loader-core.js +6 -0
- package/dist/core/extensions/loader-core.js.map +1 -1
- package/dist/core/model-resolver-scope.d.ts +9 -0
- package/dist/core/model-resolver-scope.d.ts.map +1 -1
- package/dist/core/model-resolver-scope.js +12 -4
- package/dist/core/model-resolver-scope.js.map +1 -1
- package/dist/core/model-resolver.d.ts +3 -2
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/resource-loader-extensions.d.ts.map +1 -1
- package/dist/core/resource-loader-extensions.js +4 -0
- package/dist/core/resource-loader-extensions.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +11 -0
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/settings-manager-core.d.ts.map +1 -1
- package/dist/core/settings-manager-core.js +3 -2
- package/dist/core/settings-manager-core.js.map +1 -1
- package/dist/core/settings-storage.d.ts.map +1 -1
- package/dist/core/settings-storage.js +2 -1
- package/dist/core/settings-storage.js.map +1 -1
- package/dist/core/trust-manager.d.ts +9 -0
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +44 -2
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main-deferred-startup.d.ts +19 -0
- package/dist/main-deferred-startup.d.ts.map +1 -0
- package/dist/main-deferred-startup.js +21 -0
- package/dist/main-deferred-startup.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +24 -22
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts +2 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +34 -1
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js +2 -2
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.d.ts +5 -1
- package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +2 -2
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/utils/child-process.d.ts +8 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +39 -6
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/event-loop.d.ts +7 -0
- package/dist/utils/event-loop.d.ts.map +1 -0
- package/dist/utils/event-loop.js +14 -0
- package/dist/utils/event-loop.js.map +1 -0
- package/dist/utils/json.d.ts +4 -0
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js +8 -0
- package/dist/utils/json.js.map +1 -1
- package/docs/compaction.md +45 -27
- package/docs/settings.md +5 -1
- package/docs/workflows.md +6 -2
- package/npm-shrinkwrap.json +23 -23
- 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":"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","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
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 (
|
|
84
|
-
return createContextCompactionStopStream(requestModel, `Reached
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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":"AAAA,OAAO,EAAE,KAAK,EAAyC,MAAM,+BAA+B,CAAC;AAE7F,OAAO,EAAE,iCAAiC,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAClH,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EACN,oCAAoC,EACpC,4BAA4B,EAC5B,gCAAgC,EAChC,4BAA4B,EAC5B,0BAA0B,EAC1B,kBAAkB,GAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,iCAAiC,EAAE,oCAAoC,EAAE,MAAM,kCAAkC,CAAC;AAC3H,OAAO,EACN,mCAAmC,EACnC,wBAAwB,EACxB,6BAA6B,EAC7B,4BAA4B,EAC5B,mCAAmC,GACnC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EACN,4BAA4B,EAC5B,gCAAgC,EAChC,oCAAoC,GACpC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACN,2CAA2C,EAC3C,4BAA4B,EAC5B,kCAAkC,GAClC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAEnF,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAC/C,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,CAAC;AAYxD,SAAS,yCAAyC,CACjD,MAAkD,EAClD,UAAuC;IAEvC,MAAM,uBAAuB,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzE,MAAM,WAAW,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAAC;IAC7D,MAAM,cAAc,GAAG,MAAM;QAC5B,CAAC,CAAC,oCAAoC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAuB;QAC5G,CAAC,CAAC,SAAS,CAAC;IACb,MAAM,aAAa,GAAG,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,cAAc,0CAA0C,CAAC,CAAC,CAAC,EAAE,CAAC;IACpI,OAAO;QACN,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,cAAc,WAAW,iFAAiF,uBAAuB,KAAK,aAAa,gFAAgF,wBAAwB,OAAO,6BAA6B,yBAAyB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,uCAAuC,mCAAmC,oGAAoG,WAAW,GAAG;aAC1hB;SACD;QACD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACrB,CAAC;AACH,CAAC;AAED,SAAS,uCAAuC,CAC/C,KAAiB,EACjB,OAAoC,EACpC,UAA0C,EAC1C,YAAqB;IAErB,OAAO;QACN,IAAI,EAAE,WAAW;QACjB,OAAO;QACP,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,KAAK,CAAC,EAAE;QACf,KAAK,EAAE;YACN,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;SACpE;QACD,UAAU;QACV,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACrB,CAAC;AACH,CAAC;AAED,SAAS,iCAAiC,CAAC,KAAiB,EAAE,IAAY;IACzE,MAAM,MAAM,GAAG,iCAAiC,EAAE,CAAC;IACnD,cAAc,CAAC,GAAG,EAAE;QACnB,MAAM,OAAO,GAAG,uCAAuC,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACjG,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,gCAAgC,CAAC,KAAiB,EAAE,YAAoB;IAChF,OAAO,iBAAiB,CAAC,uCAAuC,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;AAC1H,CAAC;AAED,SAAS,gBAAgB,CACxB,MAAkD,EAClD,qBAAyC;IAEzC,OAAO,CACN,qBAAqB,KAAK,SAAS;QACnC,MAAM,KAAK,SAAS;QACpB,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,qBAAqB,CACjD,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CACzB,MAAkD,EAClD,UAAuC,EACvC,qBAAyC;IAEzC,IAAI,qBAAqB,KAAK,SAAS;QAAE,OAAO,gBAAgB,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAChG,OAAO,0BAA0B,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,0BAA0B,CAClC,GAAuB,EACvB,UAAuC,EACvC,MAAkD;IAElD,IAAI,CAAC,6BAA6B,CAAC,GAAG,EAAE,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,MAAM,cAAc,GAAG,MAAM,EAAE,2BAA2B,CAAC;IAC3D,OAAO,cAAc,KAAK,SAAS,IAAI,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,IAAI,cAAc,CAAC;AAChG,CAAC;AAQD,KAAK,UAAU,2BAA2B,CACzC,eAAsC,EACtC,KAAiB,EACjB,MAAc,EACd,OAAgC,EAChC,MAAoB,EACpB,aAAa,GAAkB,KAAK,EACpC,UAAU,GAAgC,iCAAiC,CAAC,eAAe,CAAC,EAC5F,OAAO,GAAoC,EAAE;IAE7C,MAAM,UAAU,GAA0B,EAAE,GAAG,eAAe,EAAE,UAAU,EAAE,CAAC;IAC7E,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;IACnF,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACvF,MAAM,cAAc,GAAG,oCAAoC,CAAC,UAAU,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,4BAA4B,CAAC,UAAU,EAAE,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC5H,MAAM,aAAa,GAAiB;QACnC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAC7C,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACrB,CAAC;IACF,MAAM,YAAY,GAAG,yBAAyB,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,GAAG,UAAU,EAAE,CAAC,CAAC;IAClH,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACvB,YAAY,EAAE;YACb,YAAY,EAAE,gCAAgC;YAC9C,KAAK;YACL,aAAa;YACb,KAAK,EAAE,YAAY,CAAC,KAAK;SACzB;QACD,aAAa,EAAE,UAAU;QACzB,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;YACxD,MAAM,aAAa,GAAG,YAAY,CAAC,kBAAkB,EAAE,CAAC;YACxD,IAAI,iBAAiB,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC;gBACjF,OAAO,iCAAiC,CACvC,YAAY,EACZ,mDAAmD,aAAa,CAAC,KAAK,CAAC,gBAAgB,MAAM,aAAa,CAAC,KAAK,CAAC,WAAW,2EAA2E,CACvM,CAAC;YACH,CAAC;YACD,IAAI,iBAAiB,IAAI,4BAA4B,EAAE,CAAC;gBACvD,OAAO,iCAAiC,CACvC,YAAY,EACZ,4CAA4C,4BAA4B,mDAAmD,CAC3H,CAAC;YACH,CAAC;YACD,iBAAiB,IAAI,CAAC,CAAC;YACvB,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,EAAE;gBAC1C,GAAG,aAAa;gBAChB,SAAS;gBACT,MAAM;gBACN,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,OAAO;aAC1C,CAAC,CAAC;QACJ,CAAC;KACD,CAAC,CAAC;IAEH,IAAI,qBAAyC,CAAC;IAC9C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,gBAAgB,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE;QAC/D,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,MAAM,EAAE,OAAO,IAAI,WAAW,CAAC,OAAO;YAAE,OAAO;QAChF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO;QAC/C,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS;YAAE,OAAO;QAC3F,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC;YAAE,OAAO;QACjF,IAAI,UAAU,IAAI,qCAAqC;YAAE,OAAO;QAChE,MAAM,aAAa,GAAG,YAAY,CAAC,kBAAkB,EAAE,CAAC;QACxD,IAAI,iBAAiB,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,qBAAqB,CAAC;YAAE,OAAO;QACxF,MAAM,WAAW,GAAG,4BAA4B,CAAC,aAAa,CAAC,CAAC;QAChE,IAAI,WAAW,KAAK,qBAAqB;YAAE,OAAO;QAClD,qBAAqB,GAAG,WAAW,CAAC;QACpC,UAAU,IAAI,CAAC,CAAC;QAChB,KAAK,CAAC,QAAQ,CAAC,yCAAyC,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC1C,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACvF,MAAM,IAAI,KAAK,CAAC,8BAA8B,0BAA0B,CAAC,KAAK,CAAC,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IACxH,CAAC;YAAS,CAAC;QACV,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACpD,gBAAgB,EAAE,CAAC;QACnB,cAAc,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACvF,IAAI,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAC9B,MAAM,qBAAqB,GAAG,0BAA0B,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACnG,IAAI,gCAAgC,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;YACvE,OAAO;gBACN,eAAe,EAAE,YAAY,CAAC,kBAAkB,EAAE;gBAClD,aAAa,EAAE,YAAY,CAAC,YAAY,EAAE;gBAC1C,aAAa,EAAE,qBAAqB,KAAK,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB;aACrG,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,qBAAqB,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACd,yFAAyF,mCAAmC,KAAK,4BAA4B,KAAK,mCAAmC,KAAK,wBAAwB,QAAQ,6BAA6B,GAAG,CAC1Q,CAAC;IACH,CAAC;IACD,OAAO;QACN,eAAe,EAAE,YAAY,CAAC,kBAAkB,EAAE;QAClD,aAAa,EAAE,YAAY,CAAC,YAAY,EAAE;QAC1C,aAAa,EAAE,SAAS;KACxB,CAAC;AACH,CAAC;AAED,SAAS,6BAA6B,CACrC,GAAuB,EACvB,UAAuC;IAEvC,OAAO,0BAA0B,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,2CAA2C,CACnD,QAA8C,EAC9C,UAAuC;IAEvC,MAAM,WAAW,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAAC;IAC7D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,8CAA8C,WAAW,wBAAwB,CAAC;IACpH,MAAM,cAAc,GAAG,QAAQ;SAC7B,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAChB,MAAM,SAAS,GAAG,gCAAgC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC5E,MAAM,aAAa,GAAG,OAAO,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,IAAI,CAAC,CAAC;QAC1E,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,mBAAmB,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtH,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,+BAA+B,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1G,MAAM,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,qBAAqB,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpG,OAAO,mBAAmB,SAAS,UAAU,aAAa,gCAAgC,eAAe,GAAG,aAAa,GAAG,iBAAiB,EAAE,CAAC;IACjJ,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,8CAA8C,WAAW,2BAA2B,cAAc,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAY;IACrC,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;AAC/F,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAY,EAAE,MAA+B,EAAE,MAAkD;IACnI,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,KAAK,CAAC,OAAO,KAAK,gDAAgD;QAAE,OAAO,IAAI,CAAC;IACpF,OAAO,MAAM,EAAE,2BAA2B,KAAK,SAAS,CAAC;AAC1D,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,WAAyC,EACzC,KAAiB,EACjB,MAAc,EACd,OAAgC,EAChC,MAAoB,EACpB,aAAa,GAAkB,KAAK,EACpC,MAAuC;IAEvC,MAAM,UAAU,GAAG,oCAAoC,CACtD,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,UAAU,CAAC,UAAU,EAC3D,WAAW,CAAC,UAAU,EAAE,KAAK,IAAI,WAAW,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,IAAI,6BAA6B,CAC1G,CAAC;IACF,MAAM,UAAU,GAA0B,EAAE,GAAG,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;IACpF,MAAM,QAAQ,GAAgC,EAAE,CAAC;IACjD,IAAI,CAAC;QACJ,MAAM,WAAW,GAAG,MAAM,2BAA2B,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;QAC7H,IAAI,0BAA0B,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC;YAAE,OAAO,WAAW,CAAC,eAAe,CAAC;QACpG,IAAI,gBAAgB,CAAC,WAAW,CAAC,eAAe,EAAE,MAAM,EAAE,qBAAqB,CAAC;YAAE,OAAO,WAAW,CAAC,eAAe,CAAC;QACrH,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,cAAc,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7F,IAAI,yBAAyB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC;YAAE,MAAM,cAAc,CAAC;QACpF,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,MAAM,EAAE,2BAA2B,KAAK,SAAS,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,IAAI,CAAC;QACJ,MAAM,kBAAkB,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAAC;QACpE,MAAM,kBAAkB,GAAG,kCAAkC,CAAC,UAAU,CAAC,CAAC;QAC1E,MAAM,WAAW,GAAG,MAAM,2BAA2B,CACpD,kBAAkB,EAClB,KAAK,EACL,MAAM,EACN,OAAO,EACP,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB;YACC,YAAY,EAAE,2CAA2C;YACzD,qBAAqB,EAAE,MAAM,CAAC,2BAA2B;SACzD,CACD,CAAC;QACF,IAAI,0BAA0B,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC;YAAE,OAAO,WAAW,CAAC,eAAe,CAAC;QACpG,IAAI,gBAAgB,CAAC,WAAW,CAAC,eAAe,EAAE,MAAM,CAAC,2BAA2B,CAAC;YAAE,OAAO,WAAW,CAAC,eAAe,CAAC;QAC1H,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,cAAc,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7F,IAAI,MAAM,EAAE,OAAO,IAAI,cAAc,CAAC,OAAO,KAAK,gDAAgD;YAAE,MAAM,cAAc,CAAC;QACzH,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,+BAA+B,CAAC,UAAU,EAAE,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACxF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,GAAG,2CAA2C,CAAC,QAAQ,EAAE,UAAU,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IACrG,CAAC;AACF,CAAC","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"]}
|