@code-yeongyu/senpi 2026.5.15 → 2026.5.16
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 +1113 -1177
- package/README.md +1 -2
- package/dist/core/agent-session.d.ts +9 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +114 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/dynamic-prompt/verification.d.ts +31 -0
- package/dist/core/dynamic-prompt/verification.d.ts.map +1 -1
- package/dist/core/dynamic-prompt/verification.js +41 -0
- package/dist/core/dynamic-prompt/verification.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/context-reduction.d.ts +97 -0
- package/dist/core/extensions/builtin/compaction/context-reduction.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/context-reduction.js +420 -0
- package/dist/core/extensions/builtin/compaction/context-reduction.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +168 -31
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +197 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.js +690 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/prompts.d.ts +3 -3
- package/dist/core/extensions/builtin/compaction/prompts.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/prompts.js +0 -22
- package/dist/core/extensions/builtin/compaction/prompts.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts +4 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js +48 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +3 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +80 -33
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +8 -0
- package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/todo-bridge.js +12 -6
- package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
- package/dist/core/extensions/builtin/diff.d.ts.map +1 -1
- package/dist/core/extensions/builtin/diff.js +1 -1
- package/dist/core/extensions/builtin/diff.js.map +1 -1
- package/dist/core/extensions/builtin/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/index.js +0 -2
- package/dist/core/extensions/builtin/index.js.map +1 -1
- package/dist/core/extensions/builtin/openai-web-search/index.d.ts +6 -2
- package/dist/core/extensions/builtin/openai-web-search/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/openai-web-search/index.js +82 -10
- package/dist/core/extensions/builtin/openai-web-search/index.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/prompt.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/prompt.js +0 -5
- package/dist/core/extensions/builtin/permission-system/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/system-messages.d.ts +1 -1
- package/dist/core/extensions/builtin/system-messages.d.ts.map +1 -1
- package/dist/core/extensions/builtin/system-messages.js.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.js +8 -4
- package/dist/core/extensions/builtin/tool-pair-guard/index.js.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js +89 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js +122 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +18 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +22 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/messages.d.ts +3 -3
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +5 -10
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -22
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/thinking-levels.d.ts +6 -0
- package/dist/core/thinking-levels.d.ts.map +1 -0
- package/dist/core/thinking-levels.js +36 -0
- package/dist/core/thinking-levels.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +15 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +20 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +3 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +137 -49
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/working-status.d.ts +15 -0
- package/dist/modes/interactive/working-status.d.ts.map +1 -0
- package/dist/modes/interactive/working-status.js +60 -0
- package/dist/modes/interactive/working-status.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/docs/extensions.md +0 -1
- package/docs/index.md +0 -1
- package/docs/models.md +9 -0
- package/docs/sdk.md +0 -1
- package/docs/settings.md +1 -29
- package/docs/termux.md +2 -2
- package/docs/usage.md +1 -1
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/overlay-qa-tests.ts +1 -1
- package/package.json +4 -4
- package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts +0 -10
- package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/cancel-tool.js +0 -109
- package/dist/core/extensions/builtin/background-task/cancel-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/index.d.ts +0 -3
- package/dist/core/extensions/builtin/background-task/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/index.js +0 -207
- package/dist/core/extensions/builtin/background-task/index.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/manager.d.ts +0 -17
- package/dist/core/extensions/builtin/background-task/manager.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/manager.js +0 -114
- package/dist/core/extensions/builtin/background-task/manager.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/notification.d.ts +0 -22
- package/dist/core/extensions/builtin/background-task/notification.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/notification.js +0 -105
- package/dist/core/extensions/builtin/background-task/notification.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/output-tool.d.ts +0 -11
- package/dist/core/extensions/builtin/background-task/output-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/output-tool.js +0 -127
- package/dist/core/extensions/builtin/background-task/output-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/spawner.d.ts +0 -8
- package/dist/core/extensions/builtin/background-task/spawner.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/spawner.js +0 -207
- package/dist/core/extensions/builtin/background-task/spawner.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/task-tool.d.ts +0 -20
- package/dist/core/extensions/builtin/background-task/task-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/task-tool.js +0 -302
- package/dist/core/extensions/builtin/background-task/task-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/types.d.ts +0 -72
- package/dist/core/extensions/builtin/background-task/types.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/types.js +0 -32
- package/dist/core/extensions/builtin/background-task/types.js.map +0 -1
- package/docs/agents.md +0 -348
- package/examples/extensions/subagent/README.md +0 -172
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -987
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
16
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { basename, dirname, resolve } from "node:path";
|
|
18
|
-
import { cleanupSessionResources,
|
|
18
|
+
import { cleanupSessionResources, isContextOverflow, modelsAreEqual, resetApiProviders } from "@earendil-works/pi-ai";
|
|
19
19
|
import { expandTildePath } from "../config.js";
|
|
20
20
|
import { theme } from "../modes/interactive/theme/theme.js";
|
|
21
21
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
@@ -34,6 +34,7 @@ import { getModelNarrowingPatterns, resolveModelScope } from "./model-resolver.j
|
|
|
34
34
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
35
35
|
import { buildSessionContext, CURRENT_SESSION_VERSION, getLatestCompactionEntry, } from "./session-manager.js";
|
|
36
36
|
import { createSyntheticSourceInfo } from "./source-info.js";
|
|
37
|
+
import { getSupportedThinkingLevels, supportsMax, supportsXhigh } from "./thinking-levels.js";
|
|
37
38
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
38
39
|
import { createAllToolDefinitions } from "./tools/index.js";
|
|
39
40
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
@@ -1377,8 +1378,11 @@ export class AgentSession {
|
|
|
1377
1378
|
if (options.expectedRevision !== undefined && options.expectedRevision !== this._messageRevision) {
|
|
1378
1379
|
return { applied: false, reason: "stale" };
|
|
1379
1380
|
}
|
|
1380
|
-
this._compactionAbortController
|
|
1381
|
-
|
|
1381
|
+
const ownsController = this._compactionAbortController === undefined;
|
|
1382
|
+
if (ownsController) {
|
|
1383
|
+
this._compactionAbortController = new AbortController();
|
|
1384
|
+
this._emit({ type: "compaction_start", reason: options.reason });
|
|
1385
|
+
}
|
|
1382
1386
|
try {
|
|
1383
1387
|
const execution = await this._executeCompaction({
|
|
1384
1388
|
reason: options.reason,
|
|
@@ -1407,6 +1411,38 @@ export class AgentSession {
|
|
|
1407
1411
|
this._compactionAbortController = undefined;
|
|
1408
1412
|
}
|
|
1409
1413
|
}
|
|
1414
|
+
_beginExtensionCompactionFeedback(reason) {
|
|
1415
|
+
if (!this._compactionAbortController) {
|
|
1416
|
+
this._compactionAbortController = new AbortController();
|
|
1417
|
+
this._emit({ type: "compaction_start", reason });
|
|
1418
|
+
}
|
|
1419
|
+
return this._compactionAbortController.signal;
|
|
1420
|
+
}
|
|
1421
|
+
_updateExtensionCompactionFeedback(options) {
|
|
1422
|
+
if (!this._compactionAbortController && !this._autoCompactionAbortController)
|
|
1423
|
+
return;
|
|
1424
|
+
this._emit({
|
|
1425
|
+
type: "compaction_progress",
|
|
1426
|
+
reason: options.reason,
|
|
1427
|
+
...(options.delta !== undefined ? { delta: options.delta } : {}),
|
|
1428
|
+
...(options.text !== undefined ? { text: options.text } : {}),
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
_endExtensionCompactionFeedback(options) {
|
|
1432
|
+
const controller = this._compactionAbortController;
|
|
1433
|
+
if (!controller)
|
|
1434
|
+
return;
|
|
1435
|
+
const aborted = options.aborted ?? controller.signal.aborted;
|
|
1436
|
+
this._emit({
|
|
1437
|
+
type: "compaction_end",
|
|
1438
|
+
reason: options.reason,
|
|
1439
|
+
result: undefined,
|
|
1440
|
+
aborted,
|
|
1441
|
+
willRetry: false,
|
|
1442
|
+
errorMessage: aborted ? undefined : options.errorMessage,
|
|
1443
|
+
});
|
|
1444
|
+
this._compactionAbortController = undefined;
|
|
1445
|
+
}
|
|
1410
1446
|
async _executeCompaction(request) {
|
|
1411
1447
|
if (!this.model) {
|
|
1412
1448
|
throw new Error(formatNoModelSelectedMessage());
|
|
@@ -1573,14 +1609,18 @@ export class AgentSession {
|
|
|
1573
1609
|
shouldCompact(contextUsage.tokens, contextUsage.contextWindow, settings);
|
|
1574
1610
|
if (isContextOverflow(assistantMessage, contextWindow) && (sameModel || currentContextNeedsCompaction)) {
|
|
1575
1611
|
if (this._overflowRecoveryAttempted) {
|
|
1612
|
+
const errorMessage = "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.";
|
|
1576
1613
|
this._emit({
|
|
1577
1614
|
type: "compaction_end",
|
|
1578
1615
|
reason: "overflow",
|
|
1579
1616
|
result: undefined,
|
|
1580
1617
|
aborted: false,
|
|
1581
1618
|
willRetry: false,
|
|
1582
|
-
errorMessage
|
|
1619
|
+
errorMessage,
|
|
1583
1620
|
});
|
|
1621
|
+
if (requestReason === "pre_prompt") {
|
|
1622
|
+
throw new Error(errorMessage);
|
|
1623
|
+
}
|
|
1584
1624
|
return;
|
|
1585
1625
|
}
|
|
1586
1626
|
this._overflowRecoveryAttempted = true;
|
|
@@ -1635,14 +1675,20 @@ export class AgentSession {
|
|
|
1635
1675
|
this._emit({ type: "compaction_start", reason: "pre_prompt" });
|
|
1636
1676
|
this._compactionAbortController = new AbortController();
|
|
1637
1677
|
try {
|
|
1638
|
-
await this._executeCompaction({
|
|
1678
|
+
const execution = await this._executeCompaction({
|
|
1639
1679
|
reason: "pre_prompt",
|
|
1640
1680
|
willRetry: false,
|
|
1641
1681
|
lastAssistantMessage,
|
|
1642
1682
|
skipAbortedCheck,
|
|
1643
1683
|
});
|
|
1684
|
+
if (!execution.accepted && isContextOverflow(lastAssistantMessage, this.model?.contextWindow ?? 0)) {
|
|
1685
|
+
this._overflowRecoveryAttempted = false;
|
|
1686
|
+
}
|
|
1644
1687
|
}
|
|
1645
1688
|
catch (error) {
|
|
1689
|
+
if (isContextOverflow(lastAssistantMessage, this.model?.contextWindow ?? 0)) {
|
|
1690
|
+
this._overflowRecoveryAttempted = false;
|
|
1691
|
+
}
|
|
1646
1692
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1647
1693
|
const aborted = errorMessage === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1648
1694
|
this._emit({
|
|
@@ -1666,6 +1712,8 @@ export class AgentSession {
|
|
|
1666
1712
|
this._autoCompactionAbortController = new AbortController();
|
|
1667
1713
|
try {
|
|
1668
1714
|
if (!this.model) {
|
|
1715
|
+
if (reason === "overflow")
|
|
1716
|
+
this._overflowRecoveryAttempted = false;
|
|
1669
1717
|
this._emit({
|
|
1670
1718
|
type: "compaction_end",
|
|
1671
1719
|
reason,
|
|
@@ -1677,6 +1725,8 @@ export class AgentSession {
|
|
|
1677
1725
|
}
|
|
1678
1726
|
const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
|
|
1679
1727
|
if (!authResult.ok || !authResult.apiKey) {
|
|
1728
|
+
if (reason === "overflow")
|
|
1729
|
+
this._overflowRecoveryAttempted = false;
|
|
1680
1730
|
this._emit({
|
|
1681
1731
|
type: "compaction_end",
|
|
1682
1732
|
reason,
|
|
@@ -1688,6 +1738,8 @@ export class AgentSession {
|
|
|
1688
1738
|
}
|
|
1689
1739
|
const preparation = prepareCompaction(this.sessionManager.getBranch(), this.settingsManager.getCompactionSettings());
|
|
1690
1740
|
if (!preparation) {
|
|
1741
|
+
if (reason === "overflow")
|
|
1742
|
+
this._overflowRecoveryAttempted = false;
|
|
1691
1743
|
this._emit({
|
|
1692
1744
|
type: "compaction_end",
|
|
1693
1745
|
reason,
|
|
@@ -1699,6 +1751,8 @@ export class AgentSession {
|
|
|
1699
1751
|
}
|
|
1700
1752
|
const execution = await this._executeCompaction({ reason, willRetry });
|
|
1701
1753
|
if (!execution.accepted) {
|
|
1754
|
+
if (reason === "overflow")
|
|
1755
|
+
this._overflowRecoveryAttempted = false;
|
|
1702
1756
|
return;
|
|
1703
1757
|
}
|
|
1704
1758
|
if (willRetry) {
|
|
@@ -1721,6 +1775,8 @@ export class AgentSession {
|
|
|
1721
1775
|
}
|
|
1722
1776
|
}
|
|
1723
1777
|
catch (error) {
|
|
1778
|
+
if (reason === "overflow")
|
|
1779
|
+
this._overflowRecoveryAttempted = false;
|
|
1724
1780
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1725
1781
|
const aborted = errorMessage === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1726
1782
|
this._emit({
|
|
@@ -1943,6 +1999,9 @@ export class AgentSession {
|
|
|
1943
1999
|
}
|
|
1944
2000
|
})();
|
|
1945
2001
|
},
|
|
2002
|
+
beginCompaction: (options) => this._beginExtensionCompactionFeedback(options.reason),
|
|
2003
|
+
updateCompaction: (options) => this._updateExtensionCompactionFeedback(options),
|
|
2004
|
+
endCompaction: (options) => this._endExtensionCompactionFeedback(options),
|
|
1946
2005
|
getMessageRevision: () => this.getMessageRevision(),
|
|
1947
2006
|
applyCompaction: (precomputed, options) => this.applyCompaction(precomputed, options),
|
|
1948
2007
|
getSystemPrompt: () => this.systemPrompt,
|
|
@@ -2101,16 +2160,49 @@ export class AgentSession {
|
|
|
2101
2160
|
* Context overflow errors are NOT retryable (handled by compaction instead).
|
|
2102
2161
|
*/
|
|
2103
2162
|
_isRetryableError(message) {
|
|
2104
|
-
if (
|
|
2163
|
+
if (!message.errorMessage)
|
|
2105
2164
|
return false;
|
|
2106
2165
|
// Context overflow is handled by compaction, not retry
|
|
2107
2166
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
2108
2167
|
if (isContextOverflow(message, contextWindow))
|
|
2109
2168
|
return false;
|
|
2110
2169
|
const err = message.errorMessage;
|
|
2170
|
+
if (message.stopReason === "aborted") {
|
|
2171
|
+
return /timed? out|timeout/i.test(err);
|
|
2172
|
+
}
|
|
2173
|
+
if (message.stopReason !== "error")
|
|
2174
|
+
return false;
|
|
2111
2175
|
// Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504, service unavailable, network/connection errors (including connection lost), WebSocket transport closes/errors, fetch failed, premature stream endings, HTTP/2 closed before response, terminated, retry delay exceeded
|
|
2112
2176
|
return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|stream ended before message_stop|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i.test(err);
|
|
2113
2177
|
}
|
|
2178
|
+
_getProviderRetryDelayMs(errorMessage) {
|
|
2179
|
+
const retryAfterMsMatch = errorMessage.match(/\bretry[-_ ]?after[-_ ]?ms\s*[:=]\s*(\d+(?:\.\d+)?)/i);
|
|
2180
|
+
if (retryAfterMsMatch) {
|
|
2181
|
+
const delayMs = Math.ceil(Number(retryAfterMsMatch[1]));
|
|
2182
|
+
return Number.isFinite(delayMs) && delayMs > 0 ? delayMs : undefined;
|
|
2183
|
+
}
|
|
2184
|
+
const retryAfterSecondsMatch = errorMessage.match(/\bretry[-_ ]?after\s*[:=]\s*(\d+(?:\.\d+)?)/i);
|
|
2185
|
+
if (retryAfterSecondsMatch) {
|
|
2186
|
+
const delayMs = Math.ceil(Number(retryAfterSecondsMatch[1]) * 1000);
|
|
2187
|
+
return Number.isFinite(delayMs) && delayMs > 0 ? delayMs : undefined;
|
|
2188
|
+
}
|
|
2189
|
+
const retryInMatch = errorMessage.match(/\b(?:retry|try again|wait)\s+(?:after|in)\s*(\d+(?:\.\d+)?)\s*(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m)\b/i);
|
|
2190
|
+
if (!retryInMatch) {
|
|
2191
|
+
return undefined;
|
|
2192
|
+
}
|
|
2193
|
+
const value = Number(retryInMatch[1]);
|
|
2194
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
2195
|
+
return undefined;
|
|
2196
|
+
}
|
|
2197
|
+
const unit = retryInMatch[2].toLowerCase();
|
|
2198
|
+
if (unit === "m" || unit.startsWith("min")) {
|
|
2199
|
+
return Math.ceil(value * 60_000);
|
|
2200
|
+
}
|
|
2201
|
+
if (unit.startsWith("s")) {
|
|
2202
|
+
return Math.ceil(value * 1000);
|
|
2203
|
+
}
|
|
2204
|
+
return Math.ceil(value);
|
|
2205
|
+
}
|
|
2114
2206
|
/**
|
|
2115
2207
|
* Handle retryable errors with exponential backoff.
|
|
2116
2208
|
* @returns true if retry was initiated, false if max retries exceeded or disabled
|
|
@@ -2141,13 +2233,27 @@ export class AgentSession {
|
|
|
2141
2233
|
this._resolveRetry(); // Resolve so waitForRetry() completes
|
|
2142
2234
|
return false;
|
|
2143
2235
|
}
|
|
2144
|
-
const
|
|
2236
|
+
const errorMessage = message.errorMessage || "Unknown error";
|
|
2237
|
+
const providerDelayMs = this._getProviderRetryDelayMs(errorMessage);
|
|
2238
|
+
const maxRetryDelayMs = this.settingsManager.getProviderRetrySettings().maxRetryDelayMs;
|
|
2239
|
+
if (providerDelayMs !== undefined && providerDelayMs > maxRetryDelayMs) {
|
|
2240
|
+
this._emit({
|
|
2241
|
+
type: "auto_retry_end",
|
|
2242
|
+
success: false,
|
|
2243
|
+
attempt: this._retryAttempt,
|
|
2244
|
+
finalError: `Provider requested retry delay ${providerDelayMs}ms, exceeding configured maximum ${maxRetryDelayMs}ms`,
|
|
2245
|
+
});
|
|
2246
|
+
this._retryAttempt = 0;
|
|
2247
|
+
this._resolveRetry();
|
|
2248
|
+
return false;
|
|
2249
|
+
}
|
|
2250
|
+
const delayMs = providerDelayMs ?? settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
|
|
2145
2251
|
this._emit({
|
|
2146
2252
|
type: "auto_retry_start",
|
|
2147
2253
|
attempt: this._retryAttempt,
|
|
2148
2254
|
maxAttempts: settings.maxRetries,
|
|
2149
2255
|
delayMs,
|
|
2150
|
-
errorMessage
|
|
2256
|
+
errorMessage,
|
|
2151
2257
|
});
|
|
2152
2258
|
// Remove error message from agent state (keep in session for history)
|
|
2153
2259
|
const messages = this.agent.state.messages;
|