@bastani/atomic 0.9.5-alpha.7 → 0.9.5-alpha.8
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 +17 -2
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +17 -0
- package/dist/builtin/intercom/README.md +27 -21
- package/dist/builtin/intercom/broker/broker.ts +3 -6
- package/dist/builtin/intercom/broker/paths.ts +42 -5
- package/dist/builtin/intercom/broker/spawn.ts +78 -10
- package/dist/builtin/intercom/config.ts +6 -3
- package/dist/builtin/intercom/contact-supervisor-tool.ts +6 -4
- package/dist/builtin/intercom/index-heavy.ts +1 -1
- package/dist/builtin/intercom/index.ts +162 -130
- package/dist/builtin/intercom/intercom-tool.ts +9 -3
- package/dist/builtin/intercom/package.json +10 -1
- package/dist/builtin/intercom/result-renderers.ts +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/intercom/ui/inline-message.ts +2 -2
- package/dist/builtin/intercom/ui/session-list.ts +2 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +15 -48
- package/dist/builtin/subagents/src/tui/render-layout.ts +9 -0
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +27 -25
- package/dist/builtin/subagents/src/tui/render-widget.ts +46 -69
- package/dist/builtin/subagents/src/tui/render.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +11 -0
- package/dist/builtin/workflows/README.md +3 -1
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +3 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -2
- package/dist/builtin/workflows/builtin/goal-reducer.ts +21 -0
- package/dist/builtin/workflows/builtin/goal-review.ts +60 -6
- package/dist/builtin/workflows/builtin/goal-runner.ts +32 -21
- package/dist/builtin/workflows/builtin/goal-types.ts +7 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +52 -4
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +10 -3
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +23 -2
- package/dist/builtin/workflows/builtin/ralph-runner.ts +38 -16
- package/dist/builtin/workflows/builtin/review-convergence.ts +111 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/create-spec/SKILL.md +2 -0
- package/dist/builtin/workflows/src/durable/child-primitive.ts +12 -8
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +47 -2
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +28 -0
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +165 -27
- package/dist/builtin/workflows/src/durable/types.ts +14 -1
- package/dist/builtin/workflows/src/engine/run.ts +12 -13
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-continuation.ts +13 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +18 -19
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-unresolved-overflow.ts +38 -0
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +18 -1
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +23 -5
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/bun/internal-intercom-broker.d.ts +6 -0
- package/dist/bun/internal-intercom-broker.d.ts.map +1 -0
- package/dist/bun/internal-intercom-broker.js +39 -0
- package/dist/bun/internal-intercom-broker.js.map +1 -0
- package/dist/bun/split-loader.d.ts.map +1 -1
- package/dist/bun/split-loader.js +21 -8
- package/dist/bun/split-loader.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts +4 -5
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +49 -9
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +3 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +9 -3
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts +2 -2
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +1 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +2 -0
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +152 -4
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +15 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +4 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +36 -20
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/copilot-anthropic-sse-repair.d.ts +23 -0
- package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -0
- package/dist/core/copilot-anthropic-sse-repair.js +340 -0
- package/dist/core/copilot-anthropic-sse-repair.js.map +1 -0
- package/dist/core/copilot-gemini-reasoning.d.ts +16 -8
- package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
- package/dist/core/copilot-gemini-reasoning.js +27 -22
- package/dist/core/copilot-gemini-reasoning.js.map +1 -1
- package/dist/core/copilot-hosts.d.ts +12 -0
- package/dist/core/copilot-hosts.d.ts.map +1 -0
- package/dist/core/copilot-hosts.js +33 -0
- package/dist/core/copilot-hosts.js.map +1 -0
- package/dist/core/extensions/agent-events.d.ts +1 -1
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -5
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -0
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +6 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/main-deferred-startup.d.ts +12 -0
- package/dist/main-deferred-startup.d.ts.map +1 -1
- package/dist/main-deferred-startup.js +21 -0
- package/dist/main-deferred-startup.js.map +1 -1
- package/dist/main-early-input.d.ts +41 -0
- package/dist/main-early-input.d.ts.map +1 -0
- package/dist/main-early-input.js +147 -0
- package/dist/main-early-input.js.map +1 -0
- package/dist/main.d.ts +0 -6
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +19 -13
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +15 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +24 -0
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +279 -181
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +36 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.d.ts +3 -0
- 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-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +21 -9
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +6 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/docs/compaction.md +4 -0
- package/docs/json.md +3 -1
- package/docs/providers.md +1 -0
- package/docs/rpc.md +3 -1
- package/docs/settings.md +26 -0
- package/docs/terminal-setup.md +4 -0
- package/docs/usage.md +2 -2
- package/docs/workflows.md +13 -3
- package/npm-shrinkwrap.json +513 -23
- package/package.json +3 -2
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
|
|
16
16
|
import type { Store } from "./store.js";
|
|
17
17
|
import type { RunSnapshot } from "./store-types.js";
|
|
18
|
-
import type { WorkflowInputValues } from "./types.js";
|
|
18
|
+
import type { WorkflowInputValues, WorkflowSerializableValue } from "./types.js";
|
|
19
19
|
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
// Config option
|
|
@@ -32,7 +32,25 @@ export type ResumeInFlight = "ask" | "auto" | "never";
|
|
|
32
32
|
export interface SessionEntry {
|
|
33
33
|
readonly id: string;
|
|
34
34
|
readonly type: string;
|
|
35
|
-
readonly payload
|
|
35
|
+
readonly payload?: Record<string, WorkflowSerializableValue>;
|
|
36
|
+
readonly customType?: string;
|
|
37
|
+
readonly data?: Record<string, WorkflowSerializableValue>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface NormalizedSessionEntry {
|
|
41
|
+
readonly id: string;
|
|
42
|
+
readonly type: string;
|
|
43
|
+
readonly payload: Record<string, WorkflowSerializableValue>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function normalizeSessionEntries(entries: readonly SessionEntry[]): readonly NormalizedSessionEntry[] {
|
|
47
|
+
return entries.flatMap((entry): readonly NormalizedSessionEntry[] => {
|
|
48
|
+
if (entry.type === "custom" && typeof entry.customType === "string" && entry.data !== undefined) {
|
|
49
|
+
return [{ id: entry.id, type: entry.customType, payload: entry.data }];
|
|
50
|
+
}
|
|
51
|
+
if (entry.payload !== undefined) return [{ id: entry.id, type: entry.type, payload: entry.payload }];
|
|
52
|
+
return [];
|
|
53
|
+
});
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
/** Structural type for pi's sessionManager (optional — degrades gracefully). */
|
|
@@ -69,7 +87,7 @@ export function scanInFlightRuns(entries: readonly SessionEntry[]): InFlightRun[
|
|
|
69
87
|
const started = new Map<string, { name: string; inputs: WorkflowInputValues; startTs: number; stageIds: string[] }>();
|
|
70
88
|
const ended = new Set<string>();
|
|
71
89
|
|
|
72
|
-
for (const entry of entries) {
|
|
90
|
+
for (const entry of normalizeSessionEntries(entries)) {
|
|
73
91
|
if (entry.type === "workflow.run.start") {
|
|
74
92
|
const runId = entry.payload["runId"];
|
|
75
93
|
const name = entry.payload["name"];
|
|
@@ -168,8 +186,8 @@ export function restoreOnSessionStart(
|
|
|
168
186
|
const getEntries = sessionManager.getEntries;
|
|
169
187
|
if (typeof getEntries !== "function") return;
|
|
170
188
|
|
|
171
|
-
const entries = getEntries.call(sessionManager);
|
|
172
|
-
const sessionEntries = entries
|
|
189
|
+
const entries = getEntries.call(sessionManager) as readonly SessionEntry[];
|
|
190
|
+
const sessionEntries = normalizeSessionEntries(entries);
|
|
173
191
|
restoreTerminalRuns(sessionEntries, store);
|
|
174
192
|
const inFlight = scanInFlightRuns(sessionEntries);
|
|
175
193
|
if (inFlight.length === 0) return;
|
|
@@ -112,6 +112,8 @@ export interface RunEndPayload {
|
|
|
112
112
|
readonly failedStageId?: string;
|
|
113
113
|
readonly resumable?: boolean;
|
|
114
114
|
readonly retryAfterMs?: number;
|
|
115
|
+
readonly endedAt?: number;
|
|
116
|
+
readonly durationMs?: number;
|
|
115
117
|
readonly ts: number;
|
|
116
118
|
}
|
|
117
119
|
|
|
@@ -254,6 +256,8 @@ export function appendRunEnd(api: PersistenceAPI, payload: RunEndPayload): void
|
|
|
254
256
|
...(terminalPayload.failedStageId !== undefined ? { failedStageId: terminalPayload.failedStageId } : {}),
|
|
255
257
|
...(terminalPayload.resumable !== undefined ? { resumable: terminalPayload.resumable } : {}),
|
|
256
258
|
...(terminalPayload.retryAfterMs !== undefined ? { retryAfterMs: terminalPayload.retryAfterMs } : {}),
|
|
259
|
+
...(terminalPayload.endedAt !== undefined ? { endedAt: terminalPayload.endedAt } : {}),
|
|
260
|
+
...(terminalPayload.durationMs !== undefined ? { durationMs: terminalPayload.durationMs } : {}),
|
|
257
261
|
ts: terminalPayload.ts,
|
|
258
262
|
});
|
|
259
263
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const INTERNAL_INTERCOM_BROKER_ARG = "--atomic-internal-intercom-broker";
|
|
2
|
+
export declare function getBundledIntercomBrokerPath(executablePath?: string): string;
|
|
3
|
+
export declare function isBundledIntercomBrokerPath(modulePath: string, executablePath?: string, platform?: NodeJS.Platform): boolean;
|
|
4
|
+
export declare function validateInternalIntercomBrokerPath(modulePath: string | undefined, executablePath?: string, platform?: NodeJS.Platform): string;
|
|
5
|
+
export declare function importInternalIntercomBroker(modulePath: string, executablePath?: string, platform?: NodeJS.Platform): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=internal-intercom-broker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-intercom-broker.d.ts","sourceRoot":"","sources":["../../src/bun/internal-intercom-broker.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,4BAA4B,sCAAsC,CAAC;AAEhF,wBAAgB,4BAA4B,CAAC,cAAc,GAAE,MAAyB,GAAG,MAAM,CAE9F;AAOD,wBAAgB,2BAA2B,CAC1C,UAAU,EAAE,MAAM,EAClB,cAAc,GAAE,MAAyB,EACzC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C,OAAO,CAET;AAED,wBAAgB,kCAAkC,CACjD,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,cAAc,GAAE,MAAyB,EACzC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C,MAAM,CAQR;AAED,wBAAsB,4BAA4B,CACjD,UAAU,EAAE,MAAM,EAClB,cAAc,GAAE,MAAyB,EACzC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C,OAAO,CAAC,IAAI,CAAC,CAMf","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nexport const INTERNAL_INTERCOM_BROKER_ARG = \"--atomic-internal-intercom-broker\";\n\nexport function getBundledIntercomBrokerPath(executablePath: string = process.execPath): string {\n\treturn join(dirname(executablePath), \"builtin\", \"intercom\", \"broker\", \"broker.ts\");\n}\n\nfunction comparablePath(path: string, platform: NodeJS.Platform): string {\n\tconst resolved = resolve(path);\n\treturn platform === \"win32\" ? resolved.toLowerCase() : resolved;\n}\n\nexport function isBundledIntercomBrokerPath(\n\tmodulePath: string,\n\texecutablePath: string = process.execPath,\n\tplatform: NodeJS.Platform = process.platform,\n): boolean {\n\treturn comparablePath(modulePath, platform) === comparablePath(getBundledIntercomBrokerPath(executablePath), platform);\n}\n\nexport function validateInternalIntercomBrokerPath(\n\tmodulePath: string | undefined,\n\texecutablePath: string = process.execPath,\n\tplatform: NodeJS.Platform = process.platform,\n): string {\n\tif (!modulePath) {\n\t\tthrow new Error(\"Atomic internal intercom broker module path is required\");\n\t}\n\tif (!isBundledIntercomBrokerPath(modulePath, executablePath, platform)) {\n\t\tthrow new Error(\"Atomic internal intercom broker path must resolve to the bundled intercom broker module\");\n\t}\n\treturn resolve(modulePath);\n}\n\nexport async function importInternalIntercomBroker(\n\tmodulePath: string,\n\texecutablePath: string = process.execPath,\n\tplatform: NodeJS.Platform = process.platform,\n): Promise<void> {\n\tconst brokerPath = validateInternalIntercomBrokerPath(modulePath, executablePath, platform);\n\tif (!existsSync(brokerPath)) {\n\t\tthrow new Error(`Atomic internal intercom broker module not found at ${brokerPath}`);\n\t}\n\tawait import(pathToFileURL(brokerPath).href);\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { dirname, join, resolve } from "node:path";
|
|
11
|
+
import { pathToFileURL } from "node:url";
|
|
12
|
+
export const INTERNAL_INTERCOM_BROKER_ARG = "--atomic-internal-intercom-broker";
|
|
13
|
+
export function getBundledIntercomBrokerPath(executablePath = process.execPath) {
|
|
14
|
+
return join(dirname(executablePath), "builtin", "intercom", "broker", "broker.ts");
|
|
15
|
+
}
|
|
16
|
+
function comparablePath(path, platform) {
|
|
17
|
+
const resolved = resolve(path);
|
|
18
|
+
return platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
19
|
+
}
|
|
20
|
+
export function isBundledIntercomBrokerPath(modulePath, executablePath = process.execPath, platform = process.platform) {
|
|
21
|
+
return comparablePath(modulePath, platform) === comparablePath(getBundledIntercomBrokerPath(executablePath), platform);
|
|
22
|
+
}
|
|
23
|
+
export function validateInternalIntercomBrokerPath(modulePath, executablePath = process.execPath, platform = process.platform) {
|
|
24
|
+
if (!modulePath) {
|
|
25
|
+
throw new Error("Atomic internal intercom broker module path is required");
|
|
26
|
+
}
|
|
27
|
+
if (!isBundledIntercomBrokerPath(modulePath, executablePath, platform)) {
|
|
28
|
+
throw new Error("Atomic internal intercom broker path must resolve to the bundled intercom broker module");
|
|
29
|
+
}
|
|
30
|
+
return resolve(modulePath);
|
|
31
|
+
}
|
|
32
|
+
export async function importInternalIntercomBroker(modulePath, executablePath = process.execPath, platform = process.platform) {
|
|
33
|
+
const brokerPath = validateInternalIntercomBrokerPath(modulePath, executablePath, platform);
|
|
34
|
+
if (!existsSync(brokerPath)) {
|
|
35
|
+
throw new Error(`Atomic internal intercom broker module not found at ${brokerPath}`);
|
|
36
|
+
}
|
|
37
|
+
await import(__rewriteRelativeImportExtension(pathToFileURL(brokerPath).href));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=internal-intercom-broker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-intercom-broker.js","sourceRoot":"","sources":["../../src/bun/internal-intercom-broker.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,4BAA4B,GAAG,mCAAmC,CAAC;AAEhF,MAAM,UAAU,4BAA4B,CAAC,cAAc,GAAW,OAAO,CAAC,QAAQ;IACrF,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,QAAyB;IAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAC1C,UAAkB,EAClB,cAAc,GAAW,OAAO,CAAC,QAAQ,EACzC,QAAQ,GAAoB,OAAO,CAAC,QAAQ;IAE5C,OAAO,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,cAAc,CAAC,4BAA4B,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,CAAC;AACxH,CAAC;AAED,MAAM,UAAU,kCAAkC,CACjD,UAA8B,EAC9B,cAAc,GAAW,OAAO,CAAC,QAAQ,EACzC,QAAQ,GAAoB,OAAO,CAAC,QAAQ;IAE5C,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,2BAA2B,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,yFAAyF,CAAC,CAAC;IAC5G,CAAC;IACD,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CACjD,UAAkB,EAClB,cAAc,GAAW,OAAO,CAAC,QAAQ,EACzC,QAAQ,GAAoB,OAAO,CAAC,QAAQ;IAE5C,MAAM,UAAU,GAAG,kCAAkC,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;IAC5F,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,uDAAuD,UAAU,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,MAAM,kCAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,EAAC,CAAC;AAC9C,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nexport const INTERNAL_INTERCOM_BROKER_ARG = \"--atomic-internal-intercom-broker\";\n\nexport function getBundledIntercomBrokerPath(executablePath: string = process.execPath): string {\n\treturn join(dirname(executablePath), \"builtin\", \"intercom\", \"broker\", \"broker.ts\");\n}\n\nfunction comparablePath(path: string, platform: NodeJS.Platform): string {\n\tconst resolved = resolve(path);\n\treturn platform === \"win32\" ? resolved.toLowerCase() : resolved;\n}\n\nexport function isBundledIntercomBrokerPath(\n\tmodulePath: string,\n\texecutablePath: string = process.execPath,\n\tplatform: NodeJS.Platform = process.platform,\n): boolean {\n\treturn comparablePath(modulePath, platform) === comparablePath(getBundledIntercomBrokerPath(executablePath), platform);\n}\n\nexport function validateInternalIntercomBrokerPath(\n\tmodulePath: string | undefined,\n\texecutablePath: string = process.execPath,\n\tplatform: NodeJS.Platform = process.platform,\n): string {\n\tif (!modulePath) {\n\t\tthrow new Error(\"Atomic internal intercom broker module path is required\");\n\t}\n\tif (!isBundledIntercomBrokerPath(modulePath, executablePath, platform)) {\n\t\tthrow new Error(\"Atomic internal intercom broker path must resolve to the bundled intercom broker module\");\n\t}\n\treturn resolve(modulePath);\n}\n\nexport async function importInternalIntercomBroker(\n\tmodulePath: string,\n\texecutablePath: string = process.execPath,\n\tplatform: NodeJS.Platform = process.platform,\n): Promise<void> {\n\tconst brokerPath = validateInternalIntercomBrokerPath(modulePath, executablePath, platform);\n\tif (!existsSync(brokerPath)) {\n\t\tthrow new Error(`Atomic internal intercom broker module not found at ${brokerPath}`);\n\t}\n\tawait import(pathToFileURL(brokerPath).href);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-loader.d.ts","sourceRoot":"","sources":["../../src/bun/split-loader.ts"],"names":[],"mappings":"","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nconst APP_NAME = \"atomic\";\n\nprocess.title = APP_NAME;\nprocess.env.ATOMIC_CODING_AGENT = \"true\";\nprocess.emitWarning = (() => {}) as typeof process.emitWarning;\n\nconst args = process.argv.slice(2);\n\nfunction readVersion(): string {\n\ttry {\n\t\tconst packageJsonPath = join(dirname(process.execPath), \"package.json\");\n\t\tconst pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { version?: unknown };\n\t\treturn typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n\t} catch {\n\t\treturn \"0.0.0\";\n\t}\n}\n\nif (args[0] === \"--version\" || args[0] === \"-v\") {\n\tconsole.log(readVersion());\n\tprocess.exit(0);\n}\n\
|
|
1
|
+
{"version":3,"file":"split-loader.d.ts","sourceRoot":"","sources":["../../src/bun/split-loader.ts"],"names":[],"mappings":"","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { INTERNAL_INTERCOM_BROKER_ARG, importInternalIntercomBroker } from \"./internal-intercom-broker.ts\";\n\nconst APP_NAME = \"atomic\";\n\nprocess.title = APP_NAME;\nprocess.env.ATOMIC_CODING_AGENT = \"true\";\nprocess.emitWarning = (() => {}) as typeof process.emitWarning;\n\nconst args = process.argv.slice(2);\n\nfunction readVersion(): string {\n\ttry {\n\t\tconst packageJsonPath = join(dirname(process.execPath), \"package.json\");\n\t\tconst pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { version?: unknown };\n\t\treturn typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n\t} catch {\n\t\treturn \"0.0.0\";\n\t}\n}\n\nif (args[0] === INTERNAL_INTERCOM_BROKER_ARG) {\n\tif (args.length !== 2) {\n\t\tconsole.error(`Atomic startup error: ${INTERNAL_INTERCOM_BROKER_ARG} requires exactly one broker module path`);\n\t\tprocess.exit(1);\n\t}\n\tvoid importInternalIntercomBroker(args[1]).catch((error: Error) => {\n\t\tconsole.error(`Atomic startup error: ${error.message}`);\n\t\tprocess.exit(1);\n\t});\n} else {\n\tif (args[0] === \"--version\" || args[0] === \"-v\") {\n\t\tconsole.log(readVersion());\n\t\tprocess.exit(0);\n\t}\n\n\tconst appPath = join(dirname(process.execPath), \"app.js\");\n\tif (!existsSync(appPath)) {\n\t\tconsole.error(`Atomic startup error: missing app bundle at ${appPath}`);\n\t\tprocess.exit(1);\n\t}\n\n\tvoid import(pathToFileURL(appPath).href);\n}\n"]}
|
package/dist/bun/split-loader.js
CHANGED
|
@@ -9,6 +9,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
9
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
10
|
import { dirname, join } from "node:path";
|
|
11
11
|
import { pathToFileURL } from "node:url";
|
|
12
|
+
import { INTERNAL_INTERCOM_BROKER_ARG, importInternalIntercomBroker } from "./internal-intercom-broker.js";
|
|
12
13
|
const APP_NAME = "atomic";
|
|
13
14
|
process.title = APP_NAME;
|
|
14
15
|
process.env.ATOMIC_CODING_AGENT = "true";
|
|
@@ -24,14 +25,26 @@ function readVersion() {
|
|
|
24
25
|
return "0.0.0";
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
if (args[0] ===
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
if (args[0] === INTERNAL_INTERCOM_BROKER_ARG) {
|
|
29
|
+
if (args.length !== 2) {
|
|
30
|
+
console.error(`Atomic startup error: ${INTERNAL_INTERCOM_BROKER_ARG} requires exactly one broker module path`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
void importInternalIntercomBroker(args[1]).catch((error) => {
|
|
34
|
+
console.error(`Atomic startup error: ${error.message}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
30
37
|
}
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
else {
|
|
39
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
40
|
+
console.log(readVersion());
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
const appPath = join(dirname(process.execPath), "app.js");
|
|
44
|
+
if (!existsSync(appPath)) {
|
|
45
|
+
console.error(`Atomic startup error: missing app bundle at ${appPath}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
void import(__rewriteRelativeImportExtension(pathToFileURL(appPath).href));
|
|
35
49
|
}
|
|
36
|
-
void import(__rewriteRelativeImportExtension(pathToFileURL(appPath).href));
|
|
37
50
|
//# sourceMappingURL=split-loader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-loader.js","sourceRoot":"","sources":["../../src/bun/split-loader.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"split-loader.js","sourceRoot":"","sources":["../../src/bun/split-loader.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAE3G,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAE1B,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC;AACzB,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,MAAM,CAAC;AACzC,OAAO,CAAC,WAAW,GAAG,CAAC,GAAG,EAAE,GAAE,CAAC,CAA+B,CAAC;AAE/D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,SAAS,WAAW;IACnB,IAAI,CAAC;QACJ,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,CAAC;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAA0B,CAAC;QACvF,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,OAAO,CAAC;IAChB,CAAC;AACF,CAAC;AAED,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,4BAA4B,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,yBAAyB,4BAA4B,0CAA0C,CAAC,CAAC;QAC/G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;QACjE,OAAO,CAAC,KAAK,CAAC,yBAAyB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACJ,CAAC;KAAM,CAAC;IACP,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,+CAA+C,OAAO,EAAE,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,MAAM,kCAAC,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,EAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { INTERNAL_INTERCOM_BROKER_ARG, importInternalIntercomBroker } from \"./internal-intercom-broker.ts\";\n\nconst APP_NAME = \"atomic\";\n\nprocess.title = APP_NAME;\nprocess.env.ATOMIC_CODING_AGENT = \"true\";\nprocess.emitWarning = (() => {}) as typeof process.emitWarning;\n\nconst args = process.argv.slice(2);\n\nfunction readVersion(): string {\n\ttry {\n\t\tconst packageJsonPath = join(dirname(process.execPath), \"package.json\");\n\t\tconst pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { version?: unknown };\n\t\treturn typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n\t} catch {\n\t\treturn \"0.0.0\";\n\t}\n}\n\nif (args[0] === INTERNAL_INTERCOM_BROKER_ARG) {\n\tif (args.length !== 2) {\n\t\tconsole.error(`Atomic startup error: ${INTERNAL_INTERCOM_BROKER_ARG} requires exactly one broker module path`);\n\t\tprocess.exit(1);\n\t}\n\tvoid importInternalIntercomBroker(args[1]).catch((error: Error) => {\n\t\tconsole.error(`Atomic startup error: ${error.message}`);\n\t\tprocess.exit(1);\n\t});\n} else {\n\tif (args[0] === \"--version\" || args[0] === \"-v\") {\n\t\tconsole.log(readVersion());\n\t\tprocess.exit(0);\n\t}\n\n\tconst appPath = join(dirname(process.execPath), \"app.js\");\n\tif (!existsSync(appPath)) {\n\t\tconsole.error(`Atomic startup error: missing app bundle at ${appPath}`);\n\t\tprocess.exit(1);\n\t}\n\n\tvoid import(pathToFileURL(appPath).href);\n}\n"]}
|
|
@@ -10,19 +10,18 @@ export declare function _dropTrailingAutoCompactionRetryAssistantIfPresent(this:
|
|
|
10
10
|
/**
|
|
11
11
|
* Internal: schedule a live post-event continuation probe after compaction_end listeners can flush queues.
|
|
12
12
|
*/
|
|
13
|
-
export declare function _schedulePostAutoCompactionContinuationProbe(this: AgentSession,
|
|
13
|
+
export declare function _schedulePostAutoCompactionContinuationProbe(this: AgentSession, reason: "overflow" | "threshold", willRetry: boolean): void;
|
|
14
|
+
export declare function _awaitPendingOverflowPostCompactionContinuation(this: AgentSession): Promise<void>;
|
|
14
15
|
/**
|
|
15
16
|
* Internal: resume generation after successful auto-compaction only when active work remains.
|
|
16
17
|
*/
|
|
17
|
-
export declare function _resumeAfterAutoCompaction(this: AgentSession): void
|
|
18
|
-
/**
|
|
19
|
-
* Internal: Run auto-compaction with events.
|
|
20
|
-
*/
|
|
18
|
+
export declare function _resumeAfterAutoCompaction(this: AgentSession): Promise<void>;
|
|
21
19
|
export declare function _runAutoCompaction(this: AgentSession, reason: "overflow" | "threshold", willRetry: boolean): Promise<void>;
|
|
22
20
|
/**
|
|
23
21
|
* Toggle auto-compaction setting.
|
|
24
22
|
*/
|
|
25
23
|
export declare const agentSessionAutoCompactionMethods: {
|
|
24
|
+
_awaitPendingOverflowPostCompactionContinuation: typeof _awaitPendingOverflowPostCompactionContinuation;
|
|
26
25
|
_checkCompaction: typeof _checkCompaction;
|
|
27
26
|
_isCopilotServerCapBelowSelectedContextWindow: typeof _isCopilotServerCapBelowSelectedContextWindow;
|
|
28
27
|
_dropTrailingAutoCompactionRetryAssistantIfPresent: typeof _dropTrailingAutoCompactionRetryAssistantIfPresent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session-auto-compaction.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-auto-compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMrE,OAAO,KAAK,EAAE,2BAA2B,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE9F,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA+FrI;AAGD,wBAAgB,6CAA6C,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAQ7H;AAED,wBAAgB,mCAAmC,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAE/F;AAED;;GAEG;AAEH,wBAAgB,kDAAkD,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAQ3F;AAED;;GAEG;AAEH,wBAAgB,4CAA4C,CAAC,IAAI,EAAE,YAAY,EAC9E,OAAO,EAAE,UAAU,GAAG,WAAW,EACjC,SAAS,EAAE,OAAO,GAChB,IAAI,CAiBN;AAED;;GAEG;AAEH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CASnE;AAED;;GAEG;AAEH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,GAAG,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEhI;AAED;;GAEG;AAEH,eAAO,MAAM,iCAAiC;;;;;;;CAO7C,CAAC","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai/compat\";\nimport { isContextOverflow } from \"@earendil-works/pi-ai/compat\";\nimport { getEffectiveInputBudget } from \"./context-window.ts\";\nimport { parseCopilotPromptLimitError } from \"./copilot-errors.ts\";\nimport { calculateContextTokens, estimateContextTokens, shouldCompact } from \"./compaction/index.ts\";\nimport { getLatestCompactionBoundaryEntry } from \"./session-manager.ts\";\nimport type { AgentSessionInternalSurface as AgentSession } from \"./agent-session-methods.ts\";\n\nexport async function _checkCompaction(this: AgentSession, assistantMessage: AssistantMessage, skipAbortedCheck = true): Promise<void> {\n\tconst settings = this.settingsManager.getCompactionSettings();\n\tif (!settings.enabled) return;\n\n\t// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false\n\tif (skipAbortedCheck && assistantMessage.stopReason === \"aborted\") return;\n\n\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t// Skip overflow check if the message came from a different model.\n\t// This handles the case where user switched from a smaller-context model (e.g. opus)\n\t// to a larger-context model (e.g. codex) - the overflow error from the old model\n\t// shouldn't trigger compaction for the new model.\n\tconst sameModel =\n\t\tthis.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n\n\t// Skip compaction checks if this assistant message is older than the latest\n\t// compaction boundary. This prevents a stale pre-compaction usage/error\n\t// from retriggering compaction on the first prompt after compaction.\n\tconst compactionBoundaryEntry = getLatestCompactionBoundaryEntry(this.sessionManager.getBranch());\n\tconst assistantIsFromBeforeCompactionBoundary =\n\t\tcompactionBoundaryEntry !== null &&\n\t\tassistantMessage.timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime();\n\tif (assistantIsFromBeforeCompactionBoundary) {\n\t\treturn;\n\t}\n\n\t// Case 1: Overflow - LLM returned context overflow error\n\t// When Copilot rejects a 1m client-budget prompt at a lower server cap (for example\n\t// because long-context/usage-based billing entitlement is missing), leave the friendly\n\t// error visible instead of auto-compacting down to a smaller server tier silently.\n\tif (sameModel && this._isCopilotServerCapBelowSelectedContextWindow(assistantMessage)) {\n\t\treturn;\n\t}\n\tif (sameModel && isContextOverflow(assistantMessage, contextWindow)) {\n\t\tconst willRetry = assistantMessage.stopReason !== \"stop\";\n\t\tif (!willRetry) {\n\t\t\tawait this._runAutoCompaction(\"overflow\", false);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._overflowRecoveryAttempted) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"overflow\",\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\terrorMessage:\n\t\t\t\t\t\"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\",\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._overflowRecoveryAttempted = true;\n\t\t// Remove the error message from agent state (it IS saved to session for history,\n\t\t// but we don't want it in context for the retry)\n\t\tconst messages = this.agent.state.messages;\n\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t}\n\t\tawait this._runAutoCompaction(\"overflow\", willRetry);\n\t\treturn;\n\t}\n\n\t// Case 2: Threshold - context is getting large\n\t// For error messages (no usage data), estimate from last successful response.\n\t// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.\n\tlet contextTokens: number;\n\tif (assistantMessage.stopReason === \"error\") {\n\t\tconst messages = this.agent.state.messages;\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex === null) return; // No usage data at all\n\t\t// Verify the usage source is post-compaction. Kept pre-compaction messages\n\t\t// have stale usage reflecting the old (larger) context and would falsely\n\t\t// trigger compaction right after one just finished.\n\t\tconst usageMsg = messages[estimate.lastUsageIndex];\n\t\tif (\n\t\t\tcompactionBoundaryEntry &&\n\t\t\tusageMsg.role === \"assistant\" &&\n\t\t\t(usageMsg as AssistantMessage).timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime()\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tcontextTokens = estimate.tokens;\n\t} else {\n\t\tcontextTokens = calculateContextTokens(assistantMessage.usage);\n\t}\n\t// Compact against the effective input budget (the hard prompt cap for providers like Copilot\n\t// that advertise a larger total window) so we compact before overrunning the server-side limit\n\t// rather than relying on reactive overflow recovery near the cap.\n\tconst compactionBudget = this.model ? getEffectiveInputBudget(this.model) : contextWindow;\n\tif (shouldCompact(contextTokens, compactionBudget, settings)) {\n\t\tawait this._runAutoCompaction(\"threshold\", shouldRetryAfterThresholdCompaction(assistantMessage));\n\t}\n}\n\n\nexport function _isCopilotServerCapBelowSelectedContextWindow(this: AgentSession, assistantMessage: AssistantMessage): boolean {\n\tif (!this.model || this.model.provider !== \"github-copilot\" || !assistantMessage.errorMessage) return false;\n\tconst promptLimitError = parseCopilotPromptLimitError(assistantMessage.errorMessage);\n\t// Compare against the effective input budget (the model's real prompt cap), not the displayed\n\t// total window. A rejection at the prompt cap is a normal overflow we should compact-and-retry;\n\t// only a rejection *below* the cap (e.g. a missing long-context entitlement dropping the account\n\t// to a lower server tier) keeps the friendly error visible instead of silently compacting down.\n\treturn promptLimitError !== undefined && getEffectiveInputBudget(this.model) > promptLimitError.limitTokens;\n}\n\nexport function shouldRetryAfterThresholdCompaction(assistantMessage: AssistantMessage): boolean {\n\treturn assistantMessage.stopReason === \"length\" && assistantMessage.usage.output > 0;\n}\n\n/**\n * Internal: remove an incomplete assistant from retry context before auto-continuing after compaction.\n */\n\nexport function _dropTrailingAutoCompactionRetryAssistantIfPresent(this: AgentSession): void {\n\tconst messages = this.agent.state.messages;\n\tconst lastMsg = messages[messages.length - 1];\n\tif (lastMsg?.role !== \"assistant\") return;\n\tconst stopReason = (lastMsg as AssistantMessage).stopReason;\n\tif (stopReason === \"error\" || stopReason === \"length\") {\n\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t}\n}\n\n/**\n * Internal: schedule a live post-event continuation probe after compaction_end listeners can flush queues.\n */\n\nexport function _schedulePostAutoCompactionContinuationProbe(this: AgentSession,\n\t_reason: \"overflow\" | \"threshold\",\n\twillRetry: boolean,\n): void {\n\tsetTimeout(() => {\n\t\tif (this.isCompacting || this.isStreaming) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tthis._resumeAfterAutoCompaction();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.agent.hasQueuedMessages()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._resumeAfterAutoCompaction();\n\t}, 100);\n}\n\n/**\n * Internal: resume generation after successful auto-compaction only when active work remains.\n */\n\nexport function _resumeAfterAutoCompaction(this: AgentSession): void {\n\tvoid this._runAgentContinue().catch((error) => {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis._emit({\n\t\t\ttype: \"agent_continue_error\",\n\t\t\tsource: \"post_compaction\",\n\t\t\terrorMessage: `Post-compaction continuation failed: ${message}`,\n\t\t});\n\t});\n}\n\n/**\n * Internal: Run auto-compaction with events.\n */\n\nexport async function _runAutoCompaction(this: AgentSession, reason: \"overflow\" | \"threshold\", willRetry: boolean): Promise<void> {\n\tthis._emit({ type: \"compaction_start\", reason });\n\tthis._autoCompactionAbortController = new AbortController();\n\n\ttry {\n\t\tif (!this.model) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Auth is resolved lazily: only called when the planner fallback is needed.\n\t\t// This allows extension-provided deletion requests to run before auth is checked,\n\t\t// enabling local extension compaction even when API credentials are unavailable.\n\t\t// Auto-mode resolver returns undefined (rather than throwing) when auth is missing;\n\t\t// overflow recovery then falls back to deterministic no-auth eviction, while\n\t\t// threshold compaction keeps the previous no-op behavior.\n\t\tconst model = this.model;\n\t\tconst result = await this._applyContextVerbatimCompaction({\n\t\t\tresolvePlannerAuth: async () => {\n\t\t\t\tconst authResult = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\t\t\tif (!authResult.ok || !authResult.apiKey) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn { apiKey: authResult.apiKey, headers: authResult.headers };\n\t\t\t},\n\t\t\tabortController: this._autoCompactionAbortController,\n\t\t\tbackupLabel: reason === \"overflow\" ? \"overflow-auto-compact\" : \"auto-compact\",\n\t\t\treason,\n\t\t});\n\t\tif (!result) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tthis._dropTrailingAutoCompactionRetryAssistantIfPresent();\n\t\t}\n\n\t\tthis._emit({ type: \"compaction_end\", reason, result, aborted: false, willRetry });\n\t\tthis._schedulePostAutoCompactionContinuationProbe(reason, willRetry);\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : \"compaction failed\";\n\t\tconst aborted = errorMessage === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\tthis._emit({\n\t\t\ttype: \"compaction_end\",\n\t\t\treason,\n\t\t\tresult: undefined,\n\t\t\taborted,\n\t\t\twillRetry: false,\n\t\t\terrorMessage: aborted\n\t\t\t\t? undefined\n\t\t\t\t: reason === \"overflow\"\n\t\t\t\t\t? `Context overflow recovery failed: ${errorMessage}`\n\t\t\t\t\t: `Auto-compaction failed: ${errorMessage}`,\n\t\t});\n\t} finally {\n\t\tthis._autoCompactionAbortController = undefined;\n\t}\n}\n\n/**\n * Toggle auto-compaction setting.\n */\n\nexport const agentSessionAutoCompactionMethods = {\n\t_checkCompaction,\n\t_isCopilotServerCapBelowSelectedContextWindow,\n\t_dropTrailingAutoCompactionRetryAssistantIfPresent,\n\t_schedulePostAutoCompactionContinuationProbe,\n\t_resumeAfterAutoCompaction,\n\t_runAutoCompaction,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"agent-session-auto-compaction.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-auto-compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMrE,OAAO,KAAK,EAAE,2BAA2B,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE9F,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgGrI;AAGD,wBAAgB,6CAA6C,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAQ7H;AAED,wBAAgB,mCAAmC,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAE/F;AAED;;GAEG;AAEH,wBAAgB,kDAAkD,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAQ3F;AAED;;GAEG;AAEH,wBAAgB,4CAA4C,CAAC,IAAI,EAAE,YAAY,EAC9E,MAAM,EAAE,UAAU,GAAG,WAAW,EAChC,SAAS,EAAE,OAAO,GAChB,IAAI,CAyCN;AAED,wBAAsB,+CAA+C,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvG;AAED;;GAEG;AAEH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAWlF;AAOD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,GAAG,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAyEhI;AAED;;GAEG;AAEH,eAAO,MAAM,iCAAiC;;;;;;;;CAQ7C,CAAC","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai/compat\";\nimport { isContextOverflow } from \"@earendil-works/pi-ai/compat\";\nimport { getEffectiveInputBudget } from \"./context-window.ts\";\nimport { parseCopilotPromptLimitError } from \"./copilot-errors.ts\";\nimport { calculateContextTokens, estimateContextTokens, shouldCompact } from \"./compaction/index.ts\";\nimport { getLatestCompactionBoundaryEntry } from \"./session-manager.ts\";\nimport type { AgentSessionInternalSurface as AgentSession } from \"./agent-session-methods.ts\";\n\nexport async function _checkCompaction(this: AgentSession, assistantMessage: AssistantMessage, skipAbortedCheck = true): Promise<void> {\n\tconst settings = this.settingsManager.getCompactionSettings();\n\tif (!settings.enabled) return;\n\n\t// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false\n\tif (skipAbortedCheck && assistantMessage.stopReason === \"aborted\") return;\n\n\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t// Skip overflow check if the message came from a different model.\n\t// This handles the case where user switched from a smaller-context model (e.g. opus)\n\t// to a larger-context model (e.g. codex) - the overflow error from the old model\n\t// shouldn't trigger compaction for the new model.\n\tconst sameModel =\n\t\tthis.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n\n\t// Skip compaction checks if this assistant message is older than the latest\n\t// compaction boundary. This prevents a stale pre-compaction usage/error\n\t// from retriggering compaction on the first prompt after compaction.\n\tconst compactionBoundaryEntry = getLatestCompactionBoundaryEntry(this.sessionManager.getBranch());\n\tconst assistantIsFromBeforeCompactionBoundary =\n\t\tcompactionBoundaryEntry !== null &&\n\t\tassistantMessage.timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime();\n\tif (assistantIsFromBeforeCompactionBoundary) {\n\t\treturn;\n\t}\n\n\t// Case 1: Overflow - LLM returned context overflow error\n\t// When Copilot rejects a 1m client-budget prompt at a lower server cap (for example\n\t// because long-context/usage-based billing entitlement is missing), leave the friendly\n\t// error visible instead of auto-compacting down to a smaller server tier silently.\n\tif (sameModel && this._isCopilotServerCapBelowSelectedContextWindow(assistantMessage)) {\n\t\treturn;\n\t}\n\tif (sameModel && isContextOverflow(assistantMessage, contextWindow)) {\n\t\tconst willRetry = assistantMessage.stopReason !== \"stop\";\n\t\tif (!willRetry) {\n\t\t\tawait this._runAutoCompaction(\"overflow\", false);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._overflowRecoveryAttempted) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"overflow\",\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tunresolvedOverflow: true,\n\t\t\t\terrorMessage:\n\t\t\t\t\t\"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\",\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._overflowRecoveryAttempted = true;\n\t\t// Remove the error message from agent state (it IS saved to session for history,\n\t\t// but we don't want it in context for the retry)\n\t\tconst messages = this.agent.state.messages;\n\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t}\n\t\tawait this._runAutoCompaction(\"overflow\", willRetry);\n\t\treturn;\n\t}\n\n\t// Case 2: Threshold - context is getting large\n\t// For error messages (no usage data), estimate from last successful response.\n\t// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.\n\tlet contextTokens: number;\n\tif (assistantMessage.stopReason === \"error\") {\n\t\tconst messages = this.agent.state.messages;\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex === null) return; // No usage data at all\n\t\t// Verify the usage source is post-compaction. Kept pre-compaction messages\n\t\t// have stale usage reflecting the old (larger) context and would falsely\n\t\t// trigger compaction right after one just finished.\n\t\tconst usageMsg = messages[estimate.lastUsageIndex];\n\t\tif (\n\t\t\tcompactionBoundaryEntry &&\n\t\t\tusageMsg.role === \"assistant\" &&\n\t\t\t(usageMsg as AssistantMessage).timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime()\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tcontextTokens = estimate.tokens;\n\t} else {\n\t\tcontextTokens = calculateContextTokens(assistantMessage.usage);\n\t}\n\t// Compact against the effective input budget (the hard prompt cap for providers like Copilot\n\t// that advertise a larger total window) so we compact before overrunning the server-side limit\n\t// rather than relying on reactive overflow recovery near the cap.\n\tconst compactionBudget = this.model ? getEffectiveInputBudget(this.model) : contextWindow;\n\tif (shouldCompact(contextTokens, compactionBudget, settings)) {\n\t\tawait this._runAutoCompaction(\"threshold\", shouldRetryAfterThresholdCompaction(assistantMessage));\n\t}\n}\n\n\nexport function _isCopilotServerCapBelowSelectedContextWindow(this: AgentSession, assistantMessage: AssistantMessage): boolean {\n\tif (!this.model || this.model.provider !== \"github-copilot\" || !assistantMessage.errorMessage) return false;\n\tconst promptLimitError = parseCopilotPromptLimitError(assistantMessage.errorMessage);\n\t// Compare against the effective input budget (the model's real prompt cap), not the displayed\n\t// total window. A rejection at the prompt cap is a normal overflow we should compact-and-retry;\n\t// only a rejection *below* the cap (e.g. a missing long-context entitlement dropping the account\n\t// to a lower server tier) keeps the friendly error visible instead of silently compacting down.\n\treturn promptLimitError !== undefined && getEffectiveInputBudget(this.model) > promptLimitError.limitTokens;\n}\n\nexport function shouldRetryAfterThresholdCompaction(assistantMessage: AssistantMessage): boolean {\n\treturn assistantMessage.stopReason === \"length\" && assistantMessage.usage.output > 0;\n}\n\n/**\n * Internal: remove an incomplete assistant from retry context before auto-continuing after compaction.\n */\n\nexport function _dropTrailingAutoCompactionRetryAssistantIfPresent(this: AgentSession): void {\n\tconst messages = this.agent.state.messages;\n\tconst lastMsg = messages[messages.length - 1];\n\tif (lastMsg?.role !== \"assistant\") return;\n\tconst stopReason = (lastMsg as AssistantMessage).stopReason;\n\tif (stopReason === \"error\" || stopReason === \"length\") {\n\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t}\n}\n\n/**\n * Internal: schedule a live post-event continuation probe after compaction_end listeners can flush queues.\n */\n\nexport function _schedulePostAutoCompactionContinuationProbe(this: AgentSession,\n\treason: \"overflow\" | \"threshold\",\n\twillRetry: boolean,\n): void {\n\tif (reason === \"overflow\" && willRetry) {\n\t\tconst token = this._overflowPostCompactionContinuationToken + 1;\n\t\tthis._overflowPostCompactionContinuationToken = token;\n\t\tlet pending: Promise<void>;\n\t\tpending = new Promise<void>((resolve) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tvoid (async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (this._overflowPostCompactionContinuationToken !== token) return;\n\t\t\t\t\t\tif (this.isCompacting || this.isStreaming) return;\n\t\t\t\t\t\tawait this._resumeAfterAutoCompaction();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (this._pendingOverflowPostCompactionContinuation === pending) {\n\t\t\t\t\t\t\tthis._pendingOverflowPostCompactionContinuation = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}, 100);\n\t\t});\n\t\tthis._pendingOverflowPostCompactionContinuation = pending;\n\t\treturn;\n\t}\n\n\tsetTimeout(() => {\n\t\tif (this.isCompacting || this.isStreaming) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tvoid this._resumeAfterAutoCompaction();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.agent.hasQueuedMessages()) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid this._resumeAfterAutoCompaction();\n\t}, 100);\n}\n\nexport async function _awaitPendingOverflowPostCompactionContinuation(this: AgentSession): Promise<void> {\n\tconst pending = this._pendingOverflowPostCompactionContinuation;\n\tif (pending === undefined) return;\n\tawait pending;\n}\n\n/**\n * Internal: resume generation after successful auto-compaction only when active work remains.\n */\n\nexport async function _resumeAfterAutoCompaction(this: AgentSession): Promise<void> {\n\ttry {\n\t\tawait this._runAgentContinue();\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis._emit({\n\t\t\ttype: \"agent_continue_error\",\n\t\t\tsource: \"post_compaction\",\n\t\t\terrorMessage: `Post-compaction continuation failed: ${message}`,\n\t\t});\n\t}\n}\n\n\nfunction overflowUnresolved(reason: \"overflow\" | \"threshold\", aborted = false): boolean | undefined {\n\treturn reason === \"overflow\" && !aborted ? true : undefined;\n}\n\nexport async function _runAutoCompaction(this: AgentSession, reason: \"overflow\" | \"threshold\", willRetry: boolean): Promise<void> {\n\tthis._emit({ type: \"compaction_start\", reason });\n\tthis._autoCompactionAbortController = new AbortController();\n\n\ttry {\n\t\tif (!this.model) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tunresolvedOverflow: overflowUnresolved(reason),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Auth is resolved lazily: only called when the planner fallback is needed.\n\t\t// This allows extension-provided deletion requests to run before auth is checked,\n\t\t// enabling local extension compaction even when API credentials are unavailable.\n\t\t// Auto-mode resolver returns undefined (rather than throwing) when auth is missing;\n\t\t// overflow recovery then falls back to deterministic no-auth eviction, while\n\t\t// threshold compaction keeps the previous no-op behavior.\n\t\tconst model = this.model;\n\t\tconst result = await this._applyContextVerbatimCompaction({\n\t\t\tresolvePlannerAuth: async () => {\n\t\t\t\tconst authResult = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\t\t\tif (!authResult.ok || !authResult.apiKey) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn { apiKey: authResult.apiKey, headers: authResult.headers };\n\t\t\t},\n\t\t\tabortController: this._autoCompactionAbortController,\n\t\t\tbackupLabel: reason === \"overflow\" ? \"overflow-auto-compact\" : \"auto-compact\",\n\t\t\treason,\n\t\t});\n\t\tif (!result) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tunresolvedOverflow: overflowUnresolved(reason),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tthis._dropTrailingAutoCompactionRetryAssistantIfPresent();\n\t\t}\n\n\t\tthis._emit({ type: \"compaction_end\", reason, result, aborted: false, willRetry });\n\t\tthis._schedulePostAutoCompactionContinuationProbe(reason, willRetry);\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : \"compaction failed\";\n\t\tconst aborted = errorMessage === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\tthis._emit({\n\t\t\ttype: \"compaction_end\",\n\t\t\treason,\n\t\t\tresult: undefined,\n\t\t\taborted,\n\t\t\twillRetry: false,\n\t\t\tunresolvedOverflow: overflowUnresolved(reason, aborted),\n\t\t\terrorMessage: aborted\n\t\t\t\t? undefined\n\t\t\t\t: reason === \"overflow\"\n\t\t\t\t\t? `Context overflow recovery failed: ${errorMessage}`\n\t\t\t\t\t: `Auto-compaction failed: ${errorMessage}`,\n\t\t});\n\t} finally {\n\t\tthis._autoCompactionAbortController = undefined;\n\t}\n}\n\n/**\n * Toggle auto-compaction setting.\n */\n\nexport const agentSessionAutoCompactionMethods = {\n\t_awaitPendingOverflowPostCompactionContinuation,\n\t_checkCompaction,\n\t_isCopilotServerCapBelowSelectedContextWindow,\n\t_dropTrailingAutoCompactionRetryAssistantIfPresent,\n\t_schedulePostAutoCompactionContinuationProbe,\n\t_resumeAfterAutoCompaction,\n\t_runAutoCompaction,\n};\n"]}
|
|
@@ -45,6 +45,7 @@ export async function _checkCompaction(assistantMessage, skipAbortedCheck = true
|
|
|
45
45
|
result: undefined,
|
|
46
46
|
aborted: false,
|
|
47
47
|
willRetry: false,
|
|
48
|
+
unresolvedOverflow: true,
|
|
48
49
|
errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
|
|
49
50
|
});
|
|
50
51
|
return;
|
|
@@ -119,37 +120,72 @@ export function _dropTrailingAutoCompactionRetryAssistantIfPresent() {
|
|
|
119
120
|
/**
|
|
120
121
|
* Internal: schedule a live post-event continuation probe after compaction_end listeners can flush queues.
|
|
121
122
|
*/
|
|
122
|
-
export function _schedulePostAutoCompactionContinuationProbe(
|
|
123
|
+
export function _schedulePostAutoCompactionContinuationProbe(reason, willRetry) {
|
|
124
|
+
if (reason === "overflow" && willRetry) {
|
|
125
|
+
const token = this._overflowPostCompactionContinuationToken + 1;
|
|
126
|
+
this._overflowPostCompactionContinuationToken = token;
|
|
127
|
+
let pending;
|
|
128
|
+
pending = new Promise((resolve) => {
|
|
129
|
+
setTimeout(() => {
|
|
130
|
+
void (async () => {
|
|
131
|
+
try {
|
|
132
|
+
if (this._overflowPostCompactionContinuationToken !== token)
|
|
133
|
+
return;
|
|
134
|
+
if (this.isCompacting || this.isStreaming)
|
|
135
|
+
return;
|
|
136
|
+
await this._resumeAfterAutoCompaction();
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
if (this._pendingOverflowPostCompactionContinuation === pending) {
|
|
140
|
+
this._pendingOverflowPostCompactionContinuation = undefined;
|
|
141
|
+
}
|
|
142
|
+
resolve();
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
}, 100);
|
|
146
|
+
});
|
|
147
|
+
this._pendingOverflowPostCompactionContinuation = pending;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
123
150
|
setTimeout(() => {
|
|
124
151
|
if (this.isCompacting || this.isStreaming) {
|
|
125
152
|
return;
|
|
126
153
|
}
|
|
127
154
|
if (willRetry) {
|
|
128
|
-
this._resumeAfterAutoCompaction();
|
|
155
|
+
void this._resumeAfterAutoCompaction();
|
|
129
156
|
return;
|
|
130
157
|
}
|
|
131
158
|
if (!this.agent.hasQueuedMessages()) {
|
|
132
159
|
return;
|
|
133
160
|
}
|
|
134
|
-
this._resumeAfterAutoCompaction();
|
|
161
|
+
void this._resumeAfterAutoCompaction();
|
|
135
162
|
}, 100);
|
|
136
163
|
}
|
|
164
|
+
export async function _awaitPendingOverflowPostCompactionContinuation() {
|
|
165
|
+
const pending = this._pendingOverflowPostCompactionContinuation;
|
|
166
|
+
if (pending === undefined)
|
|
167
|
+
return;
|
|
168
|
+
await pending;
|
|
169
|
+
}
|
|
137
170
|
/**
|
|
138
171
|
* Internal: resume generation after successful auto-compaction only when active work remains.
|
|
139
172
|
*/
|
|
140
|
-
export function _resumeAfterAutoCompaction() {
|
|
141
|
-
|
|
173
|
+
export async function _resumeAfterAutoCompaction() {
|
|
174
|
+
try {
|
|
175
|
+
await this._runAgentContinue();
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
142
178
|
const message = error instanceof Error ? error.message : String(error);
|
|
143
179
|
this._emit({
|
|
144
180
|
type: "agent_continue_error",
|
|
145
181
|
source: "post_compaction",
|
|
146
182
|
errorMessage: `Post-compaction continuation failed: ${message}`,
|
|
147
183
|
});
|
|
148
|
-
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function overflowUnresolved(reason, aborted = false) {
|
|
187
|
+
return reason === "overflow" && !aborted ? true : undefined;
|
|
149
188
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Internal: Run auto-compaction with events.
|
|
152
|
-
*/
|
|
153
189
|
export async function _runAutoCompaction(reason, willRetry) {
|
|
154
190
|
this._emit({ type: "compaction_start", reason });
|
|
155
191
|
this._autoCompactionAbortController = new AbortController();
|
|
@@ -161,6 +197,7 @@ export async function _runAutoCompaction(reason, willRetry) {
|
|
|
161
197
|
result: undefined,
|
|
162
198
|
aborted: false,
|
|
163
199
|
willRetry: false,
|
|
200
|
+
unresolvedOverflow: overflowUnresolved(reason),
|
|
164
201
|
});
|
|
165
202
|
return;
|
|
166
203
|
}
|
|
@@ -190,6 +227,7 @@ export async function _runAutoCompaction(reason, willRetry) {
|
|
|
190
227
|
result: undefined,
|
|
191
228
|
aborted: false,
|
|
192
229
|
willRetry: false,
|
|
230
|
+
unresolvedOverflow: overflowUnresolved(reason),
|
|
193
231
|
});
|
|
194
232
|
return;
|
|
195
233
|
}
|
|
@@ -208,6 +246,7 @@ export async function _runAutoCompaction(reason, willRetry) {
|
|
|
208
246
|
result: undefined,
|
|
209
247
|
aborted,
|
|
210
248
|
willRetry: false,
|
|
249
|
+
unresolvedOverflow: overflowUnresolved(reason, aborted),
|
|
211
250
|
errorMessage: aborted
|
|
212
251
|
? undefined
|
|
213
252
|
: reason === "overflow"
|
|
@@ -223,6 +262,7 @@ export async function _runAutoCompaction(reason, willRetry) {
|
|
|
223
262
|
* Toggle auto-compaction setting.
|
|
224
263
|
*/
|
|
225
264
|
export const agentSessionAutoCompactionMethods = {
|
|
265
|
+
_awaitPendingOverflowPostCompactionContinuation,
|
|
226
266
|
_checkCompaction,
|
|
227
267
|
_isCopilotServerCapBelowSelectedContextWindow,
|
|
228
268
|
_dropTrailingAutoCompactionRetryAssistantIfPresent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session-auto-compaction.js","sourceRoot":"","sources":["../../src/core/agent-session-auto-compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai/compat\";\nimport { isContextOverflow } from \"@earendil-works/pi-ai/compat\";\nimport { getEffectiveInputBudget } from \"./context-window.ts\";\nimport { parseCopilotPromptLimitError } from \"./copilot-errors.ts\";\nimport { calculateContextTokens, estimateContextTokens, shouldCompact } from \"./compaction/index.ts\";\nimport { getLatestCompactionBoundaryEntry } from \"./session-manager.ts\";\nimport type { AgentSessionInternalSurface as AgentSession } from \"./agent-session-methods.ts\";\n\nexport async function _checkCompaction(this: AgentSession, assistantMessage: AssistantMessage, skipAbortedCheck = true): Promise<void> {\n\tconst settings = this.settingsManager.getCompactionSettings();\n\tif (!settings.enabled) return;\n\n\t// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false\n\tif (skipAbortedCheck && assistantMessage.stopReason === \"aborted\") return;\n\n\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t// Skip overflow check if the message came from a different model.\n\t// This handles the case where user switched from a smaller-context model (e.g. opus)\n\t// to a larger-context model (e.g. codex) - the overflow error from the old model\n\t// shouldn't trigger compaction for the new model.\n\tconst sameModel =\n\t\tthis.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n\n\t// Skip compaction checks if this assistant message is older than the latest\n\t// compaction boundary. This prevents a stale pre-compaction usage/error\n\t// from retriggering compaction on the first prompt after compaction.\n\tconst compactionBoundaryEntry = getLatestCompactionBoundaryEntry(this.sessionManager.getBranch());\n\tconst assistantIsFromBeforeCompactionBoundary =\n\t\tcompactionBoundaryEntry !== null &&\n\t\tassistantMessage.timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime();\n\tif (assistantIsFromBeforeCompactionBoundary) {\n\t\treturn;\n\t}\n\n\t// Case 1: Overflow - LLM returned context overflow error\n\t// When Copilot rejects a 1m client-budget prompt at a lower server cap (for example\n\t// because long-context/usage-based billing entitlement is missing), leave the friendly\n\t// error visible instead of auto-compacting down to a smaller server tier silently.\n\tif (sameModel && this._isCopilotServerCapBelowSelectedContextWindow(assistantMessage)) {\n\t\treturn;\n\t}\n\tif (sameModel && isContextOverflow(assistantMessage, contextWindow)) {\n\t\tconst willRetry = assistantMessage.stopReason !== \"stop\";\n\t\tif (!willRetry) {\n\t\t\tawait this._runAutoCompaction(\"overflow\", false);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._overflowRecoveryAttempted) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"overflow\",\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\terrorMessage:\n\t\t\t\t\t\"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\",\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._overflowRecoveryAttempted = true;\n\t\t// Remove the error message from agent state (it IS saved to session for history,\n\t\t// but we don't want it in context for the retry)\n\t\tconst messages = this.agent.state.messages;\n\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t}\n\t\tawait this._runAutoCompaction(\"overflow\", willRetry);\n\t\treturn;\n\t}\n\n\t// Case 2: Threshold - context is getting large\n\t// For error messages (no usage data), estimate from last successful response.\n\t// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.\n\tlet contextTokens: number;\n\tif (assistantMessage.stopReason === \"error\") {\n\t\tconst messages = this.agent.state.messages;\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex === null) return; // No usage data at all\n\t\t// Verify the usage source is post-compaction. Kept pre-compaction messages\n\t\t// have stale usage reflecting the old (larger) context and would falsely\n\t\t// trigger compaction right after one just finished.\n\t\tconst usageMsg = messages[estimate.lastUsageIndex];\n\t\tif (\n\t\t\tcompactionBoundaryEntry &&\n\t\t\tusageMsg.role === \"assistant\" &&\n\t\t\t(usageMsg as AssistantMessage).timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime()\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tcontextTokens = estimate.tokens;\n\t} else {\n\t\tcontextTokens = calculateContextTokens(assistantMessage.usage);\n\t}\n\t// Compact against the effective input budget (the hard prompt cap for providers like Copilot\n\t// that advertise a larger total window) so we compact before overrunning the server-side limit\n\t// rather than relying on reactive overflow recovery near the cap.\n\tconst compactionBudget = this.model ? getEffectiveInputBudget(this.model) : contextWindow;\n\tif (shouldCompact(contextTokens, compactionBudget, settings)) {\n\t\tawait this._runAutoCompaction(\"threshold\", shouldRetryAfterThresholdCompaction(assistantMessage));\n\t}\n}\n\n\nexport function _isCopilotServerCapBelowSelectedContextWindow(this: AgentSession, assistantMessage: AssistantMessage): boolean {\n\tif (!this.model || this.model.provider !== \"github-copilot\" || !assistantMessage.errorMessage) return false;\n\tconst promptLimitError = parseCopilotPromptLimitError(assistantMessage.errorMessage);\n\t// Compare against the effective input budget (the model's real prompt cap), not the displayed\n\t// total window. A rejection at the prompt cap is a normal overflow we should compact-and-retry;\n\t// only a rejection *below* the cap (e.g. a missing long-context entitlement dropping the account\n\t// to a lower server tier) keeps the friendly error visible instead of silently compacting down.\n\treturn promptLimitError !== undefined && getEffectiveInputBudget(this.model) > promptLimitError.limitTokens;\n}\n\nexport function shouldRetryAfterThresholdCompaction(assistantMessage: AssistantMessage): boolean {\n\treturn assistantMessage.stopReason === \"length\" && assistantMessage.usage.output > 0;\n}\n\n/**\n * Internal: remove an incomplete assistant from retry context before auto-continuing after compaction.\n */\n\nexport function _dropTrailingAutoCompactionRetryAssistantIfPresent(this: AgentSession): void {\n\tconst messages = this.agent.state.messages;\n\tconst lastMsg = messages[messages.length - 1];\n\tif (lastMsg?.role !== \"assistant\") return;\n\tconst stopReason = (lastMsg as AssistantMessage).stopReason;\n\tif (stopReason === \"error\" || stopReason === \"length\") {\n\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t}\n}\n\n/**\n * Internal: schedule a live post-event continuation probe after compaction_end listeners can flush queues.\n */\n\nexport function _schedulePostAutoCompactionContinuationProbe(this: AgentSession,\n\t_reason: \"overflow\" | \"threshold\",\n\twillRetry: boolean,\n): void {\n\tsetTimeout(() => {\n\t\tif (this.isCompacting || this.isStreaming) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tthis._resumeAfterAutoCompaction();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.agent.hasQueuedMessages()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._resumeAfterAutoCompaction();\n\t}, 100);\n}\n\n/**\n * Internal: resume generation after successful auto-compaction only when active work remains.\n */\n\nexport function _resumeAfterAutoCompaction(this: AgentSession): void {\n\tvoid this._runAgentContinue().catch((error) => {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis._emit({\n\t\t\ttype: \"agent_continue_error\",\n\t\t\tsource: \"post_compaction\",\n\t\t\terrorMessage: `Post-compaction continuation failed: ${message}`,\n\t\t});\n\t});\n}\n\n/**\n * Internal: Run auto-compaction with events.\n */\n\nexport async function _runAutoCompaction(this: AgentSession, reason: \"overflow\" | \"threshold\", willRetry: boolean): Promise<void> {\n\tthis._emit({ type: \"compaction_start\", reason });\n\tthis._autoCompactionAbortController = new AbortController();\n\n\ttry {\n\t\tif (!this.model) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Auth is resolved lazily: only called when the planner fallback is needed.\n\t\t// This allows extension-provided deletion requests to run before auth is checked,\n\t\t// enabling local extension compaction even when API credentials are unavailable.\n\t\t// Auto-mode resolver returns undefined (rather than throwing) when auth is missing;\n\t\t// overflow recovery then falls back to deterministic no-auth eviction, while\n\t\t// threshold compaction keeps the previous no-op behavior.\n\t\tconst model = this.model;\n\t\tconst result = await this._applyContextVerbatimCompaction({\n\t\t\tresolvePlannerAuth: async () => {\n\t\t\t\tconst authResult = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\t\t\tif (!authResult.ok || !authResult.apiKey) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn { apiKey: authResult.apiKey, headers: authResult.headers };\n\t\t\t},\n\t\t\tabortController: this._autoCompactionAbortController,\n\t\t\tbackupLabel: reason === \"overflow\" ? \"overflow-auto-compact\" : \"auto-compact\",\n\t\t\treason,\n\t\t});\n\t\tif (!result) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tthis._dropTrailingAutoCompactionRetryAssistantIfPresent();\n\t\t}\n\n\t\tthis._emit({ type: \"compaction_end\", reason, result, aborted: false, willRetry });\n\t\tthis._schedulePostAutoCompactionContinuationProbe(reason, willRetry);\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : \"compaction failed\";\n\t\tconst aborted = errorMessage === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\tthis._emit({\n\t\t\ttype: \"compaction_end\",\n\t\t\treason,\n\t\t\tresult: undefined,\n\t\t\taborted,\n\t\t\twillRetry: false,\n\t\t\terrorMessage: aborted\n\t\t\t\t? undefined\n\t\t\t\t: reason === \"overflow\"\n\t\t\t\t\t? `Context overflow recovery failed: ${errorMessage}`\n\t\t\t\t\t: `Auto-compaction failed: ${errorMessage}`,\n\t\t});\n\t} finally {\n\t\tthis._autoCompactionAbortController = undefined;\n\t}\n}\n\n/**\n * Toggle auto-compaction setting.\n */\n\nexport const agentSessionAutoCompactionMethods = {\n\t_checkCompaction,\n\t_isCopilotServerCapBelowSelectedContextWindow,\n\t_dropTrailingAutoCompactionRetryAssistantIfPresent,\n\t_schedulePostAutoCompactionContinuationProbe,\n\t_resumeAfterAutoCompaction,\n\t_runAutoCompaction,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"agent-session-auto-compaction.js","sourceRoot":"","sources":["../../src/core/agent-session-auto-compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai/compat\";\nimport { isContextOverflow } from \"@earendil-works/pi-ai/compat\";\nimport { getEffectiveInputBudget } from \"./context-window.ts\";\nimport { parseCopilotPromptLimitError } from \"./copilot-errors.ts\";\nimport { calculateContextTokens, estimateContextTokens, shouldCompact } from \"./compaction/index.ts\";\nimport { getLatestCompactionBoundaryEntry } from \"./session-manager.ts\";\nimport type { AgentSessionInternalSurface as AgentSession } from \"./agent-session-methods.ts\";\n\nexport async function _checkCompaction(this: AgentSession, assistantMessage: AssistantMessage, skipAbortedCheck = true): Promise<void> {\n\tconst settings = this.settingsManager.getCompactionSettings();\n\tif (!settings.enabled) return;\n\n\t// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false\n\tif (skipAbortedCheck && assistantMessage.stopReason === \"aborted\") return;\n\n\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t// Skip overflow check if the message came from a different model.\n\t// This handles the case where user switched from a smaller-context model (e.g. opus)\n\t// to a larger-context model (e.g. codex) - the overflow error from the old model\n\t// shouldn't trigger compaction for the new model.\n\tconst sameModel =\n\t\tthis.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n\n\t// Skip compaction checks if this assistant message is older than the latest\n\t// compaction boundary. This prevents a stale pre-compaction usage/error\n\t// from retriggering compaction on the first prompt after compaction.\n\tconst compactionBoundaryEntry = getLatestCompactionBoundaryEntry(this.sessionManager.getBranch());\n\tconst assistantIsFromBeforeCompactionBoundary =\n\t\tcompactionBoundaryEntry !== null &&\n\t\tassistantMessage.timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime();\n\tif (assistantIsFromBeforeCompactionBoundary) {\n\t\treturn;\n\t}\n\n\t// Case 1: Overflow - LLM returned context overflow error\n\t// When Copilot rejects a 1m client-budget prompt at a lower server cap (for example\n\t// because long-context/usage-based billing entitlement is missing), leave the friendly\n\t// error visible instead of auto-compacting down to a smaller server tier silently.\n\tif (sameModel && this._isCopilotServerCapBelowSelectedContextWindow(assistantMessage)) {\n\t\treturn;\n\t}\n\tif (sameModel && isContextOverflow(assistantMessage, contextWindow)) {\n\t\tconst willRetry = assistantMessage.stopReason !== \"stop\";\n\t\tif (!willRetry) {\n\t\t\tawait this._runAutoCompaction(\"overflow\", false);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._overflowRecoveryAttempted) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"overflow\",\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tunresolvedOverflow: true,\n\t\t\t\terrorMessage:\n\t\t\t\t\t\"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\",\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._overflowRecoveryAttempted = true;\n\t\t// Remove the error message from agent state (it IS saved to session for history,\n\t\t// but we don't want it in context for the retry)\n\t\tconst messages = this.agent.state.messages;\n\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t}\n\t\tawait this._runAutoCompaction(\"overflow\", willRetry);\n\t\treturn;\n\t}\n\n\t// Case 2: Threshold - context is getting large\n\t// For error messages (no usage data), estimate from last successful response.\n\t// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.\n\tlet contextTokens: number;\n\tif (assistantMessage.stopReason === \"error\") {\n\t\tconst messages = this.agent.state.messages;\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex === null) return; // No usage data at all\n\t\t// Verify the usage source is post-compaction. Kept pre-compaction messages\n\t\t// have stale usage reflecting the old (larger) context and would falsely\n\t\t// trigger compaction right after one just finished.\n\t\tconst usageMsg = messages[estimate.lastUsageIndex];\n\t\tif (\n\t\t\tcompactionBoundaryEntry &&\n\t\t\tusageMsg.role === \"assistant\" &&\n\t\t\t(usageMsg as AssistantMessage).timestamp <= new Date(compactionBoundaryEntry.timestamp).getTime()\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tcontextTokens = estimate.tokens;\n\t} else {\n\t\tcontextTokens = calculateContextTokens(assistantMessage.usage);\n\t}\n\t// Compact against the effective input budget (the hard prompt cap for providers like Copilot\n\t// that advertise a larger total window) so we compact before overrunning the server-side limit\n\t// rather than relying on reactive overflow recovery near the cap.\n\tconst compactionBudget = this.model ? getEffectiveInputBudget(this.model) : contextWindow;\n\tif (shouldCompact(contextTokens, compactionBudget, settings)) {\n\t\tawait this._runAutoCompaction(\"threshold\", shouldRetryAfterThresholdCompaction(assistantMessage));\n\t}\n}\n\n\nexport function _isCopilotServerCapBelowSelectedContextWindow(this: AgentSession, assistantMessage: AssistantMessage): boolean {\n\tif (!this.model || this.model.provider !== \"github-copilot\" || !assistantMessage.errorMessage) return false;\n\tconst promptLimitError = parseCopilotPromptLimitError(assistantMessage.errorMessage);\n\t// Compare against the effective input budget (the model's real prompt cap), not the displayed\n\t// total window. A rejection at the prompt cap is a normal overflow we should compact-and-retry;\n\t// only a rejection *below* the cap (e.g. a missing long-context entitlement dropping the account\n\t// to a lower server tier) keeps the friendly error visible instead of silently compacting down.\n\treturn promptLimitError !== undefined && getEffectiveInputBudget(this.model) > promptLimitError.limitTokens;\n}\n\nexport function shouldRetryAfterThresholdCompaction(assistantMessage: AssistantMessage): boolean {\n\treturn assistantMessage.stopReason === \"length\" && assistantMessage.usage.output > 0;\n}\n\n/**\n * Internal: remove an incomplete assistant from retry context before auto-continuing after compaction.\n */\n\nexport function _dropTrailingAutoCompactionRetryAssistantIfPresent(this: AgentSession): void {\n\tconst messages = this.agent.state.messages;\n\tconst lastMsg = messages[messages.length - 1];\n\tif (lastMsg?.role !== \"assistant\") return;\n\tconst stopReason = (lastMsg as AssistantMessage).stopReason;\n\tif (stopReason === \"error\" || stopReason === \"length\") {\n\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t}\n}\n\n/**\n * Internal: schedule a live post-event continuation probe after compaction_end listeners can flush queues.\n */\n\nexport function _schedulePostAutoCompactionContinuationProbe(this: AgentSession,\n\treason: \"overflow\" | \"threshold\",\n\twillRetry: boolean,\n): void {\n\tif (reason === \"overflow\" && willRetry) {\n\t\tconst token = this._overflowPostCompactionContinuationToken + 1;\n\t\tthis._overflowPostCompactionContinuationToken = token;\n\t\tlet pending: Promise<void>;\n\t\tpending = new Promise<void>((resolve) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tvoid (async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (this._overflowPostCompactionContinuationToken !== token) return;\n\t\t\t\t\t\tif (this.isCompacting || this.isStreaming) return;\n\t\t\t\t\t\tawait this._resumeAfterAutoCompaction();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (this._pendingOverflowPostCompactionContinuation === pending) {\n\t\t\t\t\t\t\tthis._pendingOverflowPostCompactionContinuation = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}, 100);\n\t\t});\n\t\tthis._pendingOverflowPostCompactionContinuation = pending;\n\t\treturn;\n\t}\n\n\tsetTimeout(() => {\n\t\tif (this.isCompacting || this.isStreaming) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tvoid this._resumeAfterAutoCompaction();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.agent.hasQueuedMessages()) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid this._resumeAfterAutoCompaction();\n\t}, 100);\n}\n\nexport async function _awaitPendingOverflowPostCompactionContinuation(this: AgentSession): Promise<void> {\n\tconst pending = this._pendingOverflowPostCompactionContinuation;\n\tif (pending === undefined) return;\n\tawait pending;\n}\n\n/**\n * Internal: resume generation after successful auto-compaction only when active work remains.\n */\n\nexport async function _resumeAfterAutoCompaction(this: AgentSession): Promise<void> {\n\ttry {\n\t\tawait this._runAgentContinue();\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis._emit({\n\t\t\ttype: \"agent_continue_error\",\n\t\t\tsource: \"post_compaction\",\n\t\t\terrorMessage: `Post-compaction continuation failed: ${message}`,\n\t\t});\n\t}\n}\n\n\nfunction overflowUnresolved(reason: \"overflow\" | \"threshold\", aborted = false): boolean | undefined {\n\treturn reason === \"overflow\" && !aborted ? true : undefined;\n}\n\nexport async function _runAutoCompaction(this: AgentSession, reason: \"overflow\" | \"threshold\", willRetry: boolean): Promise<void> {\n\tthis._emit({ type: \"compaction_start\", reason });\n\tthis._autoCompactionAbortController = new AbortController();\n\n\ttry {\n\t\tif (!this.model) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tunresolvedOverflow: overflowUnresolved(reason),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Auth is resolved lazily: only called when the planner fallback is needed.\n\t\t// This allows extension-provided deletion requests to run before auth is checked,\n\t\t// enabling local extension compaction even when API credentials are unavailable.\n\t\t// Auto-mode resolver returns undefined (rather than throwing) when auth is missing;\n\t\t// overflow recovery then falls back to deterministic no-auth eviction, while\n\t\t// threshold compaction keeps the previous no-op behavior.\n\t\tconst model = this.model;\n\t\tconst result = await this._applyContextVerbatimCompaction({\n\t\t\tresolvePlannerAuth: async () => {\n\t\t\t\tconst authResult = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\t\t\tif (!authResult.ok || !authResult.apiKey) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn { apiKey: authResult.apiKey, headers: authResult.headers };\n\t\t\t},\n\t\t\tabortController: this._autoCompactionAbortController,\n\t\t\tbackupLabel: reason === \"overflow\" ? \"overflow-auto-compact\" : \"auto-compact\",\n\t\t\treason,\n\t\t});\n\t\tif (!result) {\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult: undefined,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tunresolvedOverflow: overflowUnresolved(reason),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (willRetry) {\n\t\t\tthis._dropTrailingAutoCompactionRetryAssistantIfPresent();\n\t\t}\n\n\t\tthis._emit({ type: \"compaction_end\", reason, result, aborted: false, willRetry });\n\t\tthis._schedulePostAutoCompactionContinuationProbe(reason, willRetry);\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : \"compaction failed\";\n\t\tconst aborted = errorMessage === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\tthis._emit({\n\t\t\ttype: \"compaction_end\",\n\t\t\treason,\n\t\t\tresult: undefined,\n\t\t\taborted,\n\t\t\twillRetry: false,\n\t\t\tunresolvedOverflow: overflowUnresolved(reason, aborted),\n\t\t\terrorMessage: aborted\n\t\t\t\t? undefined\n\t\t\t\t: reason === \"overflow\"\n\t\t\t\t\t? `Context overflow recovery failed: ${errorMessage}`\n\t\t\t\t\t: `Auto-compaction failed: ${errorMessage}`,\n\t\t});\n\t} finally {\n\t\tthis._autoCompactionAbortController = undefined;\n\t}\n}\n\n/**\n * Toggle auto-compaction setting.\n */\n\nexport const agentSessionAutoCompactionMethods = {\n\t_awaitPendingOverflowPostCompactionContinuation,\n\t_checkCompaction,\n\t_isCopilotServerCapBelowSelectedContextWindow,\n\t_dropTrailingAutoCompactionRetryAssistantIfPresent,\n\t_schedulePostAutoCompactionContinuationProbe,\n\t_resumeAfterAutoCompaction,\n\t_runAutoCompaction,\n};\n"]}
|