@code-yeongyu/senpi 2026.5.14 → 2026.5.15-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.
Files changed (175) hide show
  1. package/CHANGELOG.md +1110 -1175
  2. package/README.md +1 -2
  3. package/dist/core/agent-session.d.ts +9 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +109 -7
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/dynamic-prompt/verification.d.ts +31 -0
  8. package/dist/core/dynamic-prompt/verification.d.ts.map +1 -1
  9. package/dist/core/dynamic-prompt/verification.js +41 -0
  10. package/dist/core/dynamic-prompt/verification.js.map +1 -1
  11. package/dist/core/extensions/builtin/compaction/context-reduction.d.ts +97 -0
  12. package/dist/core/extensions/builtin/compaction/context-reduction.d.ts.map +1 -0
  13. package/dist/core/extensions/builtin/compaction/context-reduction.js +420 -0
  14. package/dist/core/extensions/builtin/compaction/context-reduction.js.map +1 -0
  15. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  16. package/dist/core/extensions/builtin/compaction/index.js +168 -31
  17. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  18. package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +197 -0
  19. package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -0
  20. package/dist/core/extensions/builtin/compaction/openai-remote.js +690 -0
  21. package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -0
  22. package/dist/core/extensions/builtin/compaction/prompts.d.ts +3 -3
  23. package/dist/core/extensions/builtin/compaction/prompts.d.ts.map +1 -1
  24. package/dist/core/extensions/builtin/compaction/prompts.js +0 -22
  25. package/dist/core/extensions/builtin/compaction/prompts.js.map +1 -1
  26. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts +4 -0
  27. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts.map +1 -0
  28. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js +48 -0
  29. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js.map +1 -0
  30. package/dist/core/extensions/builtin/compaction/speculative.d.ts +3 -1
  31. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  32. package/dist/core/extensions/builtin/compaction/speculative.js +82 -33
  33. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  34. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +8 -0
  35. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/compaction/todo-bridge.js +12 -6
  37. package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
  38. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/index.js +0 -2
  40. package/dist/core/extensions/builtin/index.js.map +1 -1
  41. package/dist/core/extensions/builtin/openai-web-search/index.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/openai-web-search/index.js +26 -1
  43. package/dist/core/extensions/builtin/openai-web-search/index.js.map +1 -1
  44. package/dist/core/extensions/builtin/permission-system/prompt.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/permission-system/prompt.js +0 -5
  46. package/dist/core/extensions/builtin/permission-system/prompt.js.map +1 -1
  47. package/dist/core/extensions/builtin/system-messages.d.ts +7 -7
  48. package/dist/core/extensions/builtin/system-messages.d.ts.map +1 -1
  49. package/dist/core/extensions/builtin/system-messages.js +10 -10
  50. package/dist/core/extensions/builtin/system-messages.js.map +1 -1
  51. package/dist/core/extensions/builtin/todotools/continuation/prompt.d.ts +1 -1
  52. package/dist/core/extensions/builtin/todotools/continuation/prompt.d.ts.map +1 -1
  53. package/dist/core/extensions/builtin/todotools/continuation/prompt.js +1 -1
  54. package/dist/core/extensions/builtin/todotools/continuation/prompt.js.map +1 -1
  55. package/dist/core/extensions/builtin/todotools/state.d.ts +1 -1
  56. package/dist/core/extensions/builtin/todotools/state.d.ts.map +1 -1
  57. package/dist/core/extensions/builtin/todotools/state.js +1 -1
  58. package/dist/core/extensions/builtin/todotools/state.js.map +1 -1
  59. package/dist/core/extensions/builtin/todotools/system-messages.d.ts +3 -3
  60. package/dist/core/extensions/builtin/todotools/system-messages.d.ts.map +1 -1
  61. package/dist/core/extensions/builtin/todotools/system-messages.js +6 -6
  62. package/dist/core/extensions/builtin/todotools/system-messages.js.map +1 -1
  63. package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts +1 -1
  64. package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts.map +1 -1
  65. package/dist/core/extensions/builtin/tool-pair-guard/index.js +8 -4
  66. package/dist/core/extensions/builtin/tool-pair-guard/index.js.map +1 -1
  67. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts +3 -0
  68. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts.map +1 -0
  69. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js +89 -0
  70. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js.map +1 -0
  71. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts +3 -0
  72. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts.map +1 -0
  73. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js +122 -0
  74. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js.map +1 -0
  75. package/dist/core/extensions/loader.d.ts.map +1 -1
  76. package/dist/core/extensions/loader.js +2 -0
  77. package/dist/core/extensions/loader.js.map +1 -1
  78. package/dist/core/extensions/runner.d.ts +3 -0
  79. package/dist/core/extensions/runner.d.ts.map +1 -1
  80. package/dist/core/extensions/runner.js +18 -0
  81. package/dist/core/extensions/runner.js.map +1 -1
  82. package/dist/core/extensions/types.d.ts +22 -0
  83. package/dist/core/extensions/types.d.ts.map +1 -1
  84. package/dist/core/extensions/types.js.map +1 -1
  85. package/dist/core/messages.d.ts +3 -3
  86. package/dist/core/messages.d.ts.map +1 -1
  87. package/dist/core/messages.js +5 -10
  88. package/dist/core/messages.js.map +1 -1
  89. package/dist/core/model-registry.d.ts.map +1 -1
  90. package/dist/core/model-registry.js +1 -0
  91. package/dist/core/model-registry.js.map +1 -1
  92. package/dist/core/sdk.d.ts +1 -1
  93. package/dist/core/sdk.d.ts.map +1 -1
  94. package/dist/core/sdk.js +7 -22
  95. package/dist/core/sdk.js.map +1 -1
  96. package/dist/core/session-manager.d.ts.map +1 -1
  97. package/dist/core/session-manager.js +1 -1
  98. package/dist/core/session-manager.js.map +1 -1
  99. package/dist/core/settings-manager.d.ts +0 -5
  100. package/dist/core/settings-manager.d.ts.map +1 -1
  101. package/dist/core/settings-manager.js.map +1 -1
  102. package/dist/core/thinking-levels.d.ts +6 -0
  103. package/dist/core/thinking-levels.d.ts.map +1 -0
  104. package/dist/core/thinking-levels.js +36 -0
  105. package/dist/core/thinking-levels.js.map +1 -0
  106. package/dist/core/tools/bash.d.ts.map +1 -1
  107. package/dist/core/tools/bash.js +15 -1
  108. package/dist/core/tools/bash.js.map +1 -1
  109. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  110. package/dist/modes/interactive/components/compaction-summary-message.js +20 -2
  111. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  112. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  113. package/dist/modes/interactive/components/keybinding-hints.js +3 -1
  114. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  115. package/dist/modes/interactive/interactive-mode.d.ts +8 -0
  116. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  117. package/dist/modes/interactive/interactive-mode.js +137 -49
  118. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  119. package/dist/modes/interactive/working-status.d.ts +15 -0
  120. package/dist/modes/interactive/working-status.d.ts.map +1 -0
  121. package/dist/modes/interactive/working-status.js +60 -0
  122. package/dist/modes/interactive/working-status.js.map +1 -0
  123. package/docs/extensions.md +0 -1
  124. package/docs/index.md +0 -1
  125. package/docs/sdk.md +0 -1
  126. package/docs/settings.md +1 -29
  127. package/docs/termux.md +2 -2
  128. package/docs/usage.md +1 -1
  129. package/examples/README.md +1 -1
  130. package/examples/extensions/README.md +0 -1
  131. package/examples/extensions/overlay-qa-tests.ts +1 -1
  132. package/package.json +4 -4
  133. package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts +0 -10
  134. package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts.map +0 -1
  135. package/dist/core/extensions/builtin/background-task/cancel-tool.js +0 -109
  136. package/dist/core/extensions/builtin/background-task/cancel-tool.js.map +0 -1
  137. package/dist/core/extensions/builtin/background-task/index.d.ts +0 -3
  138. package/dist/core/extensions/builtin/background-task/index.d.ts.map +0 -1
  139. package/dist/core/extensions/builtin/background-task/index.js +0 -207
  140. package/dist/core/extensions/builtin/background-task/index.js.map +0 -1
  141. package/dist/core/extensions/builtin/background-task/manager.d.ts +0 -17
  142. package/dist/core/extensions/builtin/background-task/manager.d.ts.map +0 -1
  143. package/dist/core/extensions/builtin/background-task/manager.js +0 -114
  144. package/dist/core/extensions/builtin/background-task/manager.js.map +0 -1
  145. package/dist/core/extensions/builtin/background-task/notification.d.ts +0 -22
  146. package/dist/core/extensions/builtin/background-task/notification.d.ts.map +0 -1
  147. package/dist/core/extensions/builtin/background-task/notification.js +0 -105
  148. package/dist/core/extensions/builtin/background-task/notification.js.map +0 -1
  149. package/dist/core/extensions/builtin/background-task/output-tool.d.ts +0 -11
  150. package/dist/core/extensions/builtin/background-task/output-tool.d.ts.map +0 -1
  151. package/dist/core/extensions/builtin/background-task/output-tool.js +0 -127
  152. package/dist/core/extensions/builtin/background-task/output-tool.js.map +0 -1
  153. package/dist/core/extensions/builtin/background-task/spawner.d.ts +0 -8
  154. package/dist/core/extensions/builtin/background-task/spawner.d.ts.map +0 -1
  155. package/dist/core/extensions/builtin/background-task/spawner.js +0 -207
  156. package/dist/core/extensions/builtin/background-task/spawner.js.map +0 -1
  157. package/dist/core/extensions/builtin/background-task/task-tool.d.ts +0 -20
  158. package/dist/core/extensions/builtin/background-task/task-tool.d.ts.map +0 -1
  159. package/dist/core/extensions/builtin/background-task/task-tool.js +0 -302
  160. package/dist/core/extensions/builtin/background-task/task-tool.js.map +0 -1
  161. package/dist/core/extensions/builtin/background-task/types.d.ts +0 -72
  162. package/dist/core/extensions/builtin/background-task/types.d.ts.map +0 -1
  163. package/dist/core/extensions/builtin/background-task/types.js +0 -32
  164. package/dist/core/extensions/builtin/background-task/types.js.map +0 -1
  165. package/docs/agents.md +0 -348
  166. package/examples/extensions/subagent/README.md +0 -172
  167. package/examples/extensions/subagent/agents/planner.md +0 -37
  168. package/examples/extensions/subagent/agents/reviewer.md +0 -35
  169. package/examples/extensions/subagent/agents/scout.md +0 -50
  170. package/examples/extensions/subagent/agents/worker.md +0 -24
  171. package/examples/extensions/subagent/agents.ts +0 -126
  172. package/examples/extensions/subagent/index.ts +0 -987
  173. package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
  174. package/examples/extensions/subagent/prompts/implement.md +0 -10
  175. 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, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, resetApiProviders, supportsMax, supportsXhigh, } from "@earendil-works/pi-ai";
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 = new AbortController();
1381
- this._emit({ type: "compaction_start", reason: options.reason });
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());
@@ -1635,14 +1671,20 @@ export class AgentSession {
1635
1671
  this._emit({ type: "compaction_start", reason: "pre_prompt" });
1636
1672
  this._compactionAbortController = new AbortController();
1637
1673
  try {
1638
- await this._executeCompaction({
1674
+ const execution = await this._executeCompaction({
1639
1675
  reason: "pre_prompt",
1640
1676
  willRetry: false,
1641
1677
  lastAssistantMessage,
1642
1678
  skipAbortedCheck,
1643
1679
  });
1680
+ if (!execution.accepted && isContextOverflow(lastAssistantMessage, this.model?.contextWindow ?? 0)) {
1681
+ this._overflowRecoveryAttempted = false;
1682
+ }
1644
1683
  }
1645
1684
  catch (error) {
1685
+ if (isContextOverflow(lastAssistantMessage, this.model?.contextWindow ?? 0)) {
1686
+ this._overflowRecoveryAttempted = false;
1687
+ }
1646
1688
  const errorMessage = error instanceof Error ? error.message : "compaction failed";
1647
1689
  const aborted = errorMessage === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
1648
1690
  this._emit({
@@ -1666,6 +1708,8 @@ export class AgentSession {
1666
1708
  this._autoCompactionAbortController = new AbortController();
1667
1709
  try {
1668
1710
  if (!this.model) {
1711
+ if (reason === "overflow")
1712
+ this._overflowRecoveryAttempted = false;
1669
1713
  this._emit({
1670
1714
  type: "compaction_end",
1671
1715
  reason,
@@ -1677,6 +1721,8 @@ export class AgentSession {
1677
1721
  }
1678
1722
  const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
1679
1723
  if (!authResult.ok || !authResult.apiKey) {
1724
+ if (reason === "overflow")
1725
+ this._overflowRecoveryAttempted = false;
1680
1726
  this._emit({
1681
1727
  type: "compaction_end",
1682
1728
  reason,
@@ -1688,6 +1734,8 @@ export class AgentSession {
1688
1734
  }
1689
1735
  const preparation = prepareCompaction(this.sessionManager.getBranch(), this.settingsManager.getCompactionSettings());
1690
1736
  if (!preparation) {
1737
+ if (reason === "overflow")
1738
+ this._overflowRecoveryAttempted = false;
1691
1739
  this._emit({
1692
1740
  type: "compaction_end",
1693
1741
  reason,
@@ -1699,6 +1747,8 @@ export class AgentSession {
1699
1747
  }
1700
1748
  const execution = await this._executeCompaction({ reason, willRetry });
1701
1749
  if (!execution.accepted) {
1750
+ if (reason === "overflow")
1751
+ this._overflowRecoveryAttempted = false;
1702
1752
  return;
1703
1753
  }
1704
1754
  if (willRetry) {
@@ -1721,6 +1771,8 @@ export class AgentSession {
1721
1771
  }
1722
1772
  }
1723
1773
  catch (error) {
1774
+ if (reason === "overflow")
1775
+ this._overflowRecoveryAttempted = false;
1724
1776
  const errorMessage = error instanceof Error ? error.message : "compaction failed";
1725
1777
  const aborted = errorMessage === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
1726
1778
  this._emit({
@@ -1943,6 +1995,9 @@ export class AgentSession {
1943
1995
  }
1944
1996
  })();
1945
1997
  },
1998
+ beginCompaction: (options) => this._beginExtensionCompactionFeedback(options.reason),
1999
+ updateCompaction: (options) => this._updateExtensionCompactionFeedback(options),
2000
+ endCompaction: (options) => this._endExtensionCompactionFeedback(options),
1946
2001
  getMessageRevision: () => this.getMessageRevision(),
1947
2002
  applyCompaction: (precomputed, options) => this.applyCompaction(precomputed, options),
1948
2003
  getSystemPrompt: () => this.systemPrompt,
@@ -2101,16 +2156,49 @@ export class AgentSession {
2101
2156
  * Context overflow errors are NOT retryable (handled by compaction instead).
2102
2157
  */
2103
2158
  _isRetryableError(message) {
2104
- if (message.stopReason !== "error" || !message.errorMessage)
2159
+ if (!message.errorMessage)
2105
2160
  return false;
2106
2161
  // Context overflow is handled by compaction, not retry
2107
2162
  const contextWindow = this.model?.contextWindow ?? 0;
2108
2163
  if (isContextOverflow(message, contextWindow))
2109
2164
  return false;
2110
2165
  const err = message.errorMessage;
2166
+ if (message.stopReason === "aborted") {
2167
+ return /timed? out|timeout/i.test(err);
2168
+ }
2169
+ if (message.stopReason !== "error")
2170
+ return false;
2111
2171
  // 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
2172
  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
2173
  }
2174
+ _getProviderRetryDelayMs(errorMessage) {
2175
+ const retryAfterMsMatch = errorMessage.match(/\bretry[-_ ]?after[-_ ]?ms\s*[:=]\s*(\d+(?:\.\d+)?)/i);
2176
+ if (retryAfterMsMatch) {
2177
+ const delayMs = Math.ceil(Number(retryAfterMsMatch[1]));
2178
+ return Number.isFinite(delayMs) && delayMs > 0 ? delayMs : undefined;
2179
+ }
2180
+ const retryAfterSecondsMatch = errorMessage.match(/\bretry[-_ ]?after\s*[:=]\s*(\d+(?:\.\d+)?)/i);
2181
+ if (retryAfterSecondsMatch) {
2182
+ const delayMs = Math.ceil(Number(retryAfterSecondsMatch[1]) * 1000);
2183
+ return Number.isFinite(delayMs) && delayMs > 0 ? delayMs : undefined;
2184
+ }
2185
+ 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);
2186
+ if (!retryInMatch) {
2187
+ return undefined;
2188
+ }
2189
+ const value = Number(retryInMatch[1]);
2190
+ if (!Number.isFinite(value) || value <= 0) {
2191
+ return undefined;
2192
+ }
2193
+ const unit = retryInMatch[2].toLowerCase();
2194
+ if (unit === "m" || unit.startsWith("min")) {
2195
+ return Math.ceil(value * 60_000);
2196
+ }
2197
+ if (unit.startsWith("s")) {
2198
+ return Math.ceil(value * 1000);
2199
+ }
2200
+ return Math.ceil(value);
2201
+ }
2114
2202
  /**
2115
2203
  * Handle retryable errors with exponential backoff.
2116
2204
  * @returns true if retry was initiated, false if max retries exceeded or disabled
@@ -2141,13 +2229,27 @@ export class AgentSession {
2141
2229
  this._resolveRetry(); // Resolve so waitForRetry() completes
2142
2230
  return false;
2143
2231
  }
2144
- const delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
2232
+ const errorMessage = message.errorMessage || "Unknown error";
2233
+ const providerDelayMs = this._getProviderRetryDelayMs(errorMessage);
2234
+ const maxRetryDelayMs = this.settingsManager.getProviderRetrySettings().maxRetryDelayMs;
2235
+ if (providerDelayMs !== undefined && providerDelayMs > maxRetryDelayMs) {
2236
+ this._emit({
2237
+ type: "auto_retry_end",
2238
+ success: false,
2239
+ attempt: this._retryAttempt,
2240
+ finalError: `Provider requested retry delay ${providerDelayMs}ms, exceeding configured maximum ${maxRetryDelayMs}ms`,
2241
+ });
2242
+ this._retryAttempt = 0;
2243
+ this._resolveRetry();
2244
+ return false;
2245
+ }
2246
+ const delayMs = providerDelayMs ?? settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
2145
2247
  this._emit({
2146
2248
  type: "auto_retry_start",
2147
2249
  attempt: this._retryAttempt,
2148
2250
  maxAttempts: settings.maxRetries,
2149
2251
  delayMs,
2150
- errorMessage: message.errorMessage || "Unknown error",
2252
+ errorMessage,
2151
2253
  });
2152
2254
  // Remove error message from agent state (keep in session for history)
2153
2255
  const messages = this.agent.state.messages;