@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
@@ -32,7 +32,7 @@ import {
32
32
  createToolMessage,
33
33
  } from '../../types/message/index.js'
34
34
  import type { PermissionMode } from '../../types/permission/index.js'
35
- import type { PluginHookResult } from '../../types/plugin/index.js'
35
+ import type { PluginHookPermission, PluginHookResult } from '../../types/plugin/index.js'
36
36
  import type { ChatCompletionResponse } from '../../types/provider/index.js'
37
37
  import type { Sandbox } from '../../types/sandbox/index.js'
38
38
  import type { AuditEventInput } from '../../types/session/audit.js'
@@ -65,6 +65,7 @@ import { type BackgroundJobRegistry, type JobProcess, bindOwner } from '../jobs/
65
65
  import {
66
66
  type ToolAdmissionHost,
67
67
  formatFailedToolOutput,
68
+ hookNote,
68
69
  isUnregistered,
69
70
  prepareDirectCall,
70
71
  runPreToolHook,
@@ -73,14 +74,17 @@ import {
73
74
  import { describeVisibleFileEvidence } from './file-evidence-context.js'
74
75
  import { seedObservationLedger } from './file-evidence-seed.js'
75
76
  import { DEFAULT_TOOL_RESULT_GUARDRAILS } from './guardrail-presets.js'
77
+ import { declaredWriteEscalation, shellEscalations } from './path-escalation.js'
76
78
  import type { ToolResultObservation } from './project-instructions.js'
77
79
  import { savedPresentation } from './saved-presentation.js'
78
80
  import { ToolCallBudget, assertMaxToolCalls } from './tool-call-budget.js'
79
81
  import {
80
82
  DEFAULT_MAX_TOOL_OUTPUT_CHARS,
83
+ DEFAULT_MAX_TOOL_OUTPUT_CHARS_PER_MESSAGE,
81
84
  type ToolOutputBudgetResult,
82
85
  applyToolOutputBudget,
83
86
  describeDroppedContent,
87
+ fitResultsToMessageBudget,
84
88
  measureContentBytes,
85
89
  } from './tool-output-budget.js'
86
90
 
@@ -94,6 +98,7 @@ export type PreparedDirectCall =
94
98
  readonly toolName: string
95
99
  readonly input: unknown
96
100
  readonly prepared: PreparedToolExecution
101
+ readonly hook?: PreToolHookNotes
97
102
  }
98
103
  | {
99
104
  readonly kind: 'legacy'
@@ -101,6 +106,7 @@ export type PreparedDirectCall =
101
106
  readonly toolName: string
102
107
  readonly input: unknown
103
108
  readonly inputFailure?: CompletedToolRecord['inputFailure']
109
+ readonly hook?: PreToolHookNotes
104
110
  }
105
111
  | {
106
112
  readonly kind: 'synthetic'
@@ -129,6 +135,8 @@ export interface PreparedToolBatch {
129
135
  readonly input: unknown
130
136
  /** What the prepared value reaches past the turn's boundary; see `ToolCallSummary.escalation`. */
131
137
  readonly escalation?: ToolCallEscalation
138
+ /** What a `pre_tool_use` hook asked for this call's approval; see `ToolCallSummary.hookPermission`. */
139
+ readonly hookPermission?: PluginHookPermission
132
140
  }[]
133
141
  }
134
142
 
@@ -137,6 +145,16 @@ interface OwnedPreparedToolBatch extends PreparedToolBatch {
137
145
  readonly escalations: ReadonlyMap<string, ToolCallEscalation>
138
146
  }
139
147
 
148
+ /**
149
+ * A nested call cannot open a review from inside the tool that issued it, so
150
+ * a hook that asked for a person to approve it can only be answered with a
151
+ * refusal. Silence would run the call the hook wanted a person to see.
152
+ */
153
+ function askedNestedMessage(toolName: string, outcome: PreToolHookOutcome): string | undefined {
154
+ if (outcome.kind !== 'continue' || outcome.permission?.decision !== 'ask') return undefined
155
+ return `Blocked: a hook asked that a person approve "${toolName}", and an approval cannot be requested from inside another tool. Call it directly.`
156
+ }
157
+
140
158
  function assertUniqueToolCallIds(toolCalls: readonly ToolCall[]): void {
141
159
  const seen = new Set<string>()
142
160
  for (const [index, toolCall] of toolCalls.entries()) {
@@ -420,6 +438,8 @@ export interface ToolExecutorConfig {
420
438
  * {@link DEFAULT_MAX_TOOL_OUTPUT_CHARS}; set `0` to disable.
421
439
  */
422
440
  maxToolOutputChars?: number
441
+ /** See QueryParams.maxToolOutputCharsPerMessage. */
442
+ maxToolOutputCharsPerMessage?: number
423
443
  /** See QueryParams.retainedToolPreviewChars; applies to the recorded host output. */
424
444
  retainedToolPreviewChars?: number
425
445
 
@@ -493,8 +513,16 @@ interface PostToolOverride {
493
513
  readonly content?: ToolResultContent
494
514
  }
495
515
 
516
+ /** What `pre_tool_use` hooks said about a call beyond running it or not. */
517
+ export interface PreToolHookNotes {
518
+ /** The strictest permission answer among the hooks: `ask` outranks `allow`. */
519
+ readonly permission?: PluginHookPermission
520
+ /** Hook text for the model, appended to what it reads of this call. */
521
+ readonly context?: string
522
+ }
523
+
496
524
  export type PreToolHookOutcome =
497
- | { kind: 'continue'; input: unknown; modified: boolean }
525
+ | ({ kind: 'continue'; input: unknown; modified: boolean } & PreToolHookNotes)
498
526
  | { kind: 'skip'; input: unknown; output: string }
499
527
  | { kind: 'error'; input: unknown; output: string }
500
528
 
@@ -1003,11 +1031,80 @@ export class ToolExecutor {
1003
1031
  tool.sandboxEscapeArgument !== undefined &&
1004
1032
  input[tool.sandboxEscapeArgument] === true
1005
1033
  const unknownProgram = this.unknownProgramOf(tool, input, sandboxed)
1006
- if (!outsidePaths && !sandboxEscape && unknownProgram === undefined) return undefined
1034
+ const reaches = await this.pathEscalationsOf(tool, input, sandboxed)
1035
+ if (reaches.outsidePaths.length > 0) {
1036
+ outsidePaths = [...new Set([...(outsidePaths ?? []), ...reaches.outsidePaths])]
1037
+ }
1038
+ const protectedPaths = reaches.protectedPaths
1039
+ const removal = reaches.dangerousRemoval
1040
+ if (
1041
+ !outsidePaths &&
1042
+ !sandboxEscape &&
1043
+ unknownProgram === undefined &&
1044
+ protectedPaths.length === 0 &&
1045
+ removal === undefined
1046
+ ) {
1047
+ return undefined
1048
+ }
1007
1049
  return {
1008
1050
  ...(outsidePaths ? { outsidePaths } : {}),
1009
1051
  ...(sandboxEscape ? { sandboxEscape: true as const } : {}),
1010
1052
  ...(unknownProgram !== undefined ? { unknownProgram } : {}),
1053
+ ...(protectedPaths.length > 0 ? { protectedPaths } : {}),
1054
+ ...(removal !== undefined ? { dangerousRemoval: removal } : {}),
1055
+ }
1056
+ }
1057
+
1058
+ /**
1059
+ * What the call's own arguments write or remove that no mode may approve in
1060
+ * advance, and, for a shell line, the paths outside the roots it names.
1061
+ *
1062
+ * The protected-path and removal floors hold whether or not the turn reviews
1063
+ * outside paths and whether or not it is sandboxed: they are about what the
1064
+ * write plants and what the removal destroys, not about where the turn is
1065
+ * allowed to look. The outside-path half follows `outsideRootAccess`, as the
1066
+ * file tools' own does.
1067
+ */
1068
+ private async pathEscalationsOf(
1069
+ tool: Pick<
1070
+ ToolDefinition,
1071
+ 'pathArgument' | 'commandArgument' | 'commandDialect' | 'isReadOnly'
1072
+ >,
1073
+ input: Record<string, unknown>,
1074
+ sandboxed: boolean,
1075
+ ): Promise<{
1076
+ outsidePaths: readonly string[]
1077
+ protectedPaths: readonly string[]
1078
+ dangerousRemoval?: string
1079
+ }> {
1080
+ const roots = toolRoots(this.config)
1081
+ const protectedPaths: string[] = []
1082
+ let outsidePaths: readonly string[] = []
1083
+ let removal: string | undefined
1084
+ if (tool.pathArgument !== undefined && tool.isReadOnly?.(input) !== true) {
1085
+ const value = input[tool.pathArgument]
1086
+ if (typeof value === 'string') {
1087
+ const hit = await declaredWriteEscalation(roots, value)
1088
+ if (hit !== undefined) protectedPaths.push(hit)
1089
+ }
1090
+ }
1091
+ if (tool.commandArgument !== undefined) {
1092
+ const line = input[tool.commandArgument]
1093
+ if (typeof line === 'string') {
1094
+ const dialect = tool.commandDialect?.({ sandboxed }) ?? 'sh'
1095
+ const found = await shellEscalations(line, dialect, {
1096
+ roots,
1097
+ reviewOutside: this.config.outsideRootAccess === 'review' && !sandboxed,
1098
+ })
1099
+ protectedPaths.push(...found.protectedPaths)
1100
+ outsidePaths = found.outsidePaths
1101
+ removal = found.dangerousRemoval
1102
+ }
1103
+ }
1104
+ return {
1105
+ outsidePaths,
1106
+ protectedPaths: [...new Set(protectedPaths)],
1107
+ ...(removal !== undefined ? { dangerousRemoval: removal } : {}),
1011
1108
  }
1012
1109
  }
1013
1110
 
@@ -1022,7 +1119,10 @@ export class ToolExecutor {
1022
1119
  * outside one.
1023
1120
  */
1024
1121
  private unknownProgramOf(
1025
- tool: { commandArgument?: string; commandDialect?: ToolDefinition['commandDialect'] },
1122
+ tool: {
1123
+ commandArgument?: string
1124
+ commandDialect?: ToolDefinition['commandDialect']
1125
+ },
1026
1126
  input: Record<string, unknown>,
1027
1127
  sandboxed: boolean,
1028
1128
  ): string | undefined {
@@ -1069,11 +1169,13 @@ export class ToolExecutor {
1069
1169
  )
1070
1170
  .map((call) => {
1071
1171
  const escalation = escalations.get(call.toolCall.id)
1172
+ const hookPermission = call.hook?.permission
1072
1173
  return {
1073
1174
  id: call.toolCall.id,
1074
1175
  name: call.toolName,
1075
1176
  input: call.input,
1076
1177
  ...(escalation ? { escalation } : {}),
1178
+ ...(hookPermission ? { hookPermission } : {}),
1077
1179
  }
1078
1180
  })
1079
1181
  const batch: OwnedPreparedToolBatch = Object.freeze({
@@ -1327,6 +1429,8 @@ export class ToolExecutor {
1327
1429
  })
1328
1430
  }
1329
1431
 
1432
+ this.fitBatchToMessageBudget(results)
1433
+
1330
1434
  // isError and rich content were computed and then discarded here: the
1331
1435
  // tuple narrowed to {toolCallId, output} BEFORE the message was built,
1332
1436
  // so the failure signal and any image block were structurally lost at
@@ -1338,6 +1442,51 @@ export class ToolExecutor {
1338
1442
  return { messages, results, observations }
1339
1443
  }
1340
1444
 
1445
+ /**
1446
+ * Hold the batch's combined result text under the per-message cap.
1447
+ *
1448
+ * Runs once, on the settled batch and before the results become history
1449
+ * messages, so what it writes is what every later request replays.
1450
+ */
1451
+ private fitBatchToMessageBudget(results: ToolCallOutcome[]): void {
1452
+ const maxChars =
1453
+ this.config.maxToolOutputCharsPerMessage ?? DEFAULT_MAX_TOOL_OUTPUT_CHARS_PER_MESSAGE
1454
+ const replacements = fitResultsToMessageBudget(
1455
+ results.map((r) => ({
1456
+ toolCallId: r.toolCallId,
1457
+ toolName: r.toolName,
1458
+ output: r.output,
1459
+ // A result carrying rich content or a structured-output copy is
1460
+ // not text the model reads alone, and a self-limiting tool has
1461
+ // already decided its own size.
1462
+ replaceable:
1463
+ r.content === undefined &&
1464
+ r.structuredResultJson === undefined &&
1465
+ this.config.tools.get(r.toolName)?.selfLimitingOutput !== true,
1466
+ })),
1467
+ {
1468
+ maxChars,
1469
+ spillDir: this.outputDirectory(),
1470
+ onError: (message) =>
1471
+ this.log.warn('Failed to retain a tool output replaced for the message budget', {
1472
+ [NAMZU.TURN_ID]: this.config.turnId,
1473
+ 'exception.message': message,
1474
+ }),
1475
+ },
1476
+ )
1477
+ if (replacements.size === 0) return
1478
+ for (const [i, r] of results.entries()) {
1479
+ const replacement = replacements.get(r.toolCallId)
1480
+ if (replacement === undefined) continue
1481
+ results[i] = { ...r, output: replacement.output }
1482
+ }
1483
+ this.log.warn("Tool results exceeded the message's combined budget", {
1484
+ [NAMZU.TURN_ID]: this.config.turnId,
1485
+ 'namzu.runtime.replaced_count': replacements.size,
1486
+ 'namzu.runtime.message_budget_chars': maxChars,
1487
+ })
1488
+ }
1489
+
1341
1490
  /**
1342
1491
  * Run a tool on behalf of another tool, and put it on the record.
1343
1492
  *
@@ -1802,8 +1951,10 @@ export class ToolExecutor {
1802
1951
  let input: unknown
1803
1952
  let prepared: PreparedToolExecution | undefined
1804
1953
  let inputFailure: ToolCallOutcome['inputFailure']
1954
+ let preparedHookContext: string | undefined
1805
1955
 
1806
1956
  if (preparedCall?.kind === 'ready' || preparedCall?.kind === 'legacy') {
1957
+ preparedHookContext = preparedCall.hook?.context
1807
1958
  input = preparedCall.input
1808
1959
  prepared = preparedCall.kind === 'ready' ? preparedCall.prepared : undefined
1809
1960
  if (preparedCall.kind === 'legacy') inputFailure = preparedCall.inputFailure
@@ -1824,6 +1975,7 @@ export class ToolExecutor {
1824
1975
  if (admitted.kind === 'synthetic') return this.recordSyntheticPreparation(admitted)
1825
1976
  toolName = admitted.toolName
1826
1977
  input = admitted.input
1978
+ preparedHookContext = admitted.hook?.context
1827
1979
  prepared = admitted.kind === 'ready' ? admitted.prepared : undefined
1828
1980
  if (admitted.kind === 'legacy') inputFailure = admitted.inputFailure
1829
1981
  }
@@ -2029,7 +2181,11 @@ export class ToolExecutor {
2029
2181
  ]
2030
2182
  }
2031
2183
  }
2032
- const maxToolOutputChars = this.config.maxToolOutputChars ?? DEFAULT_MAX_TOOL_OUTPUT_CHARS
2184
+ // A tool that bounds its own output is exempt from the DEFAULT per-result
2185
+ // cap only; a host that set the cap explicitly still gets it.
2186
+ const maxToolOutputChars =
2187
+ this.config.maxToolOutputChars ??
2188
+ (executedDefinition?.selfLimitingOutput === true ? 0 : DEFAULT_MAX_TOOL_OUTPUT_CHARS)
2033
2189
  const sourceOutput = output
2034
2190
  // This owner-bound channel follows the selected receipt after both result
2035
2191
  // screening and post-tool replacement. ToolResult.data and raw input can
@@ -2085,13 +2241,26 @@ export class ToolExecutor {
2085
2241
  })
2086
2242
  }
2087
2243
  output = budgeted.output
2088
- const modelContent =
2244
+ let modelContent =
2089
2245
  selectedContent === undefined
2090
2246
  ? undefined
2091
2247
  : this.budgetContent(selectedContent, toolName, toolCall.id, {
2092
2248
  sourceOutput,
2093
2249
  budgeted,
2094
2250
  })
2251
+ // What hooks said about this call rides with its result, in the model's
2252
+ // receipt and the host's alike, framed as a hook's words. Added after
2253
+ // the output budget so a bounded result is never trimmed to make room
2254
+ // for it; the note has its own bound (`hookNote`).
2255
+ const hookTexts = [preparedHookContext, post.context].filter(
2256
+ (text): text is string => text !== undefined && text.length > 0,
2257
+ )
2258
+ if (hookTexts.length > 0) {
2259
+ const note = hookNote(hookTexts)
2260
+ output = `${output}\n\n${note}`
2261
+ if (typeof modelContent === 'string') modelContent = `${modelContent}\n\n${note}`
2262
+ else if (modelContent) modelContent = [...modelContent, { type: 'text', text: note }]
2263
+ }
2095
2264
 
2096
2265
  // A failed call, or an override that says the call failed. A `replace`
2097
2266
  // says the opposite, and reading it as a failure is what made redaction
@@ -2438,9 +2607,25 @@ export class ToolExecutor {
2438
2607
  emitEvent: this.emitEvent,
2439
2608
  log: this.log,
2440
2609
  allowedTools: this.effectiveAllowedTools(),
2610
+ requestHalt: (reason) => this.requestHalt(reason),
2441
2611
  }
2442
2612
  }
2443
2613
 
2614
+ /** Why a hook asked for the turn to stop, until the iteration loop reads it. */
2615
+ private haltReason: string | undefined
2616
+
2617
+ /** The first request wins: a later hook does not rewrite why the turn stopped. */
2618
+ requestHalt(reason: string): void {
2619
+ this.haltReason ??= reason
2620
+ }
2621
+
2622
+ /** Read and clear a hook's request to stop the turn. */
2623
+ takeHalt(): string | undefined {
2624
+ const reason = this.haltReason
2625
+ this.haltReason = undefined
2626
+ return reason
2627
+ }
2628
+
2444
2629
  private async prepareNestedCall(
2445
2630
  toolName: string,
2446
2631
  input: unknown,
@@ -2468,6 +2653,14 @@ export class ToolExecutor {
2468
2653
  ...(preOutcome.kind === 'skip' ? { skipped: true as const } : {}),
2469
2654
  }
2470
2655
  }
2656
+ const nestedAsk = askedNestedMessage(toolName, preOutcome)
2657
+ if (nestedAsk)
2658
+ return {
2659
+ kind: 'synthetic',
2660
+ input: preOutcome.input,
2661
+ message: nestedAsk,
2662
+ isError: true,
2663
+ }
2471
2664
  return { kind: 'legacy', input: preOutcome.input }
2472
2665
  }
2473
2666
 
@@ -2513,6 +2706,15 @@ export class ToolExecutor {
2513
2706
  ...(preOutcome.kind === 'skip' ? { skipped: true as const } : {}),
2514
2707
  }
2515
2708
  }
2709
+ const nestedAsk = askedNestedMessage(toolName, preOutcome)
2710
+ if (nestedAsk) {
2711
+ return {
2712
+ kind: 'synthetic',
2713
+ input: preOutcome.input,
2714
+ message: nestedAsk,
2715
+ isError: true,
2716
+ }
2717
+ }
2516
2718
  if (!preOutcome.modified) {
2517
2719
  return {
2518
2720
  kind: 'ready',
@@ -2571,12 +2773,17 @@ export class ToolExecutor {
2571
2773
  /**
2572
2774
  * @returns `override` — text replacing the tool's output, or `null`.
2573
2775
  * `retry` — the hook asked for the tool to run again.
2776
+ * `context` — what the hooks want the model to read beside the result.
2574
2777
  */
2575
2778
  private async runPostToolHook(
2576
2779
  toolName: string,
2577
2780
  input: unknown,
2578
2781
  toolResult: ToolResult,
2579
- ): Promise<{ override: PostToolOverride | null; retry: boolean }> {
2782
+ ): Promise<{
2783
+ override: PostToolOverride | null
2784
+ retry: boolean
2785
+ context?: string
2786
+ }> {
2580
2787
  if (!this.config.pluginManager) return { override: null, retry: false }
2581
2788
  let results: PluginHookResult[]
2582
2789
  try {
@@ -2592,6 +2799,26 @@ export class ToolExecutor {
2592
2799
  },
2593
2800
  this.emitEvent,
2594
2801
  )
2802
+ // A failed call is announced a second time, by name, so a hook that
2803
+ // only cares about failures need not read every result. After
2804
+ // `post_tool_use`, so the existing hooks see exactly what they saw.
2805
+ if (!toolResult.success) {
2806
+ results = [
2807
+ ...results,
2808
+ ...(await this.config.pluginManager.executeHooks(
2809
+ 'post_tool_use_failure',
2810
+ {
2811
+ sessionId: this.config.sessionId,
2812
+ turnId: this.config.turnId,
2813
+ toolName,
2814
+ toolInput: input,
2815
+ toolResult,
2816
+ signal: this.config.abortSignal,
2817
+ },
2818
+ this.emitEvent,
2819
+ )),
2820
+ ]
2821
+ }
2595
2822
  } catch (error) {
2596
2823
  if (!this.config.abortSignal.aborted) throw error
2597
2824
  // The tool has already returned. Cancellation of a later redaction
@@ -2608,9 +2835,12 @@ export class ToolExecutor {
2608
2835
  }
2609
2836
  let override: PostToolOverride | null = null
2610
2837
  let retry = false
2838
+ const contexts: string[] = []
2611
2839
  for (const result of results) {
2612
2840
  switch (result.action) {
2613
2841
  case 'continue':
2842
+ if (result.context) contexts.push(result.context)
2843
+ if (result.halt) this.requestHalt(result.halt.reason)
2614
2844
  continue
2615
2845
  case 'error':
2616
2846
  override = { output: `Error: ${result.message}`, isError: true }
@@ -2646,7 +2876,11 @@ export class ToolExecutor {
2646
2876
  }
2647
2877
  }
2648
2878
  }
2649
- return { override, retry }
2879
+ return {
2880
+ override,
2881
+ retry,
2882
+ ...(contexts.length > 0 ? { context: contexts.join('\n') } : {}),
2883
+ }
2650
2884
  }
2651
2885
 
2652
2886
  /**
@@ -53,6 +53,12 @@ export interface TurnFinalization {
53
53
  * immediately before the record is written.
54
54
  */
55
55
  readonly takeSteps: () => readonly StepResult[]
56
+ /**
57
+ * Whether the loop already fired `turn_end` (and `subagent_stop`) when the
58
+ * model finished, so a hook could keep the turn going. Fired there, it is
59
+ * not fired again here.
60
+ */
61
+ readonly turnEndHooksFired?: () => boolean
56
62
  readonly workingStateManager: WorkingStateManager | undefined
57
63
  readonly resultAssembler: ResultAssembler
58
64
  readonly rootSpan: Span
@@ -71,7 +77,7 @@ export async function* finalizeTurn(
71
77
  rootSpan,
72
78
  } = finalization
73
79
 
74
- if (params.pluginManager) {
80
+ if (params.pluginManager && finalization.turnEndHooksFired?.() !== true) {
75
81
  const hookResults = await params.pluginManager.executeHooks(
76
82
  'turn_end',
77
83
  { sessionId: ctx.sessionId, turnId: ctx.turnId, signal: ctx.abortController.signal },
@@ -331,6 +331,17 @@ export interface QueryParams {
331
331
  maxToolConcurrency?: number
332
332
  /** Per-turn cumulative tool attempt limit, including nested calls and retries. Unset is unlimited. Re-supply on resume; durable reservations are never refunded. */
333
333
  maxToolCalls?: number
334
+ /**
335
+ * How many times in a row the loop nudges the model to carry on after a
336
+ * reply was cut off at its output limit, before the turn stops with an
337
+ * error naming the limit. The count restarts after any call that finishes
338
+ * on its own.
339
+ *
340
+ * Unset keeps the earlier behaviour: nudge every time, bounded only by
341
+ * `maxIterations`. Opt-in because a cap is a stop a host did not have
342
+ * before; `0` stops at the first cut-off.
343
+ */
344
+ maxOutputContinuations?: number
334
345
 
335
346
  /**
336
347
  * Model-visible size cap for a single tool result. Over-budget output is
@@ -339,6 +350,18 @@ export interface QueryParams {
339
350
  * agent decides the rest is worth re-reading. Set `0` to disable.
340
351
  */
341
352
  maxToolOutputChars?: number
353
+ /**
354
+ * Cap on the COMBINED model-visible text of every tool result one assistant
355
+ * message produced. Defaults to {@link DEFAULT_MAX_TOOL_OUTPUT_CHARS_PER_MESSAGE}
356
+ * (200,000 characters); `0` disables it. When a batch exceeds it, the
357
+ * largest results are replaced, largest first, by a short preview that
358
+ * names where the full text was kept, until the batch fits. The
359
+ * replacement is written into the result before it reaches the history, so
360
+ * it never changes afterwards and the prompt-cache prefix stays stable.
361
+ * Tools that bound their own output (`selfLimitingOutput`) are never
362
+ * replaced.
363
+ */
364
+ maxToolOutputCharsPerMessage?: number
342
365
  /**
343
366
  * Screens to run against every tool result. The turn builds its manager
344
367
  * from `toolsets` and gives it this policy.
@@ -726,6 +749,13 @@ export interface QueryParams {
726
749
  * started. See `BaseAgentConfig.inboundMessages` for what it closes.
727
750
  */
728
751
  inboundMessages?: () => import('../../types/message/index.js').Message[]
752
+ /**
753
+ * Hidden reminders a host feeds into the conversation, asked for before
754
+ * every model request of the turn. Opt-in: omitted, a turn carries none.
755
+ * See {@link ReminderSource}.
756
+ */
757
+ reminders?: import('./reminders.js').ReminderSource
758
+
729
759
  /**
730
760
  * Wake a background-task hold when operator input is available, without draining it.
731
761
  * Resolve immediately if input is already pending. Otherwise wait for its arrival;
@@ -1407,6 +1437,11 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
1407
1437
  ...(params.maxToolOutputChars !== undefined
1408
1438
  ? { maxToolOutputChars: params.maxToolOutputChars }
1409
1439
  : {}),
1440
+ ...(params.maxToolOutputCharsPerMessage !== undefined
1441
+ ? {
1442
+ maxToolOutputCharsPerMessage: params.maxToolOutputCharsPerMessage,
1443
+ }
1444
+ : {}),
1410
1445
  ...(params.toolResultGuardrails !== undefined
1411
1446
  ? { toolResultGuardrails: params.toolResultGuardrails }
1412
1447
  : {}),
@@ -1474,9 +1509,9 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
1474
1509
  // Normalised once, defaults applied. A host that passes a partial
1475
1510
  // object — a strategy and a window, nothing else — used to reach the
1476
1511
  // phase with `triggerThreshold` undefined, and `usage < undefined` is
1477
- // false: the pass ran on every iteration and the salience strategy fell
1478
- // through to the stale-result clearing it exists to replace. The eval
1479
- // suite that passed exactly that object found it.
1512
+ // false: the pass ran on every iteration. An absent threshold now means
1513
+ // the derived trigger (`resolveTriggerThreshold`), resolved where it is
1514
+ // compared.
1480
1515
  const compactionConfig = params.compactionConfig
1481
1516
  ? CompactionConfigSchema.parse(params.compactionConfig)
1482
1517
  : undefined
@@ -1635,7 +1670,11 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
1635
1670
  // would leak exactly that way.
1636
1671
  ...(params.repeatCallAdvisory === false ? {} : { repeatCalls: new RepeatCallTracker() }),
1637
1672
  compactionConfig,
1673
+ ...(params.maxOutputContinuations !== undefined
1674
+ ? { maxOutputContinuations: params.maxOutputContinuations }
1675
+ : {}),
1638
1676
  ...(params.inboundMessages ? { inboundMessages: params.inboundMessages } : {}),
1677
+ ...(params.reminders ? { reminders: params.reminders } : {}),
1639
1678
  ...(params.durableInbound ? { durableInbound: params.durableInbound } : {}),
1640
1679
  ...(params.resumeFromCheckpoint ? { resumedInput: queuedForThisRun } : {}),
1641
1680
  ...(params.waitForInbound ? { waitForInbound: params.waitForInbound } : {}),
@@ -1666,6 +1705,8 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
1666
1705
  agentBus: params.agentBus,
1667
1706
  verificationGate,
1668
1707
  pluginManager: params.pluginManager,
1708
+ ...(params.parentSessionId !== undefined ? { parentSessionId: params.parentSessionId } : {}),
1709
+ ...(params.parentTurnId !== undefined ? { parentTurnId: params.parentTurnId } : {}),
1669
1710
  })
1670
1711
 
1671
1712
  const tracer = getTracer()
@@ -2489,6 +2530,7 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
2489
2530
  params,
2490
2531
  eventTranslator,
2491
2532
  takeSteps: () => iterationOrchestrator.getSteps(),
2533
+ turnEndHooksFired: () => iterationOrchestrator.turnEndHooksFired,
2492
2534
  workingStateManager,
2493
2535
  resultAssembler,
2494
2536
  rootSpan,