@caupulican/pi-adaptative 0.81.2 → 0.81.3
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 +15 -0
- package/dist/core/agent-session.d.ts +1 -23
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +117 -131
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +2 -0
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +3 -0
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/billing-failover-controller.d.ts +31 -0
- package/dist/core/billing-failover-controller.d.ts.map +1 -0
- package/dist/core/billing-failover-controller.js +72 -0
- package/dist/core/billing-failover-controller.js.map +1 -0
- package/dist/core/billing-failover.d.ts +25 -0
- package/dist/core/billing-failover.d.ts.map +1 -0
- package/dist/core/billing-failover.js +21 -0
- package/dist/core/billing-failover.js.map +1 -0
- package/dist/core/context-pipeline.d.ts +1 -0
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +51 -14
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/model-router/config-diagnostics.d.ts +1 -1
- package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
- package/dist/core/model-router/config-diagnostics.js +29 -1
- package/dist/core/model-router/config-diagnostics.js.map +1 -1
- package/dist/core/model-router/fitness-gate.d.ts +23 -0
- package/dist/core/model-router/fitness-gate.d.ts.map +1 -0
- package/dist/core/model-router/fitness-gate.js +33 -0
- package/dist/core/model-router/fitness-gate.js.map +1 -0
- package/dist/core/model-router/status.d.ts +25 -1
- package/dist/core/model-router/status.d.ts.map +1 -1
- package/dist/core/model-router/status.js +27 -4
- package/dist/core/model-router/status.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +10 -1
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +108 -27
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +16 -0
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +88 -1
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/scout-controller.d.ts +44 -0
- package/dist/core/scout-controller.d.ts.map +1 -0
- package/dist/core/scout-controller.js +165 -0
- package/dist/core/scout-controller.js.map +1 -0
- package/dist/core/settings-manager.d.ts +16 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +35 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/context-scout.d.ts +19 -0
- package/dist/core/tools/context-scout.d.ts.map +1 -0
- package/dist/core/tools/context-scout.js +47 -0
- package/dist/core/tools/context-scout.js.map +1 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +77 -7
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/local-model-commands.d.ts +5 -2
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
- package/dist/modes/interactive/local-model-commands.js +115 -1
- package/dist/modes/interactive/local-model-commands.js.map +1 -1
- package/docs/index.md +1 -0
- package/docs/providers.md +2 -0
- package/docs/scout.md +71 -0
- package/docs/settings.md +14 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import { readFileSync } from "node:fs";
|
|
16
16
|
import { basename, dirname, join } from "node:path";
|
|
17
17
|
import { classifyFailure, compactToolResultDetailsForRetention, computeRetryDelayMs, createCustomMessage, DEFAULT_RETRY_POLICY, RetryController, sleepAbortable, withStreamIdleWatchdog, } from "@caupulican/pi-agent-core";
|
|
18
|
-
import { calculateContextTokens, compact, estimateContextTokens, getLatestCompactionEntry, prepareCompaction, shouldCompact, } from "@caupulican/pi-agent-core/node";
|
|
18
|
+
import { calculateContextTokens, compact, createDeterministicCompaction, estimateContextTokens, getLatestCompactionEntry, prepareCompaction, runCompactionLoop, shouldCompact, } from "@caupulican/pi-agent-core/node";
|
|
19
19
|
import { cleanupSessionResources, isContextOverflow, streamSimple } from "@caupulican/pi-ai";
|
|
20
20
|
import { getAgentDir } from "../config.js";
|
|
21
21
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
@@ -24,6 +24,7 @@ import { buildForegroundEnvelope, formatForegroundEnvelopeObservation } from "./
|
|
|
24
24
|
import { AutonomyTelemetry } from "./autonomy-telemetry.js";
|
|
25
25
|
import { BackgroundLaneController } from "./background-lane-controller.js";
|
|
26
26
|
import { BashExecutionController } from "./bash-execution-controller.js";
|
|
27
|
+
import { BillingFailoverController, ExhaustedProviderRegistry } from "./billing-failover-controller.js";
|
|
27
28
|
import { CompactionSupport } from "./compaction-support.js";
|
|
28
29
|
import { buildContextCompositionReport, formatContextCompositionDashboard, } from "./context/context-composition.js";
|
|
29
30
|
import { ContextPipeline } from "./context-pipeline.js";
|
|
@@ -116,52 +117,34 @@ export class AgentSession {
|
|
|
116
117
|
_unsubscribeAgent;
|
|
117
118
|
_eventListeners = [];
|
|
118
119
|
_extensionsChangedListeners = [];
|
|
119
|
-
/** Tracks pending steering messages for UI display. Removed when delivered. */
|
|
120
120
|
_steeringMessages = [];
|
|
121
|
-
/** Tracks pending follow-up messages for UI display. Removed when delivered. */
|
|
122
121
|
_followUpMessages = [];
|
|
123
|
-
/** Tracks extension slash commands queued while the agent is streaming. */
|
|
124
122
|
_queuedExtensionCommands = [];
|
|
125
|
-
/** Messages queued to be included with the next user prompt as context ("asides"). */
|
|
126
123
|
_pendingNextTurnMessages = [];
|
|
127
|
-
/** Serializes prompt() submissions made while streaming so queued steering/follow-ups keep user-typed FIFO order. */
|
|
128
124
|
_streamingPromptSubmissionTail = Promise.resolve();
|
|
129
125
|
/**
|
|
130
126
|
* The last tool set requested via setActiveToolsByName BEFORE model-capability filtering, so
|
|
131
127
|
* switching from a small-window model back to a large one restores the full requested set.
|
|
132
128
|
*/
|
|
133
129
|
_requestedActiveToolNames;
|
|
134
|
-
// Compaction/context hygiene state
|
|
135
130
|
_compactionAbortController = undefined;
|
|
136
131
|
_autoCompactionAbortController = undefined;
|
|
137
132
|
_overflowRecoveryAttempted = false;
|
|
138
133
|
_unboundToolGrantWarnings = [];
|
|
139
|
-
// Branch summarization state
|
|
140
134
|
_branchSummaryAbortController = undefined;
|
|
141
|
-
// Auto-retry driver — owns the attempt counter and abortable backoff (reliability kernel).
|
|
142
135
|
_retryController;
|
|
143
|
-
// Bash execution state
|
|
144
|
-
/** User-facing model + thinking-level selection (see model-selection-controller.ts). */
|
|
145
136
|
_modelSelection;
|
|
146
|
-
/** Standalone bash-command execution (see bash-execution-controller.ts); owns the bash abort
|
|
147
|
-
* controller and the streaming-deferred pending-message queue. */
|
|
148
137
|
_bash;
|
|
149
|
-
/** Resource-profile tool/extension gating + reload-time profile model re-apply (see profile-filter-controller.ts). */
|
|
150
138
|
_profileFilter;
|
|
151
|
-
/** Agent tool-call gate: escalation, autonomy gating, extension hooks, untrusted boundary (see tool-gate-controller.ts). */
|
|
152
139
|
_toolGate;
|
|
153
|
-
// Extension system
|
|
154
140
|
_extensionRunner;
|
|
155
141
|
_turnIndex = 0;
|
|
156
|
-
/** G7: per-turn foreground CapabilityEnvelope auto-built for visibility (observe-only; not enforced). */
|
|
157
142
|
_currentForegroundEnvelope;
|
|
158
143
|
_resourceLoader;
|
|
159
144
|
_customTools;
|
|
160
145
|
_cwd;
|
|
161
146
|
_agentDir;
|
|
162
147
|
_collectWorkspaceSources;
|
|
163
|
-
/** Owns the cached per-server OllamaRuntime instances and the local-model router readiness gate
|
|
164
|
-
* (see local-runtime-controller.ts). */
|
|
165
148
|
_localRuntimeController;
|
|
166
149
|
/** Assembles the session's base system prompt from live session state (see
|
|
167
150
|
* system-prompt-builder.ts); owns the paired _baseSystemPromptOptions. */
|
|
@@ -177,7 +160,6 @@ export class AgentSession {
|
|
|
177
160
|
* latest retrieval/prompt-inclusion reports, the reload-safe MemoryManager, the recall
|
|
178
161
|
* effectiveness tracker, and the extension-contributed pending providers. */
|
|
179
162
|
_memory;
|
|
180
|
-
/** Summarizer model/auth/settings resolution (see compaction-support.ts). */
|
|
181
163
|
_compactionSupport;
|
|
182
164
|
/** Per-turn context-shaping subsystem (see context-pipeline.ts); owns the latest
|
|
183
165
|
* audit/policy/correlation/enforcement/gc reports, the brain-curation sidecar + its skip reasons,
|
|
@@ -190,28 +172,21 @@ export class AgentSession {
|
|
|
190
172
|
_toolProfileFilter;
|
|
191
173
|
_isExplicitModel;
|
|
192
174
|
_isExplicitThinking;
|
|
193
|
-
/** R8: registry for deployment-supplied gateway channels + schedulers (lifecycle driven by the host runner). */
|
|
194
175
|
_gatewayRegistry = new GatewayRegistry();
|
|
195
|
-
/** Cache for getSpawnedUsage(), keyed by session entry count (Bug #22 — avoid O(N) per render frame). */
|
|
196
176
|
/** Usage/cost/stats accounting, /context estimate, and session export (see session-analytics.ts);
|
|
197
177
|
* owns the spawned-usage and daily-usage memo caches. */
|
|
198
178
|
_analytics;
|
|
199
|
-
/** In-file session-tree branch switching + fork-selector reads (see session-tree-navigator.ts). */
|
|
200
179
|
_treeNavigator;
|
|
201
|
-
/** Latest proactive cost-guard decision (#34), for the host UI to surface. Undefined when disabled. */
|
|
202
180
|
_lastCostGuardDecision;
|
|
203
|
-
/** One-shot latch so the cost guard downgrades reasoning once per over-threshold episode, not every call. */
|
|
204
181
|
_costGuardDowngraded = false;
|
|
205
182
|
/** Per-turn model-router subsystem (see model-router-controller.ts); owns the transient route/intent,
|
|
206
183
|
* the cheap-turn session buffer, the escalation/retry flags, and the sticky last-decision/skip-reason
|
|
207
184
|
* used by the status report. Its parallel routed drive path delegates every turn back to
|
|
208
185
|
* {@link _runAgentPrompt} so the drive loop stays host-side. */
|
|
209
186
|
_modelRouter;
|
|
210
|
-
|
|
187
|
+
_billingFailover;
|
|
211
188
|
_skillCuratorInstance;
|
|
212
|
-
/** Set on dispose so in-flight background reflection bails instead of writing to a dead session (Bug #21). */
|
|
213
189
|
_disposed = false;
|
|
214
|
-
/** Aborts in-flight background reflection completions on dispose (Bug #21). */
|
|
215
190
|
_reflectionAbort = new AbortController();
|
|
216
191
|
/** Native reflection engine + learning-apply/rollback path (see reflection-controller.ts); owns no
|
|
217
192
|
* session state, applies durable writes through the bundled memory tool and the session log. */
|
|
@@ -229,7 +204,6 @@ export class AgentSession {
|
|
|
229
204
|
_extensionShutdownHandler;
|
|
230
205
|
_extensionErrorListener;
|
|
231
206
|
_extensionErrorUnsubscriber;
|
|
232
|
-
// Model registry for API key resolution
|
|
233
207
|
_modelRegistry;
|
|
234
208
|
/** Tool-registry assembly + the self-modification-safe extension reload (see runtime-builder.ts);
|
|
235
209
|
* owns the base/wrapped tool definitions, the live tool registry, and the per-tool prompt
|
|
@@ -314,6 +288,7 @@ export class AgentSession {
|
|
|
314
288
|
getLearningDecisionSnapshots: () => this.getLearningDecisionSnapshots(),
|
|
315
289
|
getLearningAuditRecords: () => this.getLearningAuditRecords(),
|
|
316
290
|
});
|
|
291
|
+
this._modelRegistry = config.modelRegistry;
|
|
317
292
|
this._backgroundLanes = new BackgroundLaneController({
|
|
318
293
|
isDisposed: () => this._disposed,
|
|
319
294
|
isChildSession: () => this._isChildSession,
|
|
@@ -323,6 +298,7 @@ export class AgentSession {
|
|
|
323
298
|
getSessionManager: () => this.sessionManager,
|
|
324
299
|
getSettingsManager: () => this.settingsManager,
|
|
325
300
|
getModelRegistry: () => this._modelRegistry,
|
|
301
|
+
isModelExhausted: (model) => this._billingFailover.isExhausted(`${model.provider}/${model.id}`),
|
|
326
302
|
getModel: () => this.model ?? undefined,
|
|
327
303
|
getCapabilityEnvelope: () => this.capabilityEnvelope,
|
|
328
304
|
getModelCapabilityProfile: () => this.getModelCapabilityProfile(),
|
|
@@ -367,12 +343,21 @@ export class AgentSession {
|
|
|
367
343
|
addSpawnedUsage: (usage, opts) => this.addSpawnedUsage(usage, opts),
|
|
368
344
|
runIsolatedCompletion: (opts) => this.runIsolatedCompletion(opts),
|
|
369
345
|
});
|
|
346
|
+
this._billingFailover = new BillingFailoverController({
|
|
347
|
+
agent: this.agent,
|
|
348
|
+
modelRegistry: this._modelRegistry,
|
|
349
|
+
exhausted: new ExhaustedProviderRegistry(),
|
|
350
|
+
subscriptionHop: this.settingsManager.getFailoverSettings().subscriptionHop,
|
|
351
|
+
emit: (event) => this._emit(event),
|
|
352
|
+
});
|
|
370
353
|
this._modelRouter = new ModelRouterController({
|
|
371
354
|
getAgent: () => this.agent,
|
|
372
355
|
getModel: () => this.model ?? undefined,
|
|
373
356
|
getSettingsManager: () => this.settingsManager,
|
|
374
357
|
getSessionManager: () => this.sessionManager,
|
|
375
358
|
getModelRegistry: () => this._modelRegistry,
|
|
359
|
+
isModelExhausted: (model) => this._billingFailover.isExhausted(`${model.provider}/${model.id}`),
|
|
360
|
+
getFailoverStatus: () => this._billingFailover.getStatus(),
|
|
376
361
|
getAgentDir: () => this._agentDir,
|
|
377
362
|
getReflectionSignal: () => this._reflectionAbort.signal,
|
|
378
363
|
getBaseSystemPrompt: () => this._baseSystemPrompt,
|
|
@@ -407,7 +392,6 @@ export class AgentSession {
|
|
|
407
392
|
getGoalRuntimeSnapshot: (settings) => this.getGoalRuntimeSnapshot(settings),
|
|
408
393
|
prompt: (text, options) => this.prompt(text, options),
|
|
409
394
|
});
|
|
410
|
-
this._modelRegistry = config.modelRegistry;
|
|
411
395
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
412
396
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
413
397
|
this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
|
|
@@ -423,9 +407,11 @@ export class AgentSession {
|
|
|
423
407
|
this._runtimeBuilder = new RuntimeBuilder({
|
|
424
408
|
getAgent: () => this.agent,
|
|
425
409
|
getCwd: () => this._cwd,
|
|
410
|
+
getAgentDir: () => this._agentDir,
|
|
426
411
|
getSessionManager: () => this.sessionManager,
|
|
427
412
|
getSettingsManager: () => this.settingsManager,
|
|
428
413
|
getModelRegistry: () => this._modelRegistry,
|
|
414
|
+
isModelExhausted: (model) => this._billingFailover.isExhausted(`${model.provider}/${model.id}`),
|
|
429
415
|
getResourceLoader: () => this._resourceLoader,
|
|
430
416
|
getExtensionRunner: () => this._extensionRunner,
|
|
431
417
|
setExtensionRunner: (runner) => {
|
|
@@ -1530,7 +1516,6 @@ export class AgentSession {
|
|
|
1530
1516
|
async _ensureRouteModelReady(resolved) {
|
|
1531
1517
|
return this._localRuntimeController.ensureRouteModelReady(resolved);
|
|
1532
1518
|
}
|
|
1533
|
-
/** Model-router status + config diagnostics report. Delegates to {@link ModelRouterController}. */
|
|
1534
1519
|
getModelRouterStatus(formatLabel) {
|
|
1535
1520
|
return this._modelRouter.getStatus(formatLabel);
|
|
1536
1521
|
}
|
|
@@ -1543,6 +1528,8 @@ export class AgentSession {
|
|
|
1543
1528
|
if (this._isRetryableError(msg) && (await this._prepareRetry(msg))) {
|
|
1544
1529
|
return true;
|
|
1545
1530
|
}
|
|
1531
|
+
if (await this._billingFailover.handleAssistantError(msg))
|
|
1532
|
+
return false;
|
|
1546
1533
|
if (msg.stopReason === "error" && this._retryController.attempt > 0) {
|
|
1547
1534
|
this._emit({
|
|
1548
1535
|
type: "auto_retry_end",
|
|
@@ -2190,7 +2177,7 @@ export class AgentSession {
|
|
|
2190
2177
|
else {
|
|
2191
2178
|
// Generate compaction result
|
|
2192
2179
|
const compactionSignal = this._compactionAbortController.signal;
|
|
2193
|
-
const result = await this._compactWithRetry(() => compact(preparation, compactionModel, apiKey, headers, customInstructions, compactionSignal, compactionThinkingLevel, this.agent.streamFn, this._buildCompactionPreDigest()), compactionSignal);
|
|
2180
|
+
const result = await this._compactWithRetry(() => compact(preparation, compactionModel, apiKey, headers, customInstructions, compactionSignal, compactionThinkingLevel, this.agent.streamFn, this._buildCompactionPreDigest()), compactionSignal, compactionModel.provider);
|
|
2194
2181
|
summary = result.summary;
|
|
2195
2182
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
2196
2183
|
tokensBefore = result.tokensBefore;
|
|
@@ -2388,10 +2375,16 @@ export class AgentSession {
|
|
|
2388
2375
|
*/
|
|
2389
2376
|
async _runAutoCompaction(reason, willRetry) {
|
|
2390
2377
|
const settings = this._getAdaptedCompactionSettings();
|
|
2378
|
+
const model = this.model;
|
|
2391
2379
|
this._emit({ type: "compaction_start", reason });
|
|
2380
|
+
const hadQueuedMessages = this.agent.hasQueuedMessages();
|
|
2392
2381
|
this._autoCompactionAbortController = new AbortController();
|
|
2382
|
+
const signal = this._autoCompactionAbortController.signal;
|
|
2383
|
+
let fromExtension = false;
|
|
2384
|
+
let lastCompaction;
|
|
2385
|
+
let extensionCancelled = false;
|
|
2393
2386
|
try {
|
|
2394
|
-
if (!
|
|
2387
|
+
if (!model) {
|
|
2395
2388
|
this._emit({
|
|
2396
2389
|
type: "compaction_end",
|
|
2397
2390
|
reason,
|
|
@@ -2402,113 +2395,107 @@ export class AgentSession {
|
|
|
2402
2395
|
});
|
|
2403
2396
|
return false;
|
|
2404
2397
|
}
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
this.
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2398
|
+
const contextWindow = model.contextWindow;
|
|
2399
|
+
const triggerThreshold = Math.max(0, contextWindow - settings.reserveTokens);
|
|
2400
|
+
const margin = Math.max(0, Math.floor(0.01 * contextWindow));
|
|
2401
|
+
let measureReads = 0;
|
|
2402
|
+
const outcome = await runCompactionLoop({
|
|
2403
|
+
getBranch: () => this.sessionManager.getBranch(),
|
|
2404
|
+
measureLiveTokens: () => {
|
|
2405
|
+
const measured = this._pipeline.estimateCurrentContextTokens(this.agent.state.messages);
|
|
2406
|
+
return measureReads++ === 0 ? Math.max(measured, triggerThreshold + 1) : measured;
|
|
2407
|
+
},
|
|
2408
|
+
getTriggerThreshold: () => triggerThreshold,
|
|
2409
|
+
getMargin: () => margin,
|
|
2410
|
+
getBaseKeepRecentTokens: () => settings.keepRecentTokens,
|
|
2411
|
+
resolveModelAndAuth: async (modelTier) => this._resolveCompactionModelAndAuth(modelTier === "session" ? model : this._resolveCompactionModel(model), model),
|
|
2412
|
+
summarizeAndVerify: async (params, compactModel, apiKey, headers, branchEntries) => {
|
|
2413
|
+
fromExtension = false;
|
|
2414
|
+
const adaptedSettings = { ...settings, keepRecentTokens: params.keepRecentTokens };
|
|
2415
|
+
const preparation = prepareCompaction(branchEntries, adaptedSettings);
|
|
2416
|
+
if (!preparation) {
|
|
2417
|
+
throw new Error("already compacted");
|
|
2418
|
+
}
|
|
2419
|
+
const compactionThinkingLevel = this._resolveCompactionThinkingLevel(compactModel, model);
|
|
2420
|
+
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
2421
|
+
const extensionResult = (await this._extensionRunner.emit({
|
|
2422
|
+
type: "session_before_compact",
|
|
2423
|
+
preparation,
|
|
2424
|
+
branchEntries,
|
|
2425
|
+
customInstructions: undefined,
|
|
2426
|
+
signal,
|
|
2427
|
+
}));
|
|
2428
|
+
if (extensionResult?.cancel) {
|
|
2429
|
+
extensionCancelled = true;
|
|
2430
|
+
throw new Error("auto-compaction-cancelled");
|
|
2431
|
+
}
|
|
2432
|
+
if (extensionResult?.compaction) {
|
|
2433
|
+
fromExtension = true;
|
|
2434
|
+
return { result: extensionResult.compaction };
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
const compactResult = await this._compactWithRetry(() => compact(preparation, compactModel, apiKey, headers, undefined, signal, compactionThinkingLevel, this.agent.streamFn, this._buildCompactionPreDigest(), { chunked: params.chunked }), signal, compactModel.provider);
|
|
2438
|
+
return { result: compactResult };
|
|
2439
|
+
},
|
|
2440
|
+
buildDeterministicCheckpoint: async () => {
|
|
2441
|
+
const branch = this.sessionManager.getBranch();
|
|
2442
|
+
const preparation = prepareCompaction(branch, {
|
|
2443
|
+
...settings,
|
|
2444
|
+
});
|
|
2445
|
+
if (!preparation) {
|
|
2446
|
+
throw new Error("already compacted");
|
|
2447
|
+
}
|
|
2448
|
+
fromExtension = false;
|
|
2449
|
+
return { result: createDeterministicCompaction(preparation) };
|
|
2450
|
+
},
|
|
2451
|
+
apply: async (result) => {
|
|
2452
|
+
lastCompaction = result;
|
|
2453
|
+
this.sessionManager.appendCompaction(result.summary, result.firstKeptEntryId, result.tokensBefore, result.details, fromExtension);
|
|
2454
|
+
this.agent.state.messages = this.sessionManager.buildSessionContext().messages;
|
|
2455
|
+
const newEntries = this.sessionManager.getEntries();
|
|
2456
|
+
const savedCompactionEntry = newEntries.find((entry) => entry.type === "compaction" && entry.summary === result.summary);
|
|
2457
|
+
if (this._extensionRunner && savedCompactionEntry) {
|
|
2458
|
+
await this._extensionRunner.emit({
|
|
2459
|
+
type: "session_compact",
|
|
2460
|
+
compactionEntry: savedCompactionEntry,
|
|
2461
|
+
fromExtension,
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
},
|
|
2465
|
+
onTransition: ({ cycle, cause }) => {
|
|
2466
|
+
this._emit({
|
|
2467
|
+
type: "warning",
|
|
2468
|
+
message: `auto-compaction cycle ${cycle}: ${cause} — retrying from step 0`,
|
|
2469
|
+
});
|
|
2470
|
+
},
|
|
2471
|
+
signal,
|
|
2472
|
+
});
|
|
2473
|
+
if (outcome.kind === "skip") {
|
|
2428
2474
|
this._emit({
|
|
2429
2475
|
type: "compaction_end",
|
|
2430
2476
|
reason,
|
|
2431
2477
|
result: undefined,
|
|
2432
2478
|
aborted: false,
|
|
2433
2479
|
willRetry: false,
|
|
2434
|
-
skipReason:
|
|
2480
|
+
skipReason: outcome.reason,
|
|
2435
2481
|
});
|
|
2436
|
-
return
|
|
2482
|
+
return hadQueuedMessages || this.agent.hasQueuedMessages();
|
|
2437
2483
|
}
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
const extensionResult = (await this._extensionRunner.emit({
|
|
2442
|
-
type: "session_before_compact",
|
|
2443
|
-
preparation,
|
|
2444
|
-
branchEntries: pathEntries,
|
|
2445
|
-
customInstructions: undefined,
|
|
2446
|
-
signal: this._autoCompactionAbortController.signal,
|
|
2447
|
-
}));
|
|
2448
|
-
if (extensionResult?.cancel) {
|
|
2449
|
-
this._emit({
|
|
2450
|
-
type: "compaction_end",
|
|
2451
|
-
reason,
|
|
2452
|
-
result: undefined,
|
|
2453
|
-
aborted: true,
|
|
2454
|
-
willRetry: false,
|
|
2455
|
-
});
|
|
2484
|
+
if (outcome.kind === "failed") {
|
|
2485
|
+
if (outcome.reason === "aborted") {
|
|
2486
|
+
this._emit({ type: "compaction_end", reason, result: undefined, aborted: true, willRetry: false });
|
|
2456
2487
|
return false;
|
|
2457
2488
|
}
|
|
2458
|
-
|
|
2459
|
-
extensionCompaction = extensionResult.compaction;
|
|
2460
|
-
fromExtension = true;
|
|
2461
|
-
}
|
|
2489
|
+
throw new Error(outcome.reason);
|
|
2462
2490
|
}
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
let tokensBefore;
|
|
2466
|
-
let details;
|
|
2467
|
-
if (extensionCompaction) {
|
|
2468
|
-
// Extension provided compaction content
|
|
2469
|
-
summary = extensionCompaction.summary;
|
|
2470
|
-
firstKeptEntryId = extensionCompaction.firstKeptEntryId;
|
|
2471
|
-
tokensBefore = extensionCompaction.tokensBefore;
|
|
2472
|
-
details = extensionCompaction.details;
|
|
2473
|
-
}
|
|
2474
|
-
else {
|
|
2475
|
-
// Generate compaction result
|
|
2476
|
-
const autoCompactionSignal = this._autoCompactionAbortController.signal;
|
|
2477
|
-
const compactResult = await this._compactWithRetry(() => compact(preparation, compactionModel, apiKey, headers, undefined, autoCompactionSignal, compactionThinkingLevel, this.agent.streamFn, this._buildCompactionPreDigest()), autoCompactionSignal);
|
|
2478
|
-
summary = compactResult.summary;
|
|
2479
|
-
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
2480
|
-
tokensBefore = compactResult.tokensBefore;
|
|
2481
|
-
details = compactResult.details;
|
|
2482
|
-
}
|
|
2483
|
-
if (this._autoCompactionAbortController.signal.aborted) {
|
|
2484
|
-
this._emit({
|
|
2485
|
-
type: "compaction_end",
|
|
2486
|
-
reason,
|
|
2487
|
-
result: undefined,
|
|
2488
|
-
aborted: true,
|
|
2489
|
-
willRetry: false,
|
|
2490
|
-
});
|
|
2491
|
+
if (extensionCancelled || signal.aborted) {
|
|
2492
|
+
this._emit({ type: "compaction_end", reason, result: undefined, aborted: true, willRetry: false });
|
|
2491
2493
|
return false;
|
|
2492
2494
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
this.agent.state.messages = sessionContext.messages;
|
|
2497
|
-
// Get the saved compaction entry for the extension event
|
|
2498
|
-
const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
|
|
2499
|
-
if (this._extensionRunner && savedCompactionEntry) {
|
|
2500
|
-
await this._extensionRunner.emit({
|
|
2501
|
-
type: "session_compact",
|
|
2502
|
-
compactionEntry: savedCompactionEntry,
|
|
2503
|
-
fromExtension,
|
|
2504
|
-
});
|
|
2495
|
+
const result = outcome.kind === "success" ? outcome.result : lastCompaction;
|
|
2496
|
+
if (!result) {
|
|
2497
|
+
throw new Error("Auto-compaction succeeded without a result");
|
|
2505
2498
|
}
|
|
2506
|
-
const result = {
|
|
2507
|
-
summary,
|
|
2508
|
-
firstKeptEntryId,
|
|
2509
|
-
tokensBefore,
|
|
2510
|
-
details,
|
|
2511
|
-
};
|
|
2512
2499
|
this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
|
|
2513
2500
|
if (willRetry) {
|
|
2514
2501
|
const messages = this.agent.state.messages;
|
|
@@ -2518,9 +2505,7 @@ export class AgentSession {
|
|
|
2518
2505
|
}
|
|
2519
2506
|
return true;
|
|
2520
2507
|
}
|
|
2521
|
-
|
|
2522
|
-
// Continue once so queued messages are delivered.
|
|
2523
|
-
return this.agent.hasQueuedMessages();
|
|
2508
|
+
return hadQueuedMessages || this.agent.hasQueuedMessages();
|
|
2524
2509
|
}
|
|
2525
2510
|
catch (error) {
|
|
2526
2511
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
@@ -2548,7 +2533,7 @@ export class AgentSession {
|
|
|
2548
2533
|
* same failure via auto-retry. Caller aborts are never retried; sleepAbortable rejects
|
|
2549
2534
|
* with the abort reason if the signal fires mid-backoff.
|
|
2550
2535
|
*/
|
|
2551
|
-
async _compactWithRetry(run, signal) {
|
|
2536
|
+
async _compactWithRetry(run, signal, provider) {
|
|
2552
2537
|
const retrySettings = this.settingsManager.getRetrySettings();
|
|
2553
2538
|
const maxAttempts = retrySettings.enabled ? Math.max(1, retrySettings.maxRetries + 1) : 1;
|
|
2554
2539
|
const policy = {
|
|
@@ -2565,7 +2550,7 @@ export class AgentSession {
|
|
|
2565
2550
|
if (signal.aborted || attempt >= maxAttempts)
|
|
2566
2551
|
throw error;
|
|
2567
2552
|
const message = error instanceof Error ? error.message : String(error);
|
|
2568
|
-
const classified = classifyFailure({ message });
|
|
2553
|
+
const classified = classifyFailure({ message, provider });
|
|
2569
2554
|
if (!classified.retryable)
|
|
2570
2555
|
throw error;
|
|
2571
2556
|
await sleepAbortable(computeRetryDelayMs(policy, attempt, { retryAfterMs: classified.retryAfterMs }), signal);
|
|
@@ -2854,6 +2839,7 @@ export class AgentSession {
|
|
|
2854
2839
|
return classifyFailure({
|
|
2855
2840
|
message: message.errorMessage,
|
|
2856
2841
|
contextOverflow: isContextOverflow(message, contextWindow),
|
|
2842
|
+
provider: message.provider,
|
|
2857
2843
|
}).retryable;
|
|
2858
2844
|
}
|
|
2859
2845
|
/**
|