@namzu/sdk 61.4.0 → 62.1.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 (338) hide show
  1. package/CHANGELOG.md +62 -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/bridge/a2a/mapper.d.ts.map +1 -1
  6. package/dist/bridge/a2a/mapper.js +2 -0
  7. package/dist/bridge/a2a/mapper.js.map +1 -1
  8. package/dist/bridge/acp/permission.d.ts +8 -0
  9. package/dist/bridge/acp/permission.d.ts.map +1 -1
  10. package/dist/bridge/acp/permission.js.map +1 -1
  11. package/dist/bridge/acp/server.d.ts.map +1 -1
  12. package/dist/bridge/acp/server.js +8 -1
  13. package/dist/bridge/acp/server.js.map +1 -1
  14. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  15. package/dist/bridge/sse/mapper.js +13 -0
  16. package/dist/bridge/sse/mapper.js.map +1 -1
  17. package/dist/constants/tools/index.d.ts +2 -0
  18. package/dist/constants/tools/index.d.ts.map +1 -1
  19. package/dist/constants/tools/index.js +23 -0
  20. package/dist/constants/tools/index.js.map +1 -1
  21. package/dist/contracts/session/api.d.ts +1 -1
  22. package/dist/contracts/session/api.d.ts.map +1 -1
  23. package/dist/eval/harness-protection.js +1 -1
  24. package/dist/eval/harness-protection.js.map +1 -1
  25. package/dist/learning/cycle.d.ts +5 -3
  26. package/dist/learning/cycle.d.ts.map +1 -1
  27. package/dist/learning/cycle.js +11 -13
  28. package/dist/learning/cycle.js.map +1 -1
  29. package/dist/learning/guidance.d.ts +74 -0
  30. package/dist/learning/guidance.d.ts.map +1 -0
  31. package/dist/learning/guidance.js +259 -0
  32. package/dist/learning/guidance.js.map +1 -0
  33. package/dist/learning/skill.d.ts +2 -2
  34. package/dist/learning/skill.d.ts.map +1 -1
  35. package/dist/learning/skill.js +6 -6
  36. package/dist/learning/skill.js.map +1 -1
  37. package/dist/learning/store.d.ts.map +1 -1
  38. package/dist/learning/store.js +6 -6
  39. package/dist/learning/store.js.map +1 -1
  40. package/dist/pals/communication/ingress-schema.d.ts +8 -8
  41. package/dist/pals/communication/schema.d.ts +2 -2
  42. package/dist/peers/client.d.ts +2 -3
  43. package/dist/peers/client.d.ts.map +1 -1
  44. package/dist/peers/client.js +2 -3
  45. package/dist/peers/client.js.map +1 -1
  46. package/dist/peers/endpoint.d.ts +1 -2
  47. package/dist/peers/endpoint.d.ts.map +1 -1
  48. package/dist/peers/endpoint.js +1 -2
  49. package/dist/peers/endpoint.js.map +1 -1
  50. package/dist/peers/protocol.d.ts.map +1 -1
  51. package/dist/peers/protocol.js +1 -0
  52. package/dist/peers/protocol.js.map +1 -1
  53. package/dist/prompt/coding-agent-doctrine.d.ts +4 -4
  54. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  55. package/dist/prompt/coding-agent-doctrine.js +5 -3
  56. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  57. package/dist/prompt/index.d.ts +0 -4
  58. package/dist/prompt/index.d.ts.map +1 -1
  59. package/dist/prompt/index.js +0 -2
  60. package/dist/prompt/index.js.map +1 -1
  61. package/dist/provider/fallback.d.ts.map +1 -1
  62. package/dist/provider/fallback.js +3 -0
  63. package/dist/provider/fallback.js.map +1 -1
  64. package/dist/provider/idle-timeout.d.ts.map +1 -1
  65. package/dist/provider/idle-timeout.js +5 -0
  66. package/dist/provider/idle-timeout.js.map +1 -1
  67. package/dist/provider/model-window-suffix.d.ts.map +1 -1
  68. package/dist/provider/model-window-suffix.js +1 -0
  69. package/dist/provider/model-window-suffix.js.map +1 -1
  70. package/dist/provider/retry.d.ts.map +1 -1
  71. package/dist/provider/retry.js +5 -0
  72. package/dist/provider/retry.js.map +1 -1
  73. package/dist/provider/step-stopped.d.ts +19 -0
  74. package/dist/provider/step-stopped.d.ts.map +1 -0
  75. package/dist/provider/step-stopped.js +25 -0
  76. package/dist/provider/step-stopped.js.map +1 -0
  77. package/dist/provider/token-budget.d.ts.map +1 -1
  78. package/dist/provider/token-budget.js +6 -1
  79. package/dist/provider/token-budget.js.map +1 -1
  80. package/dist/public-runtime.d.ts +4 -15
  81. package/dist/public-runtime.d.ts.map +1 -1
  82. package/dist/public-runtime.js +4 -15
  83. package/dist/public-runtime.js.map +1 -1
  84. package/dist/public-tools.d.ts +0 -2
  85. package/dist/public-tools.d.ts.map +1 -1
  86. package/dist/public-tools.js +0 -2
  87. package/dist/public-tools.js.map +1 -1
  88. package/dist/public-types.d.ts +4 -22
  89. package/dist/public-types.d.ts.map +1 -1
  90. package/dist/runtime/query/iteration/index.d.ts +17 -0
  91. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  92. package/dist/runtime/query/iteration/index.js +176 -6
  93. package/dist/runtime/query/iteration/index.js.map +1 -1
  94. package/dist/runtime/query/iteration/phases/per-call-review.d.ts.map +1 -1
  95. package/dist/runtime/query/iteration/phases/per-call-review.js +4 -5
  96. package/dist/runtime/query/iteration/phases/per-call-review.js.map +1 -1
  97. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  98. package/dist/runtime/query/iteration/phases/tool-review.js +6 -3
  99. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  100. package/dist/runtime/query/iteration/recorded-context.d.ts +1 -1
  101. package/dist/runtime/query/iteration/recorded-context.d.ts.map +1 -1
  102. package/dist/runtime/query/iteration/recorded-context.js +2 -1
  103. package/dist/runtime/query/iteration/recorded-context.js.map +1 -1
  104. package/dist/runtime/query/iteration/stream-turn.d.ts +9 -1
  105. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  106. package/dist/runtime/query/iteration/stream-turn.js +48 -2
  107. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  108. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  109. package/dist/runtime/query/resume-pending.js +7 -4
  110. package/dist/runtime/query/resume-pending.js.map +1 -1
  111. package/dist/runtime/query/review-policy.d.ts +40 -8
  112. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  113. package/dist/runtime/query/review-policy.js +139 -24
  114. package/dist/runtime/query/review-policy.js.map +1 -1
  115. package/dist/runtime/query/turn/completion-audit.d.ts +32 -0
  116. package/dist/runtime/query/turn/completion-audit.d.ts.map +1 -0
  117. package/dist/runtime/query/turn/completion-audit.js +56 -0
  118. package/dist/runtime/query/turn/completion-audit.js.map +1 -0
  119. package/dist/runtime/query/turn/stall-monitor.d.ts +78 -0
  120. package/dist/runtime/query/turn/stall-monitor.d.ts.map +1 -0
  121. package/dist/runtime/query/turn/stall-monitor.js +101 -0
  122. package/dist/runtime/query/turn/stall-monitor.js.map +1 -0
  123. package/dist/session/paths.d.ts +1 -2
  124. package/dist/session/paths.d.ts.map +1 -1
  125. package/dist/session/paths.js +1 -4
  126. package/dist/session/paths.js.map +1 -1
  127. package/dist/store/index.d.ts +2 -0
  128. package/dist/store/index.d.ts.map +1 -1
  129. package/dist/store/index.js +1 -0
  130. package/dist/store/index.js.map +1 -1
  131. package/dist/tools/builtins/bash.d.ts +2 -1
  132. package/dist/tools/builtins/bash.d.ts.map +1 -1
  133. package/dist/tools/builtins/bash.js +5 -2
  134. package/dist/tools/builtins/bash.js.map +1 -1
  135. package/dist/tools/builtins/content-fingerprint.d.ts +13 -0
  136. package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -1
  137. package/dist/tools/builtins/content-fingerprint.js +25 -0
  138. package/dist/tools/builtins/content-fingerprint.js.map +1 -1
  139. package/dist/tools/builtins/edit.d.ts.map +1 -1
  140. package/dist/tools/builtins/edit.js +7 -2
  141. package/dist/tools/builtins/edit.js.map +1 -1
  142. package/dist/tools/builtins/shell-read-credit.d.ts +15 -0
  143. package/dist/tools/builtins/shell-read-credit.d.ts.map +1 -0
  144. package/dist/tools/builtins/shell-read-credit.js +161 -0
  145. package/dist/tools/builtins/shell-read-credit.js.map +1 -0
  146. package/dist/tools/paths.d.ts +15 -2
  147. package/dist/tools/paths.d.ts.map +1 -1
  148. package/dist/tools/paths.js +17 -2
  149. package/dist/tools/paths.js.map +1 -1
  150. package/dist/turn/evidence-recall.d.ts +1 -1
  151. package/dist/turn/evidence-recall.d.ts.map +1 -1
  152. package/dist/turn/evidence-recall.js +5 -14
  153. package/dist/turn/evidence-recall.js.map +1 -1
  154. package/dist/turn/memory-recall.d.ts.map +1 -1
  155. package/dist/turn/memory-recall.js +18 -4
  156. package/dist/turn/memory-recall.js.map +1 -1
  157. package/dist/turn/reporter.d.ts.map +1 -1
  158. package/dist/turn/reporter.js +5 -0
  159. package/dist/turn/reporter.js.map +1 -1
  160. package/dist/types/acp/index.d.ts +6 -0
  161. package/dist/types/acp/index.d.ts.map +1 -1
  162. package/dist/types/agent/base.d.ts +4 -0
  163. package/dist/types/agent/base.d.ts.map +1 -1
  164. package/dist/types/hitl/index.d.ts +8 -0
  165. package/dist/types/hitl/index.d.ts.map +1 -1
  166. package/dist/types/hitl/index.js.map +1 -1
  167. package/dist/types/ids/index.d.ts +1 -1
  168. package/dist/types/message/index.d.ts +1 -1
  169. package/dist/types/message/index.d.ts.map +1 -1
  170. package/dist/types/message/index.js +1 -0
  171. package/dist/types/message/index.js.map +1 -1
  172. package/dist/types/provider/interface.d.ts +12 -0
  173. package/dist/types/provider/interface.d.ts.map +1 -1
  174. package/dist/types/session/config.d.ts +25 -0
  175. package/dist/types/session/config.d.ts.map +1 -1
  176. package/dist/types/session/events.d.ts +19 -0
  177. package/dist/types/session/events.d.ts.map +1 -1
  178. package/dist/types/session/events.js.map +1 -1
  179. package/dist/types/session/prepare-step.d.ts +16 -0
  180. package/dist/types/session/prepare-step.d.ts.map +1 -1
  181. package/dist/types/session/records.d.ts.map +1 -1
  182. package/dist/types/session/records.js +3 -0
  183. package/dist/types/session/records.js.map +1 -1
  184. package/dist/types/session/turn.d.ts +1 -1
  185. package/dist/types/session/turn.d.ts.map +1 -1
  186. package/dist/types/session/turn.js.map +1 -1
  187. package/package.json +1 -1
  188. package/src/agents/QueryAgent.ts +2 -0
  189. package/src/bridge/a2a/mapper.ts +2 -0
  190. package/src/bridge/acp/permission.ts +8 -0
  191. package/src/bridge/acp/server.ts +7 -1
  192. package/src/bridge/sse/mapper.ts +13 -0
  193. package/src/constants/tools/index.ts +27 -0
  194. package/src/contracts/session/api.ts +1 -0
  195. package/src/eval/harness-protection.ts +1 -1
  196. package/src/learning/cycle.ts +15 -16
  197. package/src/learning/guidance.ts +339 -0
  198. package/src/learning/skill.ts +7 -7
  199. package/src/learning/store.ts +5 -6
  200. package/src/peers/client.ts +2 -3
  201. package/src/peers/endpoint.ts +1 -2
  202. package/src/peers/protocol.ts +1 -0
  203. package/src/prompt/coding-agent-doctrine.ts +5 -3
  204. package/src/prompt/index.ts +0 -4
  205. package/src/provider/fallback.ts +7 -0
  206. package/src/provider/idle-timeout.ts +8 -0
  207. package/src/provider/model-window-suffix.ts +1 -0
  208. package/src/provider/retry.ts +8 -0
  209. package/src/provider/step-stopped.ts +27 -0
  210. package/src/provider/token-budget.ts +6 -1
  211. package/src/public-runtime.ts +7 -28
  212. package/src/public-tools.ts +0 -3
  213. package/src/public-types.ts +6 -137
  214. package/src/runtime/query/iteration/index.ts +218 -6
  215. package/src/runtime/query/iteration/phases/per-call-review.ts +7 -5
  216. package/src/runtime/query/iteration/phases/tool-review.ts +5 -3
  217. package/src/runtime/query/iteration/recorded-context.ts +2 -0
  218. package/src/runtime/query/iteration/stream-turn.ts +51 -1
  219. package/src/runtime/query/resume-pending.ts +11 -4
  220. package/src/runtime/query/review-policy.ts +157 -24
  221. package/src/runtime/query/turn/completion-audit.ts +71 -0
  222. package/src/runtime/query/turn/stall-monitor.ts +158 -0
  223. package/src/session/paths.ts +2 -6
  224. package/src/store/index.ts +2 -0
  225. package/src/tools/builtins/bash.ts +6 -2
  226. package/src/tools/builtins/content-fingerprint.ts +25 -0
  227. package/src/tools/builtins/edit.ts +11 -2
  228. package/src/tools/builtins/shell-read-credit.ts +159 -0
  229. package/src/tools/paths.ts +18 -2
  230. package/src/turn/evidence-recall.ts +7 -15
  231. package/src/turn/memory-recall.ts +26 -7
  232. package/src/turn/reporter.ts +5 -0
  233. package/src/types/acp/index.ts +6 -0
  234. package/src/types/agent/base.ts +4 -0
  235. package/src/types/hitl/index.ts +8 -0
  236. package/src/types/ids/index.ts +1 -1
  237. package/src/types/message/index.ts +1 -0
  238. package/src/types/provider/interface.ts +13 -0
  239. package/src/types/session/config.ts +27 -0
  240. package/src/types/session/events.ts +19 -0
  241. package/src/types/session/prepare-step.ts +17 -0
  242. package/src/types/session/records.ts +3 -0
  243. package/src/types/session/turn.ts +2 -1
  244. package/dist/learning/deprecated.d.ts +0 -86
  245. package/dist/learning/deprecated.d.ts.map +0 -1
  246. package/dist/learning/deprecated.js +0 -22
  247. package/dist/learning/deprecated.js.map +0 -1
  248. package/dist/manager/resident/activity.d.ts +0 -74
  249. package/dist/manager/resident/activity.d.ts.map +0 -1
  250. package/dist/manager/resident/activity.js +0 -125
  251. package/dist/manager/resident/activity.js.map +0 -1
  252. package/dist/manager/resident/agenda.d.ts +0 -167
  253. package/dist/manager/resident/agenda.d.ts.map +0 -1
  254. package/dist/manager/resident/agenda.js +0 -588
  255. package/dist/manager/resident/agenda.js.map +0 -1
  256. package/dist/manager/resident/consumption.d.ts +0 -98
  257. package/dist/manager/resident/consumption.d.ts.map +0 -1
  258. package/dist/manager/resident/consumption.js +0 -237
  259. package/dist/manager/resident/consumption.js.map +0 -1
  260. package/dist/manager/resident/delivery-window.d.ts +0 -28
  261. package/dist/manager/resident/delivery-window.d.ts.map +0 -1
  262. package/dist/manager/resident/delivery-window.js +0 -80
  263. package/dist/manager/resident/delivery-window.js.map +0 -1
  264. package/dist/manager/resident/evidence-recall.d.ts +0 -30
  265. package/dist/manager/resident/evidence-recall.d.ts.map +0 -1
  266. package/dist/manager/resident/evidence-recall.js +0 -297
  267. package/dist/manager/resident/evidence-recall.js.map +0 -1
  268. package/dist/manager/resident/history-disk.d.ts +0 -10
  269. package/dist/manager/resident/history-disk.d.ts.map +0 -1
  270. package/dist/manager/resident/history-disk.js +0 -50
  271. package/dist/manager/resident/history-disk.js.map +0 -1
  272. package/dist/manager/resident/history.d.ts +0 -115
  273. package/dist/manager/resident/history.d.ts.map +0 -1
  274. package/dist/manager/resident/history.js +0 -203
  275. package/dist/manager/resident/history.js.map +0 -1
  276. package/dist/manager/resident/host.d.ts +0 -112
  277. package/dist/manager/resident/host.d.ts.map +0 -1
  278. package/dist/manager/resident/host.js +0 -254
  279. package/dist/manager/resident/host.js.map +0 -1
  280. package/dist/manager/resident/initiative.d.ts +0 -86
  281. package/dist/manager/resident/initiative.d.ts.map +0 -1
  282. package/dist/manager/resident/initiative.js +0 -131
  283. package/dist/manager/resident/initiative.js.map +0 -1
  284. package/dist/manager/resident/loop.d.ts +0 -49
  285. package/dist/manager/resident/loop.d.ts.map +0 -1
  286. package/dist/manager/resident/loop.js +0 -75
  287. package/dist/manager/resident/loop.js.map +0 -1
  288. package/dist/manager/resident/outbox.d.ts +0 -124
  289. package/dist/manager/resident/outbox.d.ts.map +0 -1
  290. package/dist/manager/resident/outbox.js +0 -216
  291. package/dist/manager/resident/outbox.js.map +0 -1
  292. package/dist/manager/resident/proposal.d.ts +0 -65
  293. package/dist/manager/resident/proposal.d.ts.map +0 -1
  294. package/dist/manager/resident/proposal.js +0 -77
  295. package/dist/manager/resident/proposal.js.map +0 -1
  296. package/dist/manager/resident/store.d.ts +0 -108
  297. package/dist/manager/resident/store.d.ts.map +0 -1
  298. package/dist/manager/resident/store.js +0 -205
  299. package/dist/manager/resident/store.js.map +0 -1
  300. package/dist/manager/resident/tool-evidence.d.ts +0 -112
  301. package/dist/manager/resident/tool-evidence.d.ts.map +0 -1
  302. package/dist/manager/resident/tool-evidence.js +0 -289
  303. package/dist/manager/resident/tool-evidence.js.map +0 -1
  304. package/dist/prompt/resident-learning.d.ts +0 -29
  305. package/dist/prompt/resident-learning.d.ts.map +0 -1
  306. package/dist/prompt/resident-learning.js +0 -126
  307. package/dist/prompt/resident-learning.js.map +0 -1
  308. package/dist/prompt/resident-step.d.ts +0 -42
  309. package/dist/prompt/resident-step.d.ts.map +0 -1
  310. package/dist/prompt/resident-step.js +0 -137
  311. package/dist/prompt/resident-step.js.map +0 -1
  312. package/dist/tools/resident-history.d.ts +0 -12
  313. package/dist/tools/resident-history.d.ts.map +0 -1
  314. package/dist/tools/resident-history.js +0 -82
  315. package/dist/tools/resident-history.js.map +0 -1
  316. package/dist/tools/resident-tool-evidence.d.ts +0 -9
  317. package/dist/tools/resident-tool-evidence.d.ts.map +0 -1
  318. package/dist/tools/resident-tool-evidence.js +0 -61
  319. package/dist/tools/resident-tool-evidence.js.map +0 -1
  320. package/src/learning/deprecated.ts +0 -124
  321. package/src/manager/resident/activity.ts +0 -211
  322. package/src/manager/resident/agenda.ts +0 -937
  323. package/src/manager/resident/consumption.ts +0 -335
  324. package/src/manager/resident/delivery-window.ts +0 -99
  325. package/src/manager/resident/evidence-recall.ts +0 -369
  326. package/src/manager/resident/history-disk.ts +0 -63
  327. package/src/manager/resident/history.ts +0 -348
  328. package/src/manager/resident/host.ts +0 -390
  329. package/src/manager/resident/initiative.ts +0 -231
  330. package/src/manager/resident/loop.ts +0 -119
  331. package/src/manager/resident/outbox.ts +0 -341
  332. package/src/manager/resident/proposal.ts +0 -119
  333. package/src/manager/resident/store.ts +0 -279
  334. package/src/manager/resident/tool-evidence.ts +0 -455
  335. package/src/prompt/resident-learning.ts +0 -152
  336. package/src/prompt/resident-step.ts +0 -182
  337. package/src/tools/resident-history.ts +0 -88
  338. package/src/tools/resident-tool-evidence.ts +0 -72
@@ -29,6 +29,8 @@ import { diffRequestContext, snapshotRequestContext, } from '../request-context.
29
29
  import { DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES, markProviderRejectedImage, projectRequestRichContent, } from '../request-rich-content.js';
30
30
  import { withoutVoidAssistantTurns } from '../request-void-turns.js';
31
31
  import { formatSteeringNote, isOperatorUserMessage } from '../steering.js';
32
+ import { COMPLETION_AUDIT_MESSAGE, CompletionAudit } from '../turn/completion-audit.js';
33
+ import { FORCED_STEP_MESSAGE, REASONING_CAPPED_MESSAGE, REASONING_ONLY_MESSAGE, StallMonitor, callChangedState, reasoningCapChars, } from '../turn/stall-monitor.js';
32
34
  import { effortForModel } from './effort-clamp.js';
33
35
  import { parseNativeCandidate } from './native-output.js';
34
36
  import { drainArrivedTaskCompletions, holdForOutstandingWork, settleOutstandingWork, } from './outstanding-work.js';
@@ -46,6 +48,8 @@ import { RequestRepair } from './request-repair.js';
46
48
  import { placeRequestContext } from './step-context.js';
47
49
  import { beforeStep, prepareStep, selectContextModel, stepContextMessage, workContext, } from './step-shaping.js';
48
50
  import { streamProviderTurn } from './stream-turn.js';
51
+ /** Capped steps in a row after which the per-step cap stops applying for the turn's next step. */
52
+ const MAX_CAPPED_STREAK = 3;
49
53
  /** A host reviewer is not the model transport, even when its cause is an HTTP failure. */
50
54
  class AnswerReviewFailure extends NamzuError {
51
55
  constructor(cause) {
@@ -193,6 +197,16 @@ export class IterationOrchestrator {
193
197
  stopDeferredForOutstandingWork = false;
194
198
  /** Nudges sent since the model last finished a call without hitting its output cap. */
195
199
  outputContinuations = 0;
200
+ /** Watches the turn's steps for reasoning that piles up while nothing changes. */
201
+ stallMonitor;
202
+ /** Holds the turn back once when it changed files and checked nothing afterwards. */
203
+ completionAudit;
204
+ /** The next step must call a tool, at low effort: set by the stall monitor or a capped step. */
205
+ forceActionNextStep = false;
206
+ /** Steps in a row cut at the per-step reasoning cap; past a few the cap stops applying. */
207
+ cappedStreak = 0;
208
+ /** A reply that held only reasoning was already answered with one more request. */
209
+ reasoningOnlyRetried = false;
196
210
  /**
197
211
  * The model a refused request moved to. Once set it replaces the model the
198
212
  * step asked for, for the rest of the turn: the request that was refused
@@ -275,6 +289,11 @@ export class IterationOrchestrator {
275
289
  this.rememberUserMessage(createRuntimeContextMessage(text, 'steering'));
276
290
  },
277
291
  };
292
+ if (ctx.turnConfig.completionAudit === true)
293
+ this.completionAudit = new CompletionAudit();
294
+ if (ctx.turnConfig.reasoning?.stall !== false) {
295
+ this.stallMonitor = new StallMonitor(ctx.turnConfig.reasoning?.stall || undefined);
296
+ }
278
297
  ctx.checkpointMgr.setLatestUserMessageSource(() => this.latestUserMessage);
279
298
  ctx.checkpointMgr.setAnswerReviewAttemptsSource?.(() => this.answerReviewAttempts);
280
299
  ctx.checkpointMgr.setStructuredReviewAttemptsSource?.(() => this.structuredReviewAttempts);
@@ -687,7 +706,14 @@ export class IterationOrchestrator {
687
706
  // history now, after its last message, so this request and every
688
707
  // later one begin with it. Nothing is inserted ahead of a message
689
708
  // that is already recorded.
690
- appendRecordedContext(recorder, step.recordedContext, this.ctx.log);
709
+ const recalled = [];
710
+ appendRecordedContext(recorder, step.recordedContext, this.ctx.log, undefined, (item) => recalled.push(...(item.recalledMemories ?? [])));
711
+ if (recalled.length > 0)
712
+ await this.ctx.emitEvent?.({
713
+ type: 'memory_recalled',
714
+ turnId: recorder.turnId,
715
+ memories: recalled,
716
+ });
691
717
  const baseMessages = recorder.messages;
692
718
  // Step guidance is appended to the REQUEST, never pushed onto
693
719
  // the turn's history: it applies to this step only, and pushing
@@ -871,6 +897,11 @@ export class IterationOrchestrator {
871
897
  // died part-way has already emitted both `message_started` and
872
898
  // `message_completed` under this id, which is the trail a
873
899
  // reader wants most on exactly that turn.
900
+ // A step the loop forces to act runs at low effort with a tool call
901
+ // required, for this step only. Low is used only where the model
902
+ // is known to offer it; effort is refused, not clamped.
903
+ const forcedAction = this.forceActionNextStep && !forceFinalize && llmTools.length > 0;
904
+ this.forceActionNextStep = false;
874
905
  stepMessageId = generateMessageId();
875
906
  const requestedMember = this.ctx.servingMember?.() ?? {
876
907
  index: 0,
@@ -895,11 +926,22 @@ export class IterationOrchestrator {
895
926
  });
896
927
  }
897
928
  }
929
+ // A forced action step runs at low effort, where the model is known
930
+ // to offer it; effort is refused, not clamped.
931
+ const offeredEfforts = this.ctx.provider.reasoningEffortLevelsFor?.(stepModel);
932
+ const stepEffort = forcedAction && requestEffort && (offeredEfforts?.includes('low') ?? false)
933
+ ? 'low'
934
+ : requestEffort;
935
+ // A provider that refuses a forced tool choice (some models do, and
936
+ // so does manual extended thinking) is not sent one: the step keeps
937
+ // its low effort and asks in words, on this request only.
938
+ const forcedChoiceRefused = forcedAction &&
939
+ this.ctx.provider.acceptsForcedToolChoiceFor?.(stepModel, turnConfig.thinking) === false;
898
940
  const operatorInputAtDispatch = this.latestUserMessage;
899
941
  const latestReviewUserMessage = (this.ctx.reviewAnswer || this.ctx.structuredOutput?.review) && operatorInputAtDispatch
900
942
  ? structuredClone(operatorInputAtDispatch)
901
943
  : undefined;
902
- const { response, messageId, requestMessages } = yield* streamProviderTurn(this.ctx.provider, {
944
+ const { response, messageId, requestMessages, reasoningCapped = false, } = yield* streamProviderTurn(this.ctx.provider, {
903
945
  model: stepModel,
904
946
  ...(this.ctx.structuredOutput?.mode === 'native'
905
947
  ? {
@@ -914,7 +956,9 @@ export class IterationOrchestrator {
914
956
  }
915
957
  : {}),
916
958
  providerRoute: requestedRoute,
917
- messages,
959
+ messages: forcedChoiceRefused
960
+ ? [...messages, createRuntimeContextMessage(FORCED_STEP_MESSAGE, 'progress-nudge')]
961
+ : messages,
918
962
  tools: llmTools.length > 0 ? llmTools : undefined,
919
963
  ...(enforceToolInputSchema ? { enforceToolInputSchema } : {}),
920
964
  // The forced-final turn wins: a step that asked to force a
@@ -925,13 +969,15 @@ export class IterationOrchestrator {
925
969
  toolChoice: forceFinalize && llmTools.length > 0
926
970
  ? 'none'
927
971
  : llmTools.length > 0
928
- ? step.toolChoice
972
+ ? forcedAction && !forcedChoiceRefused
973
+ ? (step.toolChoice ?? 'required')
974
+ : step.toolChoice
929
975
  : undefined,
930
976
  temperature: step.temperature ?? turnConfig.temperature,
931
977
  maxTokens: outputCapOverride ?? step.maxResponseTokens ?? turnConfig.maxResponseTokens,
932
978
  cacheControl: { type: 'auto' },
933
979
  ...(turnConfig.thinking ? { thinking: turnConfig.thinking } : {}),
934
- ...(requestEffort ? { effort: requestEffort } : {}),
980
+ ...(stepEffort ? { effort: stepEffort } : {}),
935
981
  ...(!forceFinalize && turnConfig.webSearch
936
982
  ? { webSearch: turnConfig.webSearch }
937
983
  : {}),
@@ -943,8 +989,15 @@ export class IterationOrchestrator {
943
989
  onAccepted: (identity) => this.acceptProviderRejectedImage(identity),
944
990
  textOnly: this.textOnlyRecovery(stepModel),
945
991
  repair: this.requestRepair,
946
- }, Boolean(this.ctx.reviewAnswer || this.ctx.structuredOutput?.review || this.ctx.advisoryCtx), recorder.sessionId);
992
+ }, Boolean(this.ctx.reviewAnswer || this.ctx.structuredOutput?.review || this.ctx.advisoryCtx), recorder.sessionId,
993
+ // Applies only to a step that can act. Stops after a few capped
994
+ // steps in a row, so a model that cannot act within the allowance
995
+ // still gets to finish.
996
+ this.cappedStreak >= MAX_CAPPED_STREAK || forceFinalize || llmTools.length === 0
997
+ ? undefined
998
+ : reasoningCapChars(turnConfig.reasoning, stepEffort));
947
999
  stepResponse = response;
1000
+ this.cappedStreak = reasoningCapped ? this.cappedStreak + 1 : 0;
948
1001
  const reviewRequest = {
949
1002
  ...(requestMessages ? { requestMessages } : {}),
950
1003
  ...(latestReviewUserMessage ? { latestUserMessage: latestReviewUserMessage } : {}),
@@ -1206,6 +1259,25 @@ export class IterationOrchestrator {
1206
1259
  usageBefore,
1207
1260
  costBefore,
1208
1261
  });
1262
+ // The step spent its whole reasoning allowance before acting. Tell
1263
+ // the model so and make the next step an action step.
1264
+ if (reasoningCapped && !forceFinalize) {
1265
+ this.ctx.log.info('Reasoning reached the per-step cap — asking the model to act', {
1266
+ [NAMZU.TURN_ID]: recorder.turnId,
1267
+ [NAMZU.ITERATION]: iterationNum,
1268
+ });
1269
+ recorder.pushMessage(createRuntimeContextMessage(REASONING_CAPPED_MESSAGE, 'progress-nudge'));
1270
+ this.forceActionNextStep = true;
1271
+ this.observeStall(response, []);
1272
+ await this.ctx.emitEvent({
1273
+ type: 'iteration_completed',
1274
+ turnId: recorder.turnId,
1275
+ iteration: iterationNum,
1276
+ hasToolCalls: false,
1277
+ });
1278
+ yield* this.ctx.drainPending();
1279
+ continue;
1280
+ }
1209
1281
  if (this.ctx.structuredOutput?.mode === 'native') {
1210
1282
  const candidate = await parseNativeCandidate(this.ctx.structuredOutput.schema, response, this.ctx.abortController.signal);
1211
1283
  let outcome;
@@ -1445,6 +1517,27 @@ export class IterationOrchestrator {
1445
1517
  let closingStopReason = forceFinalize
1446
1518
  ? guardResult.stopReason
1447
1519
  : undefined;
1520
+ const reasoningOnly = !hasContent && (response.message.reasoning?.length ?? 0) > 0;
1521
+ if (hasContent)
1522
+ this.reasoningOnlyRetried = false;
1523
+ // A reply of reasoning alone is not an end: ask once more, plainly,
1524
+ // before the closing request below.
1525
+ if (reasoningOnly && !forceFinalize && !this.reasoningOnlyRetried) {
1526
+ this.reasoningOnlyRetried = true;
1527
+ this.ctx.log.warn('Reply held reasoning only — asking once more', {
1528
+ [NAMZU.TURN_ID]: recorder.turnId,
1529
+ [NAMZU.ITERATION]: iterationNum,
1530
+ });
1531
+ recorder.pushMessage(createRuntimeContextMessage(REASONING_ONLY_MESSAGE, 'progress-nudge'));
1532
+ await this.ctx.emitEvent({
1533
+ type: 'iteration_completed',
1534
+ turnId: recorder.turnId,
1535
+ iteration: iterationNum,
1536
+ hasToolCalls: false,
1537
+ });
1538
+ yield* this.ctx.drainPending();
1539
+ continue;
1540
+ }
1448
1541
  if (!hasContent && !forceFinalize) {
1449
1542
  this.ctx.log.warn('Empty completion detected — requesting final summary', {
1450
1543
  [NAMZU.ITERATION]: iterationNum,
@@ -1452,6 +1545,13 @@ export class IterationOrchestrator {
1452
1545
  });
1453
1546
  closingStopReason = await this.requestFinalResponse(this.refusalPinnedModel ?? model, 'end_turn');
1454
1547
  yield* this.ctx.drainPending();
1548
+ // Never end silently: if even the closing request produced nothing,
1549
+ // say so in plain words and how to go on.
1550
+ if (reasoningOnly &&
1551
+ closingStopReason === undefined &&
1552
+ !([...recorder.messages].reverse().find((m) => m.role === 'assistant')?.content ?? '').length) {
1553
+ recorder.setLastError('The model stopped after thinking without giving an answer or taking an action, even when asked again. Say "continue" and it will pick the work up from here.');
1554
+ }
1455
1555
  }
1456
1556
  await this.ctx.emitEvent({
1457
1557
  type: 'iteration_completed',
@@ -1483,6 +1583,17 @@ export class IterationOrchestrator {
1483
1583
  // The model is done and has no tool calls. A `turn_end` (or
1484
1584
  // `subagent_stop`) hook may refuse to let it be: its reason goes
1485
1585
  // back to the model and the turn goes on.
1586
+ // Files were changed and nothing checked them afterwards: ask once
1587
+ // for a check before the turn is allowed to end.
1588
+ if (!forceFinalize &&
1589
+ closingStopReason === undefined &&
1590
+ this.completionAudit?.takeBlock()) {
1591
+ this.ctx.log.info('Files changed and nothing checked them — asking for a check', {
1592
+ [NAMZU.TURN_ID]: recorder.turnId,
1593
+ });
1594
+ recorder.pushMessage(createRuntimeContextMessage(COMPLETION_AUDIT_MESSAGE, 'progress-nudge'));
1595
+ continue;
1596
+ }
1486
1597
  if (!forceFinalize && closingStopReason === undefined) {
1487
1598
  const feedback = yield* this.askStopHooks();
1488
1599
  const stoppedByHook = this.ctx.toolExecutor.takeHalt?.();
@@ -1520,6 +1631,9 @@ export class IterationOrchestrator {
1520
1631
  usageBefore,
1521
1632
  costBefore,
1522
1633
  });
1634
+ this.reasoningOnlyRetried = false;
1635
+ this.observeStall(response, reviewOutcome.results);
1636
+ this.observeAudit(response, reviewOutcome.results);
1523
1637
  if (reviewOutcome.decision === 'stop') {
1524
1638
  return;
1525
1639
  }
@@ -2645,6 +2759,62 @@ export class IterationOrchestrator {
2645
2759
  return undefined;
2646
2760
  }
2647
2761
  }
2762
+ /** Feed the completion audit the calls of one finished step. */
2763
+ observeAudit(response, results) {
2764
+ const audit = this.completionAudit;
2765
+ if (!audit)
2766
+ return;
2767
+ const calls = new Map((response.message.toolCalls ?? []).map((c) => [c.id, c]));
2768
+ audit.observe(results.map((result) => {
2769
+ let input;
2770
+ try {
2771
+ const call = calls.get(result.toolCallId);
2772
+ input = call ? JSON.parse(call.function.arguments) : undefined;
2773
+ }
2774
+ catch {
2775
+ input = undefined;
2776
+ }
2777
+ return { toolName: result.toolName, input, isError: result.isError };
2778
+ }));
2779
+ }
2780
+ /**
2781
+ * Feed the stall monitor one finished step and act on its verdict: a nudge
2782
+ * is recorded as a message, a force makes the next step an action step.
2783
+ */
2784
+ observeStall(response, results) {
2785
+ const monitor = this.stallMonitor;
2786
+ if (!monitor)
2787
+ return;
2788
+ const calls = new Map((response.message.toolCalls ?? []).map((c) => [c.id, c]));
2789
+ let changedState = false;
2790
+ for (const result of results) {
2791
+ const call = calls.get(result.toolCallId);
2792
+ let readOnly;
2793
+ try {
2794
+ const input = call ? JSON.parse(call.function.arguments) : undefined;
2795
+ readOnly = this.ctx.tools.get(result.toolName)?.isReadOnly?.(input);
2796
+ }
2797
+ catch {
2798
+ readOnly = undefined;
2799
+ }
2800
+ if (callChangedState(result.toolName, readOnly, result.isError))
2801
+ changedState = true;
2802
+ }
2803
+ const reasoningChars = (response.message.reasoning ?? []).reduce((n, block) => n + (block.text?.length ?? 0), 0);
2804
+ const directive = monitor.observe({ reasoningChars, changedState });
2805
+ if (directive.kind === 'nudge') {
2806
+ this.ctx.log.info('Many steps without a change — nudging the model to act', {
2807
+ [NAMZU.TURN_ID]: this.ctx.recorder.turnId,
2808
+ });
2809
+ this.ctx.recorder.pushMessage(createRuntimeContextMessage(directive.text, 'progress-nudge'));
2810
+ }
2811
+ else if (directive.kind === 'force') {
2812
+ this.ctx.log.info('Still no change after the nudge — forcing an action step', {
2813
+ [NAMZU.TURN_ID]: this.ctx.recorder.turnId,
2814
+ });
2815
+ this.forceActionNextStep = true;
2816
+ }
2817
+ }
2648
2818
  async requestFinalResponse(model, reason) {
2649
2819
  if (this.ctx.structuredOutput?.mode === 'native')
2650
2820
  return 'structured_output_failed';