@namzu/sdk 51.0.0 → 52.0.0

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 (352) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/dist/agents/QueryAgent.d.ts.map +1 -1
  3. package/dist/agents/QueryAgent.js +2 -0
  4. package/dist/agents/QueryAgent.js.map +1 -1
  5. package/dist/agents/SupervisorAgent.d.ts +1 -1
  6. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  7. package/dist/agents/SupervisorAgent.js.map +1 -1
  8. package/dist/agents/examples/SupervisorAgent.d.ts +42 -0
  9. package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
  10. package/dist/agents/examples/SupervisorAgent.js +80 -4
  11. package/dist/agents/examples/SupervisorAgent.js.map +1 -1
  12. package/dist/agents/index.d.ts +1 -1
  13. package/dist/agents/index.d.ts.map +1 -1
  14. package/dist/agents/index.js.map +1 -1
  15. package/dist/authorization/protected-paths.d.ts +36 -0
  16. package/dist/authorization/protected-paths.d.ts.map +1 -0
  17. package/dist/authorization/protected-paths.js +107 -0
  18. package/dist/authorization/protected-paths.js.map +1 -0
  19. package/dist/authorization/readonly-commands.d.ts +39 -0
  20. package/dist/authorization/readonly-commands.d.ts.map +1 -0
  21. package/dist/authorization/readonly-commands.js +797 -0
  22. package/dist/authorization/readonly-commands.js.map +1 -0
  23. package/dist/authorization/readonly-flags.d.ts +19 -0
  24. package/dist/authorization/readonly-flags.d.ts.map +1 -0
  25. package/dist/authorization/readonly-flags.js +178 -0
  26. package/dist/authorization/readonly-flags.js.map +1 -0
  27. package/dist/authorization/removal.d.ts +52 -0
  28. package/dist/authorization/removal.d.ts.map +1 -0
  29. package/dist/authorization/removal.js +283 -0
  30. package/dist/authorization/removal.js.map +1 -0
  31. package/dist/authorization/shell-paths.d.ts +66 -0
  32. package/dist/authorization/shell-paths.d.ts.map +1 -0
  33. package/dist/authorization/shell-paths.js +697 -0
  34. package/dist/authorization/shell-paths.js.map +1 -0
  35. package/dist/bridge/acp/update.d.ts.map +1 -1
  36. package/dist/bridge/acp/update.js +1 -0
  37. package/dist/bridge/acp/update.js.map +1 -1
  38. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  39. package/dist/bridge/sse/mapper.js +1 -0
  40. package/dist/bridge/sse/mapper.js.map +1 -1
  41. package/dist/compaction/context-window.d.ts +24 -0
  42. package/dist/compaction/context-window.d.ts.map +1 -1
  43. package/dist/compaction/context-window.js +34 -0
  44. package/dist/compaction/context-window.js.map +1 -1
  45. package/dist/compaction/manual.d.ts.map +1 -1
  46. package/dist/compaction/manual.js +10 -2
  47. package/dist/compaction/manual.js.map +1 -1
  48. package/dist/compaction/plan.d.ts +4 -0
  49. package/dist/compaction/plan.d.ts.map +1 -1
  50. package/dist/compaction/plan.js +6 -2
  51. package/dist/compaction/plan.js.map +1 -1
  52. package/dist/compaction/verifier.d.ts +11 -1
  53. package/dist/compaction/verifier.d.ts.map +1 -1
  54. package/dist/compaction/verifier.js +19 -7
  55. package/dist/compaction/verifier.js.map +1 -1
  56. package/dist/config/runtime.d.ts +55 -7
  57. package/dist/config/runtime.d.ts.map +1 -1
  58. package/dist/config/runtime.js +23 -2
  59. package/dist/config/runtime.js.map +1 -1
  60. package/dist/connector/web/guarded-fetch.d.ts.map +1 -1
  61. package/dist/connector/web/guarded-fetch.js +24 -0
  62. package/dist/connector/web/guarded-fetch.js.map +1 -1
  63. package/dist/connector/web/index.d.ts +1 -1
  64. package/dist/connector/web/index.d.ts.map +1 -1
  65. package/dist/connector/web/page.d.ts +59 -0
  66. package/dist/connector/web/page.d.ts.map +1 -0
  67. package/dist/connector/web/page.js +112 -0
  68. package/dist/connector/web/page.js.map +1 -0
  69. package/dist/connector/web/types.d.ts +47 -0
  70. package/dist/connector/web/types.d.ts.map +1 -1
  71. package/dist/connector/web/types.js.map +1 -1
  72. package/dist/constants/continuation.d.ts +8 -0
  73. package/dist/constants/continuation.d.ts.map +1 -1
  74. package/dist/constants/continuation.js +8 -0
  75. package/dist/constants/continuation.js.map +1 -1
  76. package/dist/constants/plugin/index.d.ts +1 -1
  77. package/dist/constants/plugin/index.d.ts.map +1 -1
  78. package/dist/constants/plugin/index.js +1 -1
  79. package/dist/constants/plugin/index.js.map +1 -1
  80. package/dist/manager/agent/lifecycle.d.ts +7 -0
  81. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  82. package/dist/manager/agent/lifecycle.js +11 -2
  83. package/dist/manager/agent/lifecycle.js.map +1 -1
  84. package/dist/manager/session/turn-recorder.d.ts.map +1 -1
  85. package/dist/manager/session/turn-recorder.js +4 -2
  86. package/dist/manager/session/turn-recorder.js.map +1 -1
  87. package/dist/plugin/index.d.ts +1 -1
  88. package/dist/plugin/index.d.ts.map +1 -1
  89. package/dist/plugin/index.js +1 -1
  90. package/dist/plugin/index.js.map +1 -1
  91. package/dist/plugin/lifecycle.d.ts +6 -0
  92. package/dist/plugin/lifecycle.d.ts.map +1 -1
  93. package/dist/plugin/lifecycle.js +98 -114
  94. package/dist/plugin/lifecycle.js.map +1 -1
  95. package/dist/plugin/shell-hook.d.ts +90 -22
  96. package/dist/plugin/shell-hook.d.ts.map +1 -1
  97. package/dist/plugin/shell-hook.js +434 -41
  98. package/dist/plugin/shell-hook.js.map +1 -1
  99. package/dist/provider/errors.d.ts +10 -0
  100. package/dist/provider/errors.d.ts.map +1 -1
  101. package/dist/provider/errors.js +16 -0
  102. package/dist/provider/errors.js.map +1 -1
  103. package/dist/provider/retry.d.ts +27 -0
  104. package/dist/provider/retry.d.ts.map +1 -1
  105. package/dist/provider/retry.js +19 -3
  106. package/dist/provider/retry.js.map +1 -1
  107. package/dist/public-runtime.d.ts +4 -1
  108. package/dist/public-runtime.d.ts.map +1 -1
  109. package/dist/public-runtime.js +4 -1
  110. package/dist/public-runtime.js.map +1 -1
  111. package/dist/public-types.d.ts +2 -2
  112. package/dist/public-types.d.ts.map +1 -1
  113. package/dist/runtime/jobs/registry.d.ts +21 -0
  114. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  115. package/dist/runtime/jobs/registry.js +15 -2
  116. package/dist/runtime/jobs/registry.js.map +1 -1
  117. package/dist/runtime/query/executor/tool-call-admission.d.ts +10 -0
  118. package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
  119. package/dist/runtime/query/executor/tool-call-admission.js +74 -13
  120. package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
  121. package/dist/runtime/query/executor.d.ts +41 -2
  122. package/dist/runtime/query/executor.d.ts.map +1 -1
  123. package/dist/runtime/query/executor.js +190 -6
  124. package/dist/runtime/query/executor.js.map +1 -1
  125. package/dist/runtime/query/finalize-turn.d.ts +6 -0
  126. package/dist/runtime/query/finalize-turn.d.ts.map +1 -1
  127. package/dist/runtime/query/finalize-turn.js +1 -1
  128. package/dist/runtime/query/finalize-turn.js.map +1 -1
  129. package/dist/runtime/query/index.d.ts +29 -0
  130. package/dist/runtime/query/index.d.ts.map +1 -1
  131. package/dist/runtime/query/index.js +15 -3
  132. package/dist/runtime/query/index.js.map +1 -1
  133. package/dist/runtime/query/iteration/index.d.ts +31 -0
  134. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  135. package/dist/runtime/query/iteration/index.js +216 -7
  136. package/dist/runtime/query/iteration/index.js.map +1 -1
  137. package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts +58 -0
  138. package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts.map +1 -0
  139. package/dist/runtime/query/iteration/phases/compaction-breaker.js +91 -0
  140. package/dist/runtime/query/iteration/phases/compaction-breaker.js.map +1 -0
  141. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  142. package/dist/runtime/query/iteration/phases/compaction.js +89 -7
  143. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  144. package/dist/runtime/query/iteration/phases/context.d.ts +10 -0
  145. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  146. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  147. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  148. package/dist/runtime/query/iteration/phases/tool-review.js +165 -2
  149. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  150. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  151. package/dist/runtime/query/iteration/stream-turn.js +24 -1
  152. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  153. package/dist/runtime/query/path-escalation.d.ts +36 -0
  154. package/dist/runtime/query/path-escalation.d.ts.map +1 -0
  155. package/dist/runtime/query/path-escalation.js +184 -0
  156. package/dist/runtime/query/path-escalation.js.map +1 -0
  157. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  158. package/dist/runtime/query/plugin-hooks.js +8 -0
  159. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  160. package/dist/runtime/query/reminders.d.ts +35 -0
  161. package/dist/runtime/query/reminders.d.ts.map +1 -0
  162. package/dist/runtime/query/reminders.js +7 -0
  163. package/dist/runtime/query/reminders.js.map +1 -0
  164. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  165. package/dist/runtime/query/resume-pending.js +26 -0
  166. package/dist/runtime/query/resume-pending.js.map +1 -1
  167. package/dist/runtime/query/review-policy.d.ts +26 -0
  168. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  169. package/dist/runtime/query/review-policy.js +79 -5
  170. package/dist/runtime/query/review-policy.js.map +1 -1
  171. package/dist/runtime/query/tool-output-budget.d.ts +46 -0
  172. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  173. package/dist/runtime/query/tool-output-budget.js +85 -1
  174. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  175. package/dist/runtime/query/tooling.d.ts +1 -0
  176. package/dist/runtime/query/tooling.d.ts.map +1 -1
  177. package/dist/runtime/query/tooling.js +5 -0
  178. package/dist/runtime/query/tooling.js.map +1 -1
  179. package/dist/session/paths.d.ts +5 -1
  180. package/dist/session/paths.d.ts.map +1 -1
  181. package/dist/session/paths.js +8 -0
  182. package/dist/session/paths.js.map +1 -1
  183. package/dist/store/memory/disk.d.ts.map +1 -1
  184. package/dist/store/memory/disk.js +2 -2
  185. package/dist/store/memory/disk.js.map +1 -1
  186. package/dist/store/memory/markdown.d.ts.map +1 -1
  187. package/dist/store/memory/markdown.js +2 -2
  188. package/dist/store/memory/markdown.js.map +1 -1
  189. package/dist/store/memory/naming.d.ts +9 -0
  190. package/dist/store/memory/naming.d.ts.map +1 -1
  191. package/dist/store/memory/naming.js +12 -0
  192. package/dist/store/memory/naming.js.map +1 -1
  193. package/dist/tools/builtins/bash.d.ts +30 -1
  194. package/dist/tools/builtins/bash.d.ts.map +1 -1
  195. package/dist/tools/builtins/bash.js +170 -26
  196. package/dist/tools/builtins/bash.js.map +1 -1
  197. package/dist/tools/builtins/content-fingerprint.d.ts +2 -0
  198. package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -1
  199. package/dist/tools/builtins/content-fingerprint.js +4 -0
  200. package/dist/tools/builtins/content-fingerprint.js.map +1 -1
  201. package/dist/tools/builtins/edit.d.ts.map +1 -1
  202. package/dist/tools/builtins/edit.js +60 -18
  203. package/dist/tools/builtins/edit.js.map +1 -1
  204. package/dist/tools/builtins/grep.d.ts +8 -1
  205. package/dist/tools/builtins/grep.d.ts.map +1 -1
  206. package/dist/tools/builtins/grep.js +152 -33
  207. package/dist/tools/builtins/grep.js.map +1 -1
  208. package/dist/tools/builtins/read-file.d.ts +1 -0
  209. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  210. package/dist/tools/builtins/read-file.js +44 -5
  211. package/dist/tools/builtins/read-file.js.map +1 -1
  212. package/dist/tools/builtins/read-render.d.ts +52 -0
  213. package/dist/tools/builtins/read-render.d.ts.map +1 -1
  214. package/dist/tools/builtins/read-render.js +143 -0
  215. package/dist/tools/builtins/read-render.js.map +1 -1
  216. package/dist/tools/builtins/web.d.ts +13 -2
  217. package/dist/tools/builtins/web.d.ts.map +1 -1
  218. package/dist/tools/builtins/web.js +225 -32
  219. package/dist/tools/builtins/web.js.map +1 -1
  220. package/dist/tools/coordinator/ask-user-question.d.ts +2 -0
  221. package/dist/tools/coordinator/ask-user-question.d.ts.map +1 -1
  222. package/dist/tools/coordinator/ask-user-question.js +256 -92
  223. package/dist/tools/coordinator/ask-user-question.js.map +1 -1
  224. package/dist/tools/coordinator/question-options.d.ts +1 -0
  225. package/dist/tools/coordinator/question-options.d.ts.map +1 -1
  226. package/dist/tools/coordinator/question-options.js +6 -1
  227. package/dist/tools/coordinator/question-options.js.map +1 -1
  228. package/dist/tools/defineTool.d.ts +4 -1
  229. package/dist/tools/defineTool.d.ts.map +1 -1
  230. package/dist/tools/defineTool.js +6 -1
  231. package/dist/tools/defineTool.js.map +1 -1
  232. package/dist/tools/paths.d.ts +6 -0
  233. package/dist/tools/paths.d.ts.map +1 -1
  234. package/dist/tools/paths.js +1 -1
  235. package/dist/tools/paths.js.map +1 -1
  236. package/dist/types/agent/query.d.ts +3 -0
  237. package/dist/types/agent/query.d.ts.map +1 -1
  238. package/dist/types/errors/catalog.js +1 -1
  239. package/dist/types/errors/catalog.js.map +1 -1
  240. package/dist/types/hitl/index.d.ts +104 -0
  241. package/dist/types/hitl/index.d.ts.map +1 -1
  242. package/dist/types/hitl/index.js.map +1 -1
  243. package/dist/types/message/index.d.ts +1 -1
  244. package/dist/types/message/index.d.ts.map +1 -1
  245. package/dist/types/message/index.js +2 -0
  246. package/dist/types/message/index.js.map +1 -1
  247. package/dist/types/plugin/index.d.ts +93 -19
  248. package/dist/types/plugin/index.d.ts.map +1 -1
  249. package/dist/types/plugin/index.js +3 -0
  250. package/dist/types/plugin/index.js.map +1 -1
  251. package/dist/types/provider/error.d.ts +6 -0
  252. package/dist/types/provider/error.d.ts.map +1 -1
  253. package/dist/types/provider/errors.d.ts +19 -0
  254. package/dist/types/provider/errors.d.ts.map +1 -1
  255. package/dist/types/provider/errors.js +39 -1
  256. package/dist/types/provider/errors.js.map +1 -1
  257. package/dist/types/provider/stream.d.ts +6 -0
  258. package/dist/types/provider/stream.d.ts.map +1 -1
  259. package/dist/types/session/events.d.ts +15 -2
  260. package/dist/types/session/events.d.ts.map +1 -1
  261. package/dist/types/session/events.js.map +1 -1
  262. package/dist/types/session/records.d.ts +9 -9
  263. package/dist/types/session/records.d.ts.map +1 -1
  264. package/dist/types/session/records.js +1 -0
  265. package/dist/types/session/records.js.map +1 -1
  266. package/dist/types/session/stop-reason.d.ts +5 -0
  267. package/dist/types/session/stop-reason.d.ts.map +1 -1
  268. package/dist/types/tool/index.d.ts +52 -0
  269. package/dist/types/tool/index.d.ts.map +1 -1
  270. package/dist/types/tool/index.js.map +1 -1
  271. package/dist/utils/backoff.d.ts +12 -0
  272. package/dist/utils/backoff.d.ts.map +1 -1
  273. package/dist/utils/backoff.js +15 -0
  274. package/dist/utils/backoff.js.map +1 -1
  275. package/package.json +4 -2
  276. package/src/agents/QueryAgent.ts +5 -1
  277. package/src/agents/SupervisorAgent.ts +1 -1
  278. package/src/agents/examples/SupervisorAgent.ts +217 -106
  279. package/src/agents/index.ts +1 -1
  280. package/src/authorization/protected-paths.ts +110 -0
  281. package/src/authorization/readonly-commands.ts +771 -0
  282. package/src/authorization/readonly-flags.ts +196 -0
  283. package/src/authorization/removal.ts +326 -0
  284. package/src/authorization/shell-paths.ts +927 -0
  285. package/src/bridge/acp/update.ts +1 -0
  286. package/src/bridge/sse/mapper.ts +1 -0
  287. package/src/compaction/context-window.ts +41 -0
  288. package/src/compaction/manual.ts +10 -2
  289. package/src/compaction/plan.ts +11 -2
  290. package/src/compaction/verifier.ts +28 -3
  291. package/src/config/runtime.ts +23 -2
  292. package/src/connector/web/guarded-fetch.ts +26 -0
  293. package/src/connector/web/index.ts +3 -0
  294. package/src/connector/web/page.ts +130 -0
  295. package/src/connector/web/types.ts +47 -0
  296. package/src/constants/continuation.ts +10 -0
  297. package/src/constants/plugin/index.ts +1 -1
  298. package/src/manager/agent/lifecycle.ts +12 -4
  299. package/src/manager/session/turn-recorder.ts +10 -2
  300. package/src/plugin/index.ts +1 -0
  301. package/src/plugin/lifecycle.ts +107 -119
  302. package/src/plugin/shell-hook.ts +477 -43
  303. package/src/provider/errors.ts +18 -0
  304. package/src/provider/retry.ts +53 -3
  305. package/src/public-runtime.ts +8 -0
  306. package/src/public-types.ts +4 -0
  307. package/src/runtime/jobs/registry.ts +39 -2
  308. package/src/runtime/query/executor/tool-call-admission.ts +79 -13
  309. package/src/runtime/query/executor.ts +242 -8
  310. package/src/runtime/query/finalize-turn.ts +7 -1
  311. package/src/runtime/query/index.ts +45 -3
  312. package/src/runtime/query/iteration/index.ts +251 -12
  313. package/src/runtime/query/iteration/phases/compaction-breaker.ts +106 -0
  314. package/src/runtime/query/iteration/phases/compaction.ts +99 -12
  315. package/src/runtime/query/iteration/phases/context.ts +11 -0
  316. package/src/runtime/query/iteration/phases/tool-review.ts +177 -2
  317. package/src/runtime/query/iteration/stream-turn.ts +24 -1
  318. package/src/runtime/query/path-escalation.ts +204 -0
  319. package/src/runtime/query/plugin-hooks.ts +8 -0
  320. package/src/runtime/query/reminders.ts +45 -0
  321. package/src/runtime/query/resume-pending.ts +27 -0
  322. package/src/runtime/query/review-policy.ts +106 -5
  323. package/src/runtime/query/tool-output-budget.ts +115 -1
  324. package/src/runtime/query/tooling.ts +6 -0
  325. package/src/session/paths.ts +11 -1
  326. package/src/store/memory/disk.ts +2 -1
  327. package/src/store/memory/markdown.ts +2 -1
  328. package/src/store/memory/naming.ts +13 -0
  329. package/src/tools/builtins/bash.ts +203 -34
  330. package/src/tools/builtins/content-fingerprint.ts +5 -0
  331. package/src/tools/builtins/edit.ts +69 -19
  332. package/src/tools/builtins/grep.ts +159 -38
  333. package/src/tools/builtins/read-file.ts +48 -5
  334. package/src/tools/builtins/read-render.ts +193 -0
  335. package/src/tools/builtins/web.ts +258 -33
  336. package/src/tools/coordinator/ask-user-question.ts +309 -103
  337. package/src/tools/coordinator/question-options.ts +8 -1
  338. package/src/tools/defineTool.ts +11 -2
  339. package/src/tools/paths.ts +1 -1
  340. package/src/types/agent/query.ts +3 -0
  341. package/src/types/errors/catalog.ts +1 -1
  342. package/src/types/hitl/index.ts +104 -0
  343. package/src/types/message/index.ts +2 -0
  344. package/src/types/plugin/index.ts +101 -18
  345. package/src/types/provider/error.ts +6 -0
  346. package/src/types/provider/errors.ts +49 -1
  347. package/src/types/provider/stream.ts +6 -0
  348. package/src/types/session/events.ts +15 -2
  349. package/src/types/session/records.ts +1 -0
  350. package/src/types/session/stop-reason.ts +5 -0
  351. package/src/types/tool/index.ts +53 -2
  352. package/src/utils/backoff.ts +21 -0
@@ -76,6 +76,8 @@ export class ProviderRequestError extends Error {
76
76
  * See {@link vendorDetail} for what is kept and what is scrubbed.
77
77
  */
78
78
  public readonly detail?: string
79
+ /** The provider's `x-should-retry` verdict, when it sent one; see {@link ProviderRequestErrorInit.shouldRetry}. */
80
+ public readonly shouldRetry?: boolean
79
81
 
80
82
  constructor(init: ProviderRequestErrorInit) {
81
83
  super(buildProviderErrorMessage(init))
@@ -87,6 +89,7 @@ export class ProviderRequestError extends Error {
87
89
  if (init.status !== undefined) this.status = init.status
88
90
  if (init.retryAfterMs !== undefined) this.retryAfterMs = init.retryAfterMs
89
91
  if (init.detail !== undefined) this.detail = init.detail
92
+ if (init.shouldRetry !== undefined) this.shouldRetry = init.shouldRetry
90
93
  }
91
94
  }
92
95
 
@@ -273,6 +276,15 @@ export function bodySaysContextOverflow(body: string | undefined | null): boolea
273
276
  * a negative delay is worse than none, because a caller would treat it as
274
277
  * "retry immediately" against a provider that just asked it to wait.
275
278
  */
279
+ /**
280
+ * `x-should-retry` is only read when it says `false`: that is the provider
281
+ * refusing a resend, and it outranks the status code. `true` changes nothing,
282
+ * because a retryable status is already retried.
283
+ */
284
+ export function parseShouldRetry(value: string | null | undefined): false | undefined {
285
+ return value?.trim().toLowerCase() === 'false' ? false : undefined
286
+ }
287
+
276
288
  export function parseRetryAfterMs(
277
289
  headerValue: string | null | undefined,
278
290
  now: number = Date.now(),
@@ -525,6 +537,7 @@ export function providerVendorError(input: {
525
537
  input.retryAfter ?? vendorRetryAfter(error),
526
538
  input.now ?? Date.now(),
527
539
  )
540
+ const shouldRetry = parseShouldRetry(vendorHeader(error, ['x-should-retry']))
528
541
  const fields = error as { type?: unknown; param?: unknown; requestID?: unknown } | null
529
542
  // A message that already carries its body (Anthropic's) has the fields; one that is only the
530
543
  // parsed sentence (OpenAI's) gets them from the SDK error's own properties.
@@ -544,6 +557,7 @@ export function providerVendorError(input: {
544
557
  ...(status !== undefined ? { status } : {}),
545
558
  ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
546
559
  ...(detail !== undefined ? { detail } : {}),
560
+ ...(shouldRetry !== undefined ? { shouldRetry } : {}),
547
561
  })
548
562
  }
549
563
 
@@ -605,6 +619,8 @@ export function providerHttpError(input: {
605
619
  readonly retryAfter?: string | null
606
620
  /** The response's request ID header, when the driver read one. */
607
621
  readonly requestId?: string | null
622
+ /** The response's `x-should-retry` header, when the driver read one. */
623
+ readonly shouldRetry?: string | null
608
624
  readonly now?: number
609
625
  }): ProviderRequestError {
610
626
  const kind = classifyProviderHttpStatus(input.status, input.body)
@@ -621,6 +637,7 @@ export function providerHttpError(input: {
621
637
  })
622
638
  : vendorDetail(input.body)
623
639
  const exactProviderCode = providerCode(input.body)
640
+ const shouldRetry = parseShouldRetry(input.shouldRetry)
624
641
  return new ProviderRequestError({
625
642
  kind,
626
643
  providerId: input.providerId,
@@ -628,5 +645,6 @@ export function providerHttpError(input: {
628
645
  status: input.status,
629
646
  ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
630
647
  ...(detail !== undefined ? { detail } : {}),
648
+ ...(shouldRetry !== undefined ? { shouldRetry } : {}),
631
649
  })
632
650
  }
@@ -1,7 +1,12 @@
1
1
  import { GENAI } from '../constants/telemetry/index.js'
2
2
  import { classifyProviderError, isAbortError } from '../types/provider/errors.js'
3
3
  import type { ChatCompletionParams, LLMProvider, StreamChunk } from '../types/provider/index.js'
4
- import { type BackoffPolicy, backoffWithJitter, sleep } from '../utils/backoff.js'
4
+ import {
5
+ type BackoffPolicy,
6
+ backoffProportional,
7
+ backoffWithJitter,
8
+ sleep,
9
+ } from '../utils/backoff.js'
5
10
  import type { Logger } from '../utils/logger.js'
6
11
  import { isProviderRequestError } from './errors.js'
7
12
 
@@ -31,6 +36,33 @@ export interface ProviderRetryConfig extends BackoffPolicy {
31
36
  * still slept exactly as instructed.
32
37
  */
33
38
  readonly maxRetryAfterMs: number
39
+ /**
40
+ * Shape of the random part of a backoff.
41
+ *
42
+ * `'full'` (the default) sleeps a uniform amount in `[0, backoff]`.
43
+ * `'proportional'` sleeps the backoff plus up to a quarter of it, so a step
44
+ * is never shorter than its exponential value.
45
+ */
46
+ readonly jitter?: 'full' | 'proportional'
47
+ /**
48
+ * What a server-named wait means.
49
+ *
50
+ * `'exact'` (the default) sleeps exactly what `Retry-After` said.
51
+ * `'floor'` sleeps the longer of that and the backoff for this attempt, so
52
+ * a server that says "1 second" on the seventh failure is still given the
53
+ * backoff's thirty. The ceiling above applies either way.
54
+ */
55
+ readonly retryAfter?: 'exact' | 'floor'
56
+ /**
57
+ * Also retry a stream that failed AFTER it produced text or reasoning.
58
+ *
59
+ * Off by default, because the decorator cannot un-emit: the consumer has
60
+ * already seen those deltas. When on, the retry notice carries
61
+ * `restart: true` and the consumer must discard what the failed attempt
62
+ * produced; the runtime does this itself. A stream that has begun a tool
63
+ * call is never restarted, because the call may already be underway.
64
+ */
65
+ readonly retryMidStream?: boolean
34
66
  }
35
67
 
36
68
  export const DEFAULT_PROVIDER_RETRY: ProviderRetryConfig = {
@@ -97,6 +129,9 @@ export function withProviderRetry(
97
129
  async function* chatStream(params: ChatCompletionParams): AsyncIterable<StreamChunk> {
98
130
  for (let attempt = 0; ; attempt++) {
99
131
  let produced = false
132
+ // A tool call or hosted tool began: past this point a restart could
133
+ // repeat work that is already underway, so it is never offered.
134
+ let acted = false
100
135
  try {
101
136
  for await (const chunk of provider.chatStream(params)) {
102
137
  // An error-only chunk is a failure report, not output: it
@@ -106,6 +141,9 @@ export function withProviderRetry(
106
141
  chunk.error !== undefined && !chunk.delta.content && !chunk.delta.toolCalls?.length
107
142
 
108
143
  if (!isErrorOnly) produced = true
144
+ if (chunk.delta.toolCalls?.length || chunk.delta.toolCallEnd || chunk.delta.hostedTool) {
145
+ acted = true
146
+ }
109
147
 
110
148
  if (isErrorOnly && !produced && attempt < config.maxRetries) {
111
149
  throw new Error(chunk.error)
@@ -132,7 +170,8 @@ export function withProviderRetry(
132
170
  const classified = classifyProviderError(err, provider.id)
133
171
  const exhausted = attempt >= config.maxRetries
134
172
 
135
- if (produced || !classified.retryable || exhausted) {
173
+ const restartable = produced && config.retryMidStream === true && !acted
174
+ if ((produced && !restartable) || !classified.retryable || exhausted) {
136
175
  log?.warn('Provider call failed', {
137
176
  [GENAI.SYSTEM]: provider.id,
138
177
  'namzu.provider.code': classified.code,
@@ -200,7 +239,16 @@ export function withProviderRetry(
200
239
  throw isProviderRequestError(err) ? err : classified
201
240
  }
202
241
 
203
- const delay = serverDirected ?? backoffWithJitter(attempt, config, random)
242
+ const backoff =
243
+ config.jitter === 'proportional'
244
+ ? backoffProportional(attempt, config, random)
245
+ : backoffWithJitter(attempt, config, random)
246
+ const delay =
247
+ serverDirected === undefined
248
+ ? backoff
249
+ : config.retryAfter === 'floor'
250
+ ? Math.max(serverDirected, backoff)
251
+ : serverDirected
204
252
 
205
253
  log?.warn('Provider call failed — retrying', {
206
254
  [GENAI.SYSTEM]: provider.id,
@@ -210,6 +258,7 @@ export function withProviderRetry(
210
258
  'namzu.provider.max_retries': config.maxRetries,
211
259
  'namzu.provider.delay_ms': delay,
212
260
  'namzu.provider.server_directed': serverDirected !== undefined,
261
+ 'namzu.provider.restart': restartable,
213
262
  })
214
263
 
215
264
  // Tell the consumer BEFORE sleeping. With the default policy a
@@ -231,6 +280,7 @@ export function withProviderRetry(
231
280
  code: classified.code,
232
281
  ...(classified.status !== undefined ? { status: classified.status } : {}),
233
282
  serverDirected: serverDirected !== undefined,
283
+ ...(restartable ? { restart: true } : {}),
234
284
  },
235
285
  }
236
286
 
@@ -318,6 +318,12 @@ export {
318
318
  formatSteeringNote,
319
319
  } from './runtime/query/steering.js'
320
320
  export type { SteeringChannel } from './runtime/query/steering.js'
321
+ // Hidden mid-conversation reminders a host feeds per model request (opt-in).
322
+ export { isReminderMessage } from './runtime/query/reminders.js'
323
+ export type {
324
+ ReminderContext,
325
+ ReminderSource,
326
+ } from './runtime/query/reminders.js'
321
327
  export {
322
328
  BidiSessionCloseTimeoutError,
323
329
  createMockBidiProvider,
@@ -628,6 +634,7 @@ export {
628
634
  runShellHook,
629
635
  SHELL_HOOK_EVENTS,
630
636
  SHELL_HOOKS_PLUGIN_ID,
637
+ shellHookIfMatches,
631
638
  shellHookMatches,
632
639
  shellHookVerdict,
633
640
  } from './plugin/index.js'
@@ -1505,6 +1512,7 @@ export {
1505
1512
  // consumer (`SpanProcessorLike`, then `CompactNowInput` and `CompactionResult`).
1506
1513
  // The gate is the reason this is a list rather than a fourth accident.
1507
1514
  export type { ResolvedContextWindow } from './compaction/context-window.js'
1515
+ export { resolveTriggerThreshold } from './compaction/context-window.js'
1508
1516
  export type { CompactRegionInput } from './compaction/manual.js'
1509
1517
  export type {
1510
1518
  CompactionVerificationOptions,
@@ -204,6 +204,7 @@ export type {
204
204
  Disposable,
205
205
  RunAgentOptions,
206
206
  RunAgentResult,
207
+ SupervisorResumeTarget,
207
208
  } from './agents/index.js'
208
209
 
209
210
  export type {
@@ -457,7 +458,10 @@ export type {
457
458
 
458
459
  export type {
459
460
  GuardedFetchConfig,
461
+ WebContentExtractor,
462
+ WebExtractRequest,
460
463
  WebFetchProvider,
464
+ WebFetchRedirectPolicy,
461
465
  WebFetchRefusalReason,
462
466
  WebFetchRequest,
463
467
  WebFetchResult,
@@ -99,6 +99,21 @@ export interface StartJobParams {
99
99
  * expect stdin.
100
100
  */
101
101
  readonly spawn?: () => JobProcess
102
+ /**
103
+ * Output the process already wrote before the registry took it over, in
104
+ * the order it was written. Used when a foreground command is moved to the
105
+ * background, so a later `read` starts with what the model was shown.
106
+ */
107
+ readonly initialOutput?: readonly {
108
+ readonly stream: 'stdout' | 'stderr'
109
+ readonly text: string
110
+ }[]
111
+ /**
112
+ * `spawn` returned a process on THIS host that the host shell started (a
113
+ * foreground command being moved to the background), so its bytes are
114
+ * decoded the way a foreground command's are, not as a Linux guest's.
115
+ */
116
+ readonly hostOutput?: boolean
102
117
  }
103
118
 
104
119
  export interface BackgroundJobRegistryConfig {
@@ -333,8 +348,12 @@ export class BackgroundJobRegistry {
333
348
  // Raw bytes, decoded here: a Windows console writes its OEM code page.
334
349
  // A process a sandbox started runs a Linux guest, so it is UTF-8.
335
350
  const decoders = {
336
- stdout: createHostOutputDecoder(params.spawn ? { platform: 'linux' } : {}),
337
- stderr: createHostOutputDecoder(params.spawn ? { platform: 'linux' } : {}),
351
+ stdout: createHostOutputDecoder(
352
+ params.spawn && !params.hostOutput ? { platform: 'linux' } : {},
353
+ ),
354
+ stderr: createHostOutputDecoder(
355
+ params.spawn && !params.hostOutput ? { platform: 'linux' } : {},
356
+ ),
338
357
  }
339
358
  let startError: string | undefined
340
359
  let settleStarted!: () => void
@@ -473,6 +492,7 @@ export class BackgroundJobRegistry {
473
492
  const text = typeof data === 'string' ? data : decoders[stream].write(data)
474
493
  if (text) append(text, stream)
475
494
  }
495
+ for (const seed of params.initialOutput ?? []) append(seed.text, seed.stream)
476
496
  child.stdout?.on('data', onData('stdout'))
477
497
  child.stderr?.on('data', onData('stderr'))
478
498
 
@@ -855,6 +875,23 @@ export function bindOwner(
855
875
  : {}),
856
876
  })
857
877
  },
878
+ // A foreground command that ran out of time, kept instead of killed.
879
+ // The same owner and cap as `start`; the process is the one already
880
+ // running, with what it has written so far.
881
+ adopt: (params: {
882
+ command: string
883
+ child: ReturnType<typeof spawn>
884
+ workingDirectory?: string
885
+ initialOutput?: StartJobParams['initialOutput']
886
+ }) =>
887
+ registry.start({
888
+ owner,
889
+ command: params.command,
890
+ workingDirectory: params.workingDirectory ?? defaults.workingDirectory ?? process.cwd(),
891
+ spawn: () => ({ child: params.child }),
892
+ hostOutput: true,
893
+ ...(params.initialOutput ? { initialOutput: params.initialOutput } : {}),
894
+ }),
858
895
  get: (id: string) => mine(id),
859
896
  awaitStarted: (id: string) => {
860
897
  mine(id)
@@ -2,7 +2,7 @@ import { GENAI, NAMZU } from '../../../constants/telemetry/index.js'
2
2
  import { callableToolNames, formatToolNames } from '../../../registry/tool/callable.js'
3
3
  import { renderToolSchema } from '../../../registry/tool/schema.js'
4
4
  import type { ToolCall, ToolInputError } from '../../../types/message/index.js'
5
- import type { PluginHookResult } from '../../../types/plugin/index.js'
5
+ import type { PluginHookPermission, PluginHookResult } from '../../../types/plugin/index.js'
6
6
  import type { ToolDefinition } from '../../../types/tool/index.js'
7
7
  import type { ToolCallRepair, ToolCallRepairReason } from '../../../types/tool/repair.js'
8
8
  import { awaitWithAbort } from '../../../utils/await-with-abort.js'
@@ -10,6 +10,7 @@ import { toErrorMessage } from '../../../utils/error.js'
10
10
  import type { Logger } from '../../../utils/logger.js'
11
11
  import type {
12
12
  EmitEvent,
13
+ PreToolHookNotes,
13
14
  PreToolHookOutcome,
14
15
  PreparedDirectCall,
15
16
  ToolExecutorConfig,
@@ -49,6 +50,11 @@ export interface ToolAdmissionHost {
49
50
  * step, which is the answer that sent a model round in a circle.
50
51
  */
51
52
  readonly allowedTools: readonly string[] | undefined
53
+ /**
54
+ * A hook asked for the turn to stop after the current step. Optional so a
55
+ * host that builds an admission by hand (a test) need not say anything.
56
+ */
57
+ readonly requestHalt?: (reason: string) => void
52
58
  }
53
59
 
54
60
  /**
@@ -89,7 +95,7 @@ export async function runPreToolHook(
89
95
  signal,
90
96
  )
91
97
  signal.throwIfAborted()
92
- return interpretPreToolResults(toolName, input, results)
98
+ return interpretPreToolResults(toolName, input, results, host.requestHalt)
93
99
  }
94
100
 
95
101
  export async function prepareDirectCall(
@@ -169,6 +175,7 @@ export async function prepareDirectCall(
169
175
  ...(providerInput && !truncationRepair && !preOutcome.modified && resolved.inputFailure
170
176
  ? { inputFailure: resolved.inputFailure }
171
177
  : {}),
178
+ ...hookNotesOf(preOutcome),
172
179
  }
173
180
  }
174
181
  return {
@@ -321,6 +328,20 @@ export async function prepareDirectCall(
321
328
  toolName,
322
329
  input: preparation.prepared.input,
323
330
  prepared: preparation.prepared,
331
+ ...hookNotesOf(preOutcome),
332
+ }
333
+ }
334
+
335
+ /** The hook answers a ready or legacy call carries forward, or nothing. */
336
+ function hookNotesOf(outcome: Extract<PreToolHookOutcome, { kind: 'continue' }>): {
337
+ hook?: PreToolHookNotes
338
+ } {
339
+ if (outcome.permission === undefined && outcome.context === undefined) return {}
340
+ return {
341
+ hook: {
342
+ ...(outcome.permission ? { permission: outcome.permission } : {}),
343
+ ...(outcome.context !== undefined ? { context: outcome.context } : {}),
344
+ },
324
345
  }
325
346
  }
326
347
 
@@ -328,29 +349,49 @@ function interpretPreToolResults(
328
349
  toolName: string,
329
350
  initialInput: unknown,
330
351
  results: readonly PluginHookResult[],
352
+ requestHalt?: (reason: string) => void,
331
353
  ): PreToolHookOutcome {
332
354
  let currentInput = initialInput
333
355
  let modified = false
356
+ let permission: PluginHookPermission | undefined
357
+ const contexts: string[] = []
358
+ /** `ask` outranks `allow`: the stricter answer is the one that stands. */
359
+ const takePermission = (next: PluginHookPermission | undefined) => {
360
+ if (next === undefined) return
361
+ if (permission === undefined || (permission.decision === 'allow' && next.decision === 'ask')) {
362
+ permission = next
363
+ }
364
+ }
365
+ const withContext = (text: string): string =>
366
+ contexts.length === 0 ? text : `${text}\n\n${hookNote(contexts)}`
367
+ // The hooks ran side by side on the original input, and their answers are
368
+ // combined here. The first refusal (or failure) in registration order is the
369
+ // answer, whatever the others said; of several rewrites the last wins;
370
+ // `ask` outranks `allow`; every context is kept; every request to stop is
371
+ // passed on.
372
+ let refusal: { kind: 'skip' | 'error'; text: string } | undefined
334
373
  for (const result of results) {
335
374
  switch (result.action) {
336
375
  case 'continue':
376
+ takePermission(result.permission)
377
+ if (result.context) contexts.push(result.context)
378
+ if (result.halt) requestHalt?.(result.halt.reason)
337
379
  continue
338
380
  case 'modify':
339
381
  currentInput = result.input
340
382
  modified = true
383
+ takePermission(result.permission)
384
+ if (result.context) contexts.push(result.context)
385
+ if (result.halt) requestHalt?.(result.halt.reason)
341
386
  continue
342
387
  case 'skip':
343
- return {
344
- kind: 'skip',
345
- input: currentInput,
346
- output: skippedToolResultText(toolName, result.reason),
347
- }
388
+ if (result.context) contexts.push(result.context)
389
+ if (result.halt) requestHalt?.(result.halt.reason)
390
+ refusal ??= { kind: 'skip', text: skippedToolResultText(toolName, result.reason) }
391
+ continue
348
392
  case 'error':
349
- return {
350
- kind: 'error',
351
- input: currentInput,
352
- output: `Error: ${result.message}`,
353
- }
393
+ refusal ??= { kind: 'error', text: `Error: ${result.message}` }
394
+ continue
354
395
  case 'retry':
355
396
  case 'annotate':
356
397
  // There is no result to replace yet. Rejecting loudly beats
@@ -367,9 +408,34 @@ function interpretPreToolResults(
367
408
  }
368
409
  }
369
410
  }
370
- return { kind: 'continue', input: currentInput, modified }
411
+ if (refusal) {
412
+ return {
413
+ kind: refusal.kind,
414
+ input: currentInput,
415
+ output: refusal.kind === 'skip' ? withContext(refusal.text) : refusal.text,
416
+ }
417
+ }
418
+ return {
419
+ kind: 'continue',
420
+ input: currentInput,
421
+ modified,
422
+ ...(permission ? { permission } : {}),
423
+ ...(contexts.length > 0 ? { context: contexts.join('\n') } : {}),
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Hook text, framed so the model reads it as what a configured hook said and
429
+ * not as something the tool returned.
430
+ */
431
+ export function hookNote(texts: readonly string[]): string {
432
+ const joined = texts.join('\n')
433
+ return `[Hook note]\n${joined.length > MAX_HOOK_NOTE_CHARS ? `${joined.slice(0, MAX_HOOK_NOTE_CHARS)}\n[truncated]` : joined}`
371
434
  }
372
435
 
436
+ /** A hook's text is one more thing for the model to read; it gets a bound. */
437
+ const MAX_HOOK_NOTE_CHARS = 8_000
438
+
373
439
  /**
374
440
  * Turn the call the model issued into a name and a parsed input, giving
375
441
  * a configured repairer one chance to fix it first.