@leanandmean/coding-agent 0.74.1-scramjet.68 → 0.74.1-scramjet.69
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/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +57 -20
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +3 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +47 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/docs/compaction.md +3 -1
- package/docs/custom-provider.md +23 -3
- package/docs/sdk.md +6 -0
- package/docs/settings.md +6 -2
- package/package.json +4 -4
|
@@ -17,14 +17,13 @@ import { basename, dirname, resolve } from "node:path";
|
|
|
17
17
|
// SCRAMJET-DIVERGENCE: provider-safe harness tool-call id generation for the persisted-settlement
|
|
18
18
|
// acknowledgement key (#341).
|
|
19
19
|
import { generateHarnessToolCallId } from "@leanandmean/agent";
|
|
20
|
-
import { clampThinkingLevel, cleanupSessionResources, flattenSystemPrompt, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, resetApiProviders, } from "@leanandmean/ai";
|
|
21
|
-
import { validateResponsesProviderFailure } from "@leanandmean/ai/openai-responses";
|
|
20
|
+
import { blocksFailureRecovery, clampThinkingLevel, cleanupSessionResources, flattenSystemPrompt, getSupportedThinkingLevels, inspectFailureEvidence, isContextOverflow, modelsAreEqual, resetApiProviders, } from "@leanandmean/ai";
|
|
22
21
|
import { theme } from "../modes/interactive/theme/theme.js";
|
|
23
22
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
24
23
|
import { sleep } from "../utils/sleep.js";
|
|
25
24
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
26
25
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
27
|
-
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
26
|
+
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
28
27
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
29
28
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
30
29
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
@@ -1319,7 +1318,7 @@ export class AgentSession {
|
|
|
1319
1318
|
// Check if we need to compact before sending (catches aborted responses)
|
|
1320
1319
|
const lastAssistant = this._findLastAssistantMessage();
|
|
1321
1320
|
if (lastAssistant) {
|
|
1322
|
-
await this._checkCompaction(lastAssistant,
|
|
1321
|
+
await this._checkCompaction(lastAssistant, "new_prompt");
|
|
1323
1322
|
}
|
|
1324
1323
|
// Build messages array (custom message if any, then user message)
|
|
1325
1324
|
messages = [];
|
|
@@ -2005,17 +2004,43 @@ export class AgentSession {
|
|
|
2005
2004
|
* 2. Threshold: Context over threshold, compact, NO auto-retry (user continues manually)
|
|
2006
2005
|
*
|
|
2007
2006
|
* @param assistantMessage The assistant message to check
|
|
2008
|
-
* @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true
|
|
2009
2007
|
*/
|
|
2010
|
-
async _checkCompaction(assistantMessage,
|
|
2008
|
+
async _checkCompaction(assistantMessage, trigger = "settlement") {
|
|
2011
2009
|
if (this._manualCompactionDrain)
|
|
2012
2010
|
return;
|
|
2013
2011
|
const settings = this.settingsManager.getCompactionSettings();
|
|
2014
2012
|
if (!settings.enabled)
|
|
2015
2013
|
return;
|
|
2016
|
-
//
|
|
2017
|
-
if (
|
|
2014
|
+
// SCRAMJET-DIVERGENCE: New prompts maintain context independently of failed-turn recovery.
|
|
2015
|
+
if (trigger === "settlement" && blocksFailureRecovery(assistantMessage))
|
|
2018
2016
|
return;
|
|
2017
|
+
if (trigger === "new_prompt") {
|
|
2018
|
+
const boundary = getLatestCompactionEntry(this.sessionManager.getBranch());
|
|
2019
|
+
const messages = this.agent.state.messages;
|
|
2020
|
+
const reverseIndex = [...messages]
|
|
2021
|
+
.reverse()
|
|
2022
|
+
.findIndex((message) => message.role === "assistant" &&
|
|
2023
|
+
message.origin !== "harness" &&
|
|
2024
|
+
message.stopReason !== "error" &&
|
|
2025
|
+
message.stopReason !== "aborted" &&
|
|
2026
|
+
message.provider === this.model?.provider &&
|
|
2027
|
+
message.model === this.model?.id &&
|
|
2028
|
+
Number.isFinite(calculateContextTokens(message.usage)) &&
|
|
2029
|
+
calculateContextTokens(message.usage) >= 0 &&
|
|
2030
|
+
(!boundary || message.timestamp > new Date(boundary.timestamp).getTime()) &&
|
|
2031
|
+
[message.usage.input, message.usage.output, message.usage.cacheRead, message.usage.cacheWrite].every((n) => Number.isFinite(n) && n >= 0));
|
|
2032
|
+
if (reverseIndex < 0)
|
|
2033
|
+
return;
|
|
2034
|
+
const sourceIndex = messages.length - reverseIndex - 1;
|
|
2035
|
+
const source = messages[sourceIndex];
|
|
2036
|
+
const tokens = calculateContextTokens(source.usage) +
|
|
2037
|
+
messages.slice(sourceIndex + 1).reduce((total, message) => total + estimateTokens(message), 0);
|
|
2038
|
+
const window = this.model?.contextWindow ?? 0;
|
|
2039
|
+
if (shouldCompact(tokens, window, settings) ||
|
|
2040
|
+
(window > settings.reserveTokens && tokens > (this.model?.maxInputTokens ?? Infinity)))
|
|
2041
|
+
await this._runAutoCompaction("threshold", false);
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2019
2044
|
// SCRAMJET-DIVERGENCE: Total context and independent input limits are separate constraints.
|
|
2020
2045
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
2021
2046
|
// Skip overflow check if the message came from a different model.
|
|
@@ -2577,20 +2602,30 @@ export class AgentSession {
|
|
|
2577
2602
|
// =========================================================================
|
|
2578
2603
|
// SCRAMJET-DIVERGENCE: persisted post-extension snapshots authoritatively classify and settle retries (#553).
|
|
2579
2604
|
_classifyRetry(message) {
|
|
2605
|
+
if ((message.origin === "harness" || message.stopReason === "aborted") && blocksFailureRecovery(message))
|
|
2606
|
+
return { kind: "do_not_retry", reason: "non_provider_failure", evidence: "none" };
|
|
2580
2607
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
2581
2608
|
if (isContextOverflow(message, Math.min(contextWindow, this.model?.maxInputTokens ?? Infinity))) {
|
|
2582
2609
|
return { kind: "context_overflow" };
|
|
2583
2610
|
}
|
|
2584
|
-
const structured =
|
|
2611
|
+
const structured = inspectFailureEvidence(message.diagnostics);
|
|
2585
2612
|
if (structured.status === "valid") {
|
|
2586
|
-
if (structured.
|
|
2587
|
-
return { kind: "
|
|
2613
|
+
if (structured.source !== "provider")
|
|
2614
|
+
return { kind: "do_not_retry", reason: "non_provider_failure", evidence: "none" };
|
|
2615
|
+
if (structured.suppression)
|
|
2616
|
+
return { kind: "do_not_retry", reason: structured.suppression, evidence: structured.family };
|
|
2617
|
+
if (structured.transient || ["missing_terminal_event", "missing_body"].includes(structured.category))
|
|
2618
|
+
return { kind: "retry", evidence: structured.family };
|
|
2588
2619
|
return {
|
|
2589
2620
|
kind: "do_not_retry",
|
|
2590
|
-
reason:
|
|
2591
|
-
|
|
2621
|
+
reason: ["unknown", "provider_error", "malformed_event"].includes(structured.category)
|
|
2622
|
+
? "structured_unknown"
|
|
2623
|
+
: "structured_non_transient",
|
|
2624
|
+
evidence: structured.family,
|
|
2592
2625
|
};
|
|
2593
2626
|
}
|
|
2627
|
+
if (structured.status === "conflicting")
|
|
2628
|
+
return { kind: "do_not_retry", reason: "invalid_failure_evidence", evidence: "none" };
|
|
2594
2629
|
if (structured.status === "malformed") {
|
|
2595
2630
|
return { kind: "do_not_retry", reason: "malformed_provider_diagnostic", evidence: "none" };
|
|
2596
2631
|
}
|
|
@@ -2687,9 +2722,8 @@ export class AgentSession {
|
|
|
2687
2722
|
async _handleRetryableError(message, evidence, run) {
|
|
2688
2723
|
const settings = this.settingsManager.getRetrySettings();
|
|
2689
2724
|
const attempt = (this._retry?.attempt ?? 0) + 1;
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
if (attempt > settings.maxRetries) {
|
|
2725
|
+
const cumulativeCap = Math.min(Number.MAX_SAFE_INTEGER, settings.maxRetries * 2);
|
|
2726
|
+
if ((this._retry?.attempt ?? 0) >= settings.maxRetries) {
|
|
2693
2727
|
const attemptsCompleted = attempt - 1;
|
|
2694
2728
|
this._finishRetry({
|
|
2695
2729
|
schemaVersion: 1,
|
|
@@ -2701,15 +2735,15 @@ export class AgentSession {
|
|
|
2701
2735
|
}, { type: "auto_retry_end", success: false, attempt: attemptsCompleted, finalError: message.errorMessage });
|
|
2702
2736
|
return false;
|
|
2703
2737
|
}
|
|
2704
|
-
if (this._runRetryCount
|
|
2705
|
-
const attemptsCompleted = this._runRetryCount
|
|
2738
|
+
if (this._runRetryCount >= cumulativeCap) {
|
|
2739
|
+
const attemptsCompleted = this._runRetryCount;
|
|
2706
2740
|
this._finishRetry({
|
|
2707
2741
|
schemaVersion: 1,
|
|
2708
2742
|
outcome: "exhausted",
|
|
2709
2743
|
reason: "cumulative_limit",
|
|
2710
2744
|
attemptsCompleted: this._bounded(attemptsCompleted),
|
|
2711
2745
|
maxAttempts: this._bounded(settings.maxRetries),
|
|
2712
|
-
cumulativeErrors: this._bounded(this._runRetryCount),
|
|
2746
|
+
cumulativeErrors: this._bounded(this._runRetryCount + 1),
|
|
2713
2747
|
}, {
|
|
2714
2748
|
type: "auto_retry_end",
|
|
2715
2749
|
success: false,
|
|
@@ -2718,7 +2752,10 @@ export class AgentSession {
|
|
|
2718
2752
|
});
|
|
2719
2753
|
return false;
|
|
2720
2754
|
}
|
|
2721
|
-
|
|
2755
|
+
this._runRetryCount++;
|
|
2756
|
+
const delayMs = settings.baseDelayMs === 0
|
|
2757
|
+
? 0
|
|
2758
|
+
: Math.min(2_147_483_647, settings.baseDelayMs * 2 ** Math.min(31, attempt - 1));
|
|
2722
2759
|
const previous = this._retry;
|
|
2723
2760
|
this._retry = undefined;
|
|
2724
2761
|
try {
|