agentfootprint 9.112.2 → 9.114.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 (282) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/CLAUDE.md +2 -1
  3. package/dist/adapters/observability/audit.js +8 -0
  4. package/dist/adapters/observability/audit.js.map +1 -1
  5. package/dist/adapters/observability/otel.js +44 -2
  6. package/dist/adapters/observability/otel.js.map +1 -1
  7. package/dist/adapters/observability/xray.js +19 -0
  8. package/dist/adapters/observability/xray.js.map +1 -1
  9. package/dist/adapters/types.js.map +1 -1
  10. package/dist/core/Agent.js +11 -1
  11. package/dist/core/Agent.js.map +1 -1
  12. package/dist/core/agent/composeRequest.js +19 -11
  13. package/dist/core/agent/composeRequest.js.map +1 -1
  14. package/dist/core/agent/coverage/absent.js +163 -7
  15. package/dist/core/agent/coverage/absent.js.map +1 -1
  16. package/dist/core/agent/coverage/answer.js +3 -1
  17. package/dist/core/agent/coverage/answer.js.map +1 -1
  18. package/dist/core/agent/coverage/read.js +18 -12
  19. package/dist/core/agent/coverage/read.js.map +1 -1
  20. package/dist/core/agent/findings/ledger.js +27 -5
  21. package/dist/core/agent/findings/ledger.js.map +1 -1
  22. package/dist/core/agent/findings/offer.js +29 -9
  23. package/dist/core/agent/findings/offer.js.map +1 -1
  24. package/dist/core/agent/findings/serve.js +76 -7
  25. package/dist/core/agent/findings/serve.js.map +1 -1
  26. package/dist/core/agent/findings/types.js.map +1 -1
  27. package/dist/core/agent/findings/unsettled.js +283 -0
  28. package/dist/core/agent/findings/unsettled.js.map +1 -0
  29. package/dist/core/agent/stages/callLLM.js +30 -8
  30. package/dist/core/agent/stages/callLLM.js.map +1 -1
  31. package/dist/core/agent/stages/route.js +10 -2
  32. package/dist/core/agent/stages/route.js.map +1 -1
  33. package/dist/core/agent/stages/toolCalls.js +365 -68
  34. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  35. package/dist/core/agent/stages/window.js +5 -2
  36. package/dist/core/agent/stages/window.js.map +1 -1
  37. package/dist/core/agent/toolDispatch.js +4 -1
  38. package/dist/core/agent/toolDispatch.js.map +1 -1
  39. package/dist/core/agent/toolResultCap.js +0 -0
  40. package/dist/core/agent/toolResultCap.js.map +1 -1
  41. package/dist/core/agent/window/ledgerFactPins.js +13 -2
  42. package/dist/core/agent/window/ledgerFactPins.js.map +1 -1
  43. package/dist/core/agent/window/toolNames.js +17 -2
  44. package/dist/core/agent/window/toolNames.js.map +1 -1
  45. package/dist/core/checkin.js +5 -1
  46. package/dist/core/checkin.js.map +1 -1
  47. package/dist/core/inputRequest.js +32 -2
  48. package/dist/core/inputRequest.js.map +1 -1
  49. package/dist/core/pause.js +13 -1
  50. package/dist/core/pause.js.map +1 -1
  51. package/dist/core/runCheckpoint.js +26 -2
  52. package/dist/core/runCheckpoint.js.map +1 -1
  53. package/dist/esm/adapters/observability/audit.d.ts +8 -0
  54. package/dist/esm/adapters/observability/audit.js +8 -0
  55. package/dist/esm/adapters/observability/audit.js.map +1 -1
  56. package/dist/esm/adapters/observability/otel.d.ts +17 -2
  57. package/dist/esm/adapters/observability/otel.js +44 -2
  58. package/dist/esm/adapters/observability/otel.js.map +1 -1
  59. package/dist/esm/adapters/observability/xray.d.ts +8 -0
  60. package/dist/esm/adapters/observability/xray.js +19 -0
  61. package/dist/esm/adapters/observability/xray.js.map +1 -1
  62. package/dist/esm/adapters/types.d.ts +49 -0
  63. package/dist/esm/adapters/types.js.map +1 -1
  64. package/dist/esm/core/Agent.js +11 -1
  65. package/dist/esm/core/Agent.js.map +1 -1
  66. package/dist/esm/core/agent/composeRequest.d.ts +10 -7
  67. package/dist/esm/core/agent/composeRequest.js +19 -11
  68. package/dist/esm/core/agent/composeRequest.js.map +1 -1
  69. package/dist/esm/core/agent/coverage/absent.d.ts +31 -4
  70. package/dist/esm/core/agent/coverage/absent.js +160 -6
  71. package/dist/esm/core/agent/coverage/absent.js.map +1 -1
  72. package/dist/esm/core/agent/coverage/answer.js +3 -1
  73. package/dist/esm/core/agent/coverage/answer.js.map +1 -1
  74. package/dist/esm/core/agent/coverage/index.d.ts +1 -1
  75. package/dist/esm/core/agent/coverage/read.d.ts +12 -2
  76. package/dist/esm/core/agent/coverage/read.js +19 -13
  77. package/dist/esm/core/agent/coverage/read.js.map +1 -1
  78. package/dist/esm/core/agent/coverage/types.d.ts +42 -0
  79. package/dist/esm/core/agent/findings/ledger.d.ts +23 -6
  80. package/dist/esm/core/agent/findings/ledger.js +27 -5
  81. package/dist/esm/core/agent/findings/ledger.js.map +1 -1
  82. package/dist/esm/core/agent/findings/offer.d.ts +23 -6
  83. package/dist/esm/core/agent/findings/offer.js +27 -8
  84. package/dist/esm/core/agent/findings/offer.js.map +1 -1
  85. package/dist/esm/core/agent/findings/serve.d.ts +19 -6
  86. package/dist/esm/core/agent/findings/serve.js +77 -8
  87. package/dist/esm/core/agent/findings/serve.js.map +1 -1
  88. package/dist/esm/core/agent/findings/types.d.ts +81 -1
  89. package/dist/esm/core/agent/findings/types.js.map +1 -1
  90. package/dist/esm/core/agent/findings/unsettled.d.ts +128 -0
  91. package/dist/esm/core/agent/findings/unsettled.js +278 -0
  92. package/dist/esm/core/agent/findings/unsettled.js.map +1 -0
  93. package/dist/esm/core/agent/stages/callLLM.js +30 -8
  94. package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
  95. package/dist/esm/core/agent/stages/route.js +10 -2
  96. package/dist/esm/core/agent/stages/route.js.map +1 -1
  97. package/dist/esm/core/agent/stages/toolCalls.d.ts +90 -2
  98. package/dist/esm/core/agent/stages/toolCalls.js +362 -68
  99. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  100. package/dist/esm/core/agent/stages/window.js +5 -2
  101. package/dist/esm/core/agent/stages/window.js.map +1 -1
  102. package/dist/esm/core/agent/toolDispatch.d.ts +4 -1
  103. package/dist/esm/core/agent/toolDispatch.js +4 -1
  104. package/dist/esm/core/agent/toolDispatch.js.map +1 -1
  105. package/dist/esm/core/agent/toolResultCap.d.ts +4 -1
  106. package/dist/esm/core/agent/toolResultCap.js +0 -0
  107. package/dist/esm/core/agent/toolResultCap.js.map +1 -1
  108. package/dist/esm/core/agent/types.d.ts +5 -0
  109. package/dist/esm/core/agent/window/ledgerFactPins.d.ts +10 -1
  110. package/dist/esm/core/agent/window/ledgerFactPins.js +13 -2
  111. package/dist/esm/core/agent/window/ledgerFactPins.js.map +1 -1
  112. package/dist/esm/core/agent/window/strategy.d.ts +2 -1
  113. package/dist/esm/core/agent/window/toolNames.d.ts +16 -1
  114. package/dist/esm/core/agent/window/toolNames.js +17 -2
  115. package/dist/esm/core/agent/window/toolNames.js.map +1 -1
  116. package/dist/esm/core/checkin.js +5 -1
  117. package/dist/esm/core/checkin.js.map +1 -1
  118. package/dist/esm/core/inputRequest.d.ts +20 -1
  119. package/dist/esm/core/inputRequest.js +32 -2
  120. package/dist/esm/core/inputRequest.js.map +1 -1
  121. package/dist/esm/core/pause.d.ts +13 -1
  122. package/dist/esm/core/pause.js +13 -1
  123. package/dist/esm/core/pause.js.map +1 -1
  124. package/dist/esm/core/runCheckpoint.js +26 -2
  125. package/dist/esm/core/runCheckpoint.js.map +1 -1
  126. package/dist/esm/events/payloads.d.ts +76 -1
  127. package/dist/esm/index.d.ts +2 -2
  128. package/dist/esm/index.js.map +1 -1
  129. package/dist/esm/lib/bug-report/transcript.d.ts +5 -0
  130. package/dist/esm/lib/bug-report/transcript.js +1 -0
  131. package/dist/esm/lib/bug-report/transcript.js.map +1 -1
  132. package/dist/esm/lib/semantics/projection.js +1 -0
  133. package/dist/esm/lib/semantics/projection.js.map +1 -1
  134. package/dist/esm/lib/time-travel/receipt.d.ts +4 -3
  135. package/dist/esm/lib/time-travel/receipt.js +4 -3
  136. package/dist/esm/lib/time-travel/receipt.js.map +1 -1
  137. package/dist/esm/lib/time-travel/servedView.js +13 -9
  138. package/dist/esm/lib/time-travel/servedView.js.map +1 -1
  139. package/dist/esm/lib/trace-toolpack/traceToolpack.js +130 -17
  140. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  141. package/dist/esm/memory/causal/evidenceRecorder.d.ts +2 -0
  142. package/dist/esm/memory/causal/evidenceRecorder.js +13 -0
  143. package/dist/esm/memory/causal/evidenceRecorder.js.map +1 -1
  144. package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.d.ts +2 -0
  145. package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.js +11 -0
  146. package/dist/esm/recorders/observability/AgentThinkingTraceRecorder.js.map +1 -1
  147. package/dist/esm/recorders/observability/BoundaryRecorder.d.ts +10 -1
  148. package/dist/esm/recorders/observability/BoundaryRecorder.js +9 -1
  149. package/dist/esm/recorders/observability/BoundaryRecorder.js.map +1 -1
  150. package/dist/esm/recorders/observability/FlowchartRecorder.d.ts +4 -1
  151. package/dist/esm/recorders/observability/FlowchartRecorder.js +13 -1
  152. package/dist/esm/recorders/observability/FlowchartRecorder.js.map +1 -1
  153. package/dist/esm/recorders/observability/LiveStateRecorder.d.ts +2 -0
  154. package/dist/esm/recorders/observability/LiveStateRecorder.js +9 -0
  155. package/dist/esm/recorders/observability/LiveStateRecorder.js.map +1 -1
  156. package/dist/esm/recorders/observability/RouteRecorder.js +5 -0
  157. package/dist/esm/recorders/observability/RouteRecorder.js.map +1 -1
  158. package/dist/esm/recorders/observability/StatusRecorder.js +7 -0
  159. package/dist/esm/recorders/observability/StatusRecorder.js.map +1 -1
  160. package/dist/esm/recorders/observability/ToolChoiceRecorder.js +5 -0
  161. package/dist/esm/recorders/observability/ToolChoiceRecorder.js.map +1 -1
  162. package/dist/esm/recorders/observability/commentary/commentaryTemplates.js +18 -2
  163. package/dist/esm/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
  164. package/dist/esm/recorders/observability/status/statusTemplates.js +5 -0
  165. package/dist/esm/recorders/observability/status/statusTemplates.js.map +1 -1
  166. package/dist/esm/security/extractSequence.d.ts +36 -5
  167. package/dist/esm/security/extractSequence.js +99 -26
  168. package/dist/esm/security/extractSequence.js.map +1 -1
  169. package/dist/index.js.map +1 -1
  170. package/dist/lib/bug-report/transcript.js +1 -0
  171. package/dist/lib/bug-report/transcript.js.map +1 -1
  172. package/dist/lib/semantics/projection.js +1 -0
  173. package/dist/lib/semantics/projection.js.map +1 -1
  174. package/dist/lib/time-travel/receipt.js +4 -3
  175. package/dist/lib/time-travel/receipt.js.map +1 -1
  176. package/dist/lib/time-travel/servedView.js +13 -9
  177. package/dist/lib/time-travel/servedView.js.map +1 -1
  178. package/dist/lib/trace-toolpack/traceToolpack.js +130 -17
  179. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  180. package/dist/memory/causal/evidenceRecorder.js +13 -0
  181. package/dist/memory/causal/evidenceRecorder.js.map +1 -1
  182. package/dist/recorders/observability/AgentThinkingTraceRecorder.js +11 -0
  183. package/dist/recorders/observability/AgentThinkingTraceRecorder.js.map +1 -1
  184. package/dist/recorders/observability/BoundaryRecorder.js +9 -1
  185. package/dist/recorders/observability/BoundaryRecorder.js.map +1 -1
  186. package/dist/recorders/observability/FlowchartRecorder.js +13 -1
  187. package/dist/recorders/observability/FlowchartRecorder.js.map +1 -1
  188. package/dist/recorders/observability/LiveStateRecorder.js +9 -0
  189. package/dist/recorders/observability/LiveStateRecorder.js.map +1 -1
  190. package/dist/recorders/observability/RouteRecorder.js +5 -0
  191. package/dist/recorders/observability/RouteRecorder.js.map +1 -1
  192. package/dist/recorders/observability/StatusRecorder.js +7 -0
  193. package/dist/recorders/observability/StatusRecorder.js.map +1 -1
  194. package/dist/recorders/observability/ToolChoiceRecorder.js +5 -0
  195. package/dist/recorders/observability/ToolChoiceRecorder.js.map +1 -1
  196. package/dist/recorders/observability/commentary/commentaryTemplates.js +18 -2
  197. package/dist/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
  198. package/dist/recorders/observability/status/statusTemplates.js +5 -0
  199. package/dist/recorders/observability/status/statusTemplates.js.map +1 -1
  200. package/dist/security/extractSequence.js +99 -26
  201. package/dist/security/extractSequence.js.map +1 -1
  202. package/dist/types/adapters/observability/audit.d.ts +8 -0
  203. package/dist/types/adapters/observability/audit.d.ts.map +1 -1
  204. package/dist/types/adapters/observability/otel.d.ts +17 -2
  205. package/dist/types/adapters/observability/otel.d.ts.map +1 -1
  206. package/dist/types/adapters/observability/xray.d.ts +8 -0
  207. package/dist/types/adapters/observability/xray.d.ts.map +1 -1
  208. package/dist/types/adapters/types.d.ts +49 -0
  209. package/dist/types/adapters/types.d.ts.map +1 -1
  210. package/dist/types/core/Agent.d.ts.map +1 -1
  211. package/dist/types/core/agent/composeRequest.d.ts +10 -7
  212. package/dist/types/core/agent/composeRequest.d.ts.map +1 -1
  213. package/dist/types/core/agent/coverage/absent.d.ts +31 -4
  214. package/dist/types/core/agent/coverage/absent.d.ts.map +1 -1
  215. package/dist/types/core/agent/coverage/answer.d.ts.map +1 -1
  216. package/dist/types/core/agent/coverage/index.d.ts +1 -1
  217. package/dist/types/core/agent/coverage/index.d.ts.map +1 -1
  218. package/dist/types/core/agent/coverage/read.d.ts +12 -2
  219. package/dist/types/core/agent/coverage/read.d.ts.map +1 -1
  220. package/dist/types/core/agent/coverage/types.d.ts +42 -0
  221. package/dist/types/core/agent/coverage/types.d.ts.map +1 -1
  222. package/dist/types/core/agent/findings/ledger.d.ts +23 -6
  223. package/dist/types/core/agent/findings/ledger.d.ts.map +1 -1
  224. package/dist/types/core/agent/findings/offer.d.ts +23 -6
  225. package/dist/types/core/agent/findings/offer.d.ts.map +1 -1
  226. package/dist/types/core/agent/findings/serve.d.ts +19 -6
  227. package/dist/types/core/agent/findings/serve.d.ts.map +1 -1
  228. package/dist/types/core/agent/findings/types.d.ts +81 -1
  229. package/dist/types/core/agent/findings/types.d.ts.map +1 -1
  230. package/dist/types/core/agent/findings/unsettled.d.ts +129 -0
  231. package/dist/types/core/agent/findings/unsettled.d.ts.map +1 -0
  232. package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
  233. package/dist/types/core/agent/stages/route.d.ts.map +1 -1
  234. package/dist/types/core/agent/stages/toolCalls.d.ts +90 -2
  235. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  236. package/dist/types/core/agent/stages/window.d.ts.map +1 -1
  237. package/dist/types/core/agent/toolDispatch.d.ts +4 -1
  238. package/dist/types/core/agent/toolDispatch.d.ts.map +1 -1
  239. package/dist/types/core/agent/toolResultCap.d.ts +4 -1
  240. package/dist/types/core/agent/toolResultCap.d.ts.map +1 -1
  241. package/dist/types/core/agent/types.d.ts +5 -0
  242. package/dist/types/core/agent/types.d.ts.map +1 -1
  243. package/dist/types/core/agent/window/ledgerFactPins.d.ts +10 -1
  244. package/dist/types/core/agent/window/ledgerFactPins.d.ts.map +1 -1
  245. package/dist/types/core/agent/window/strategy.d.ts +2 -1
  246. package/dist/types/core/agent/window/strategy.d.ts.map +1 -1
  247. package/dist/types/core/agent/window/toolNames.d.ts +16 -1
  248. package/dist/types/core/agent/window/toolNames.d.ts.map +1 -1
  249. package/dist/types/core/checkin.d.ts.map +1 -1
  250. package/dist/types/core/inputRequest.d.ts +20 -1
  251. package/dist/types/core/inputRequest.d.ts.map +1 -1
  252. package/dist/types/core/pause.d.ts +13 -1
  253. package/dist/types/core/pause.d.ts.map +1 -1
  254. package/dist/types/core/runCheckpoint.d.ts.map +1 -1
  255. package/dist/types/events/payloads.d.ts +76 -1
  256. package/dist/types/events/payloads.d.ts.map +1 -1
  257. package/dist/types/index.d.ts +2 -2
  258. package/dist/types/index.d.ts.map +1 -1
  259. package/dist/types/lib/bug-report/transcript.d.ts +5 -0
  260. package/dist/types/lib/bug-report/transcript.d.ts.map +1 -1
  261. package/dist/types/lib/semantics/projection.d.ts.map +1 -1
  262. package/dist/types/lib/time-travel/receipt.d.ts +4 -3
  263. package/dist/types/lib/time-travel/receipt.d.ts.map +1 -1
  264. package/dist/types/lib/time-travel/servedView.d.ts.map +1 -1
  265. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  266. package/dist/types/memory/causal/evidenceRecorder.d.ts +2 -0
  267. package/dist/types/memory/causal/evidenceRecorder.d.ts.map +1 -1
  268. package/dist/types/recorders/observability/AgentThinkingTraceRecorder.d.ts +2 -0
  269. package/dist/types/recorders/observability/AgentThinkingTraceRecorder.d.ts.map +1 -1
  270. package/dist/types/recorders/observability/BoundaryRecorder.d.ts +10 -1
  271. package/dist/types/recorders/observability/BoundaryRecorder.d.ts.map +1 -1
  272. package/dist/types/recorders/observability/FlowchartRecorder.d.ts +4 -1
  273. package/dist/types/recorders/observability/FlowchartRecorder.d.ts.map +1 -1
  274. package/dist/types/recorders/observability/LiveStateRecorder.d.ts +2 -0
  275. package/dist/types/recorders/observability/LiveStateRecorder.d.ts.map +1 -1
  276. package/dist/types/recorders/observability/RouteRecorder.d.ts.map +1 -1
  277. package/dist/types/recorders/observability/ToolChoiceRecorder.d.ts.map +1 -1
  278. package/dist/types/recorders/observability/commentary/commentaryTemplates.d.ts.map +1 -1
  279. package/dist/types/recorders/observability/status/statusTemplates.d.ts.map +1 -1
  280. package/dist/types/security/extractSequence.d.ts +36 -5
  281. package/dist/types/security/extractSequence.d.ts.map +1 -1
  282. package/package.json +1 -1
@@ -10,7 +10,10 @@
10
10
  * payload so footprintjs captures a checkpoint.
11
11
  * • `resume` runs after the consumer supplies the human's answer.
12
12
  * Treats that answer as the paused tool's result, appends to
13
- * history, then continues the ReAct iteration loop.
13
+ * history, then continues the ReAct iteration loop. Calls the model
14
+ * batched AFTER the paused one were never dispatched; every resume
15
+ * path settles them with one fixed sentence each, a bracket and a
16
+ * count, and runs none of them ("── The batch settlement (9.113.0)").
14
17
  *
15
18
  * Dispatch resolution order (9.92.0 — DISPATCH FOLLOWS THE OFFER):
16
19
  * 0. A name on THIS epoch's wire resolves to the party whose contract the
@@ -71,7 +74,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
71
74
  return result;
72
75
  };
73
76
  Object.defineProperty(exports, "__esModule", { value: true });
74
- exports.buildToolCallsHandler = exports.composeReadSkillRefusal = exports.unknownToolResult = exports.notServedResult = exports.atMountedCursor = void 0;
77
+ exports.buildToolCallsHandler = exports.producerCorpusOf = exports.notDispatchedResult = exports.pausedBatchOf = exports.composeReadSkillRefusal = exports.unknownToolResult = exports.notServedResult = exports.atMountedCursor = void 0;
75
78
  const codeRunnerTool_js_1 = require("../../codeRunnerTool.js");
76
79
  const footprintjs_1 = require("footprintjs");
77
80
  const types_js_1 = require("../../../adapters/types.js");
@@ -101,6 +104,7 @@ const reserved_js_1 = require("../findings/reserved.js");
101
104
  const offer_js_1 = require("../findings/offer.js");
102
105
  const ledger_js_2 = require("../findings/ledger.js");
103
106
  const contingent_js_1 = require("../findings/contingent.js");
107
+ const unsettled_js_1 = require("../findings/unsettled.js");
104
108
  const evidenceIndex_js_1 = require("../evidence/evidenceIndex.js");
105
109
  const repeatedCall_js_1 = require("../repeatedCall.js");
106
110
  const toolArgsValidation_js_1 = require("../toolArgsValidation.js");
@@ -478,6 +482,130 @@ function argsForPausedCall(scope, toolCallId, peel = false) {
478
482
  function appendBatchResult(scope, entry) {
479
483
  scope.toolResults = [...(scope.toolResults ?? []), entry];
480
484
  }
485
+ /**
486
+ * THE PAUSED BATCH (9.113.0) — the turn that proposed the paused call, and
487
+ * the calls on it that a pause left un-dispatched.
488
+ *
489
+ * The batch loop in `execute` dispatches a turn's calls one at a time, in the
490
+ * order the model proposed them, and every pause RETURNS from inside it: the
491
+ * checkpoint is taken on call k, and calls k+1..N were never reached — no
492
+ * gate judged them, no tool ran, no bracket opened. The resume paths used to
493
+ * answer call k and stop, so the next request carried N `tool_use` blocks and
494
+ * fewer `tool_result`s (a provider builds results only from `role: 'tool'`
495
+ * messages), and `iteration_end` counted one call.
496
+ *
497
+ * READ FROM `history`, NEVER CARRIED. Every pause site commits
498
+ * `scope.history = newHistory` before it returns, so the assistant turn that
499
+ * proposed the batch is on the checkpoint — and it is the very message a
500
+ * provider turns into the `tool_use` blocks the settlement must answer. It is
501
+ * therefore the one owner of "which calls does the next request carry", and
502
+ * the checkpoint gains no key: a checkpoint written before this release
503
+ * settles the same way. The window never removes the turn holding the paused
504
+ * call (`../window/turns.ts` · `refusalFor`, its `paused-tool` arm).
505
+ *
506
+ * The LATEST turn proposing the id is the paused one — the pause site commits
507
+ * that turn last, and a provider may reuse an id across turns. No such turn:
508
+ * `size: 0` and nothing to settle, the only answer a missing turn supports.
509
+ *
510
+ * A call after the paused one that history ALREADY answers — a `role: 'tool'`
511
+ * message for its id after that turn — is not un-dispatched, whoever wrote
512
+ * the answer. No library door writes one before the resume; a checkpoint is
513
+ * data, though, and an app may have patched results into a stored one.
514
+ * Settling such a call again would put a second result for its id on the
515
+ * next request, a shape a provider rejects.
516
+ */
517
+ function pausedBatchOf(history, pausedToolCallId) {
518
+ for (let i = history.length - 1; i >= 0; i--) {
519
+ const message = history[i];
520
+ if (message?.role !== 'assistant')
521
+ continue;
522
+ const proposed = message.toolCalls ?? [];
523
+ const at = proposed.findIndex((call) => call.id === pausedToolCallId);
524
+ if (at < 0)
525
+ continue;
526
+ const answered = new Set(history.slice(i + 1).flatMap((m) => (m.role === 'tool' ? [m.toolCallId] : [])));
527
+ return {
528
+ size: proposed.length,
529
+ undispatched: proposed.slice(at + 1).filter((call) => !answered.has(call.id)),
530
+ };
531
+ }
532
+ return { size: 0, undispatched: [] };
533
+ }
534
+ exports.pausedBatchOf = pausedBatchOf;
535
+ // LENS · tool-result · persistent-history
536
+ // reads: toolName ← the un-dispatched call on the paused turn (`pausedBatchOf`); paused ← scope.pausedToolName + scope.pausedToolCallId, the checkpoint's own carriers
537
+ // law: may omit, never deny; every clause anchored to the call it was composed on; names no destination.
538
+ /**
539
+ * What a call the paused batch never dispatched gets back (9.113.0) — ONE
540
+ * fixed sentence, on all four resume paths.
541
+ *
542
+ * Every clause is a past fact about one finished event, anchored by name: the
543
+ * call this result answers ("that call"), the call the run paused on (by id
544
+ * and by tool), and the resume. It names no destination. The design page's draft
545
+ * (`docs/design/2026-09-honest-answer-ledger.md`, § 5.5, "The batch
546
+ * settlement") ended "propose it again if still needed" — an instruction about a LATER call,
547
+ * re-read on every call after this one, the tool-less wrap-up included.
548
+ * Whether the call is still needed is the model's to judge from the facts;
549
+ * the surfaces recomposed per request (the tool list, the system prompt) own
550
+ * the present tense. Precedents: the 9.86.1 resumed-call refusal in this file
551
+ * ("was not executed on that call, and the resumed dispatch had no second
552
+ * checkpoint…") and `../selfCallNotice.ts` · `selfCallNotice`.
553
+ *
554
+ * "The run paused ON call …", never "call … paused the run": on two of the
555
+ * four doors the pause was a gate's, not the call's — a middleware's `ask`, a
556
+ * credential's consent need — and on all four the run paused AT that call.
557
+ *
558
+ * The sentence is for the MODEL. The same fact as data rides the settled
559
+ * message as `LLMMessage.notDispatched` and both of its brackets as
560
+ * `notDispatched` (`notDispatchedMarker`), and a reader asking "did this call
561
+ * run?" reads that — never this text.
562
+ *
563
+ * Exported for the producer registry (`test/modelFacingSurfaces.test.ts`).
564
+ */
565
+ function notDispatchedResult(toolName, paused) {
566
+ return (`Tool '${toolName}' was not executed on that call: the run paused on call ` +
567
+ `'${paused.toolCallId}' to '${paused.toolName}', earlier in the same batch, and resumed ` +
568
+ `without executing the calls that followed it in that batch.`);
569
+ }
570
+ exports.notDispatchedResult = notDispatchedResult;
571
+ /**
572
+ * The same fact as DATA (9.113.0) — the ONE composer of the settlement's
573
+ * marker, `{ pausedCall: { toolCallId, toolName } }`. The settled call's
574
+ * history message (`LLMMessage.notDispatched`) and both of its brackets
575
+ * (`ToolStartPayload.notDispatched`, `ToolEndPayload.notDispatched`) each take
576
+ * a fresh copy from here, so the three carriers can never disagree and no
577
+ * reader holds an object another reader holds.
578
+ */
579
+ function notDispatchedMarker(paused) {
580
+ return { pausedCall: { toolCallId: paused.toolCallId, toolName: paused.toolName } };
581
+ }
582
+ /**
583
+ * The empty-lookup check's PRODUCER CORPUS (9.77.0) — every `role: 'tool'`
584
+ * RESULT in `history` from a tool the judged one names in `argumentsFrom`,
585
+ * as the run served it. The caller hands the history the judged call was
586
+ * served (the call itself is pushed after it), so a producer called earlier in
587
+ * the same batch is already in it — which is right: the model can only have
588
+ * taken a value from a result it had already been served.
589
+ *
590
+ * A message the batch settlement wrote (9.113.0) is no result: its ground
591
+ * never ran, so it produced nothing to take a value from. Read off the marker
592
+ * (`../findings/offer.ts` · `isResultMessage`), never the sentence.
593
+ *
594
+ * Exported for its unit test (`test/integrity/emptyLookup.test.ts`).
595
+ */
596
+ function producerCorpusOf(history, argumentsFrom) {
597
+ const produced = [];
598
+ for (const message of history) {
599
+ if (!(0, offer_js_1.isResultMessage)(message))
600
+ continue;
601
+ const name = message.toolName;
602
+ if (typeof name !== 'string' || !argumentsFrom.includes(name))
603
+ continue;
604
+ produced.push({ toolName: name, text: message.content });
605
+ }
606
+ return produced;
607
+ }
608
+ exports.producerCorpusOf = producerCorpusOf;
481
609
  /**
482
610
  * The judge's turn on ONE landed result (9.104.0) — called at the five
483
611
  * places a result joins the batch (the execute loop and the four resume
@@ -740,6 +868,13 @@ function buildToolCallsHandler(deps) {
740
868
  checked,
741
869
  ...(notChecked.length > 0 && { notChecked }),
742
870
  ...(cannotCover.length > 0 && { cannotCover }),
871
+ // The suggestion, as declared (9.113.0): the sentence, and the
872
+ // typed tool as a copy (`tryInsteadToolOfAbsence`). The EVENT only:
873
+ // it is advice about a call not yet made, not ground the answer
874
+ // stands on, so the tracked row below and the block composed from
875
+ // it never carry it.
876
+ ...(facts.tryInstead !== undefined && { tryInstead: facts.tryInstead }),
877
+ ...(facts.tryInsteadTool !== undefined && { tryInsteadTool: facts.tryInsteadTool }),
743
878
  });
744
879
  }
745
880
  else {
@@ -807,20 +942,9 @@ function buildToolCallsHandler(deps) {
807
942
  ledger?.note('empty-lookup', 'write', 'not-applicable');
808
943
  return;
809
944
  }
810
- // The producer corpus: every earlier `role: 'tool'` message from a tool
811
- // THIS tool declares as one of its grounds. `history` here excludes the
812
- // call being judged (it is pushed after), and a producer called earlier
813
- // in the same batch is already in it — which is right: the model can only
814
- // have taken a value from a result it had already been served.
815
- const produced = [];
816
- for (const message of history) {
817
- if (message.role !== 'tool')
818
- continue;
819
- const name = message.toolName;
820
- if (typeof name !== 'string' || !argumentsFrom.includes(name))
821
- continue;
822
- produced.push({ toolName: name, text: message.content });
823
- }
945
+ // The producer corpus: the earlier RESULTS from a tool THIS tool declares
946
+ // as one of its grounds — never a settled message (`producerCorpusOf`).
947
+ const produced = producerCorpusOf(history, argumentsFrom);
824
948
  const { findings, disposition } = (0, check_js_1.emptyLookupOf)({
825
949
  toolName: call.toolName,
826
950
  toolCallId: call.toolCallId,
@@ -835,6 +959,45 @@ function buildToolCallsHandler(deps) {
835
959
  ledger?.note('empty-lookup', 'write', disposition, disposition === 'checked-fail' ? Date.now() : undefined);
836
960
  (0, integrityFindings_js_1.fileIntegrityFindings)(scope, findings, call.iteration);
837
961
  };
962
+ /**
963
+ * A lookup that pauses still declares what it looked at (9.114.0) — the
964
+ * RAISE-SITE reader of `InputRequestDeclaration.absence`.
965
+ *
966
+ * A tool that found nothing and raised `requestInput` about the miss used
967
+ * to leave no record of it: `declareCoverage` reads a RETURNED value, and
968
+ * the pause branch returns the checkpoint before any of its call sites.
969
+ * The app could not file it either — the declaration's `context` rides to
970
+ * the model on resume, never to the record. So the raise site files it,
971
+ * through the same two readers a returned absence meets: `declareCoverage`
972
+ * (the one recognizer, `tools.absent`, the `coverageDeclared` row — the
973
+ * bytes a returned `absent(…)` files) and the empty-lookup write seam, with
974
+ * the envelope as the tool's own answer — it ran, nothing errored, nothing
975
+ * denied it, and no ceiling judged a result the model was never served.
976
+ *
977
+ * The delivered status `declareCoverage` returns is dropped on purpose: a
978
+ * paused call is not settled, so there is no `tool_end` for it to ride.
979
+ * Nothing on resume reads the field (the served result there is the
980
+ * person's `InputResponseResult`), so the rows are filed once, here.
981
+ *
982
+ * CONTAINED the way the returned path contains it. The recognizer reads an
983
+ * envelope minted elsewhere without repairing it, so its lists can be
984
+ * something `declareCoverage` cannot copy (`checked: [null]`,
985
+ * `not_checked: 5`). Returned, that throw lands in the dispatch `try` and
986
+ * errors the call; here it would land in the `catch` and fail the run. So
987
+ * the copy is caught here instead, and the error text comes back: the
988
+ * caller errors the call with it and does not pause. That is what the same
989
+ * value returned would do. `undefined` means filed.
990
+ */
991
+ const declareRaisedAbsence = (scope, call, args, absence, history) => {
992
+ try {
993
+ declareCoverage(scope, call, absence);
994
+ }
995
+ catch (err) {
996
+ return err instanceof Error ? err.message : String(err);
997
+ }
998
+ noticeEmptyLookup(scope, call, args, absence, history, true);
999
+ return undefined;
1000
+ };
838
1001
  /**
839
1002
  * The semantic envelope (9.53.0) — recognized at the SAME execute
840
1003
  * boundaries as coverage and the ceiling (one implementation, every door),
@@ -2029,6 +2192,68 @@ function buildToolCallsHandler(deps) {
2029
2192
  (0, ledger_js_1.recordDecisions)(scope, verdict.decisions);
2030
2193
  return verdict.kind === 'deny' ? verdict.reason : verdict.result;
2031
2194
  };
2195
+ const settleBatch = (answered, paused) => {
2196
+ const batch = pausedBatchOf(answered, paused.toolCallId);
2197
+ if (batch.undispatched.length === 0)
2198
+ return { history: answered, settled: [], size: batch.size, paused };
2199
+ const settled = batch.undispatched.map((call) => ({
2200
+ call,
2201
+ result: notDispatchedResult(call.name, paused),
2202
+ }));
2203
+ return {
2204
+ history: [
2205
+ ...answered,
2206
+ ...settled.map(({ call, result }) => ({
2207
+ role: 'tool',
2208
+ content: result,
2209
+ toolCallId: call.id,
2210
+ toolName: call.name,
2211
+ notDispatched: notDispatchedMarker(paused),
2212
+ })),
2213
+ ],
2214
+ settled,
2215
+ size: batch.size,
2216
+ paused,
2217
+ };
2218
+ };
2219
+ /**
2220
+ * Each settled sibling's bracket, after the paused call's own `tool_end` —
2221
+ * the ONE site that stamps `notDispatched` on the stream: `tool_start` with
2222
+ * the args the call would have run with (the batch loop's peel, so
2223
+ * `_findings` never shows on a bracket), then `tool_end` carrying the
2224
+ * sentence and `durationMs: 0`. Both carry the marker the history message
2225
+ * carries (`notDispatchedMarker`), and no other bracket in the library ever
2226
+ * does.
2227
+ *
2228
+ * No `error`. It says a call FAILED — the tool threw, or the call itself
2229
+ * could not run as written (an args rejection, a `wants` block, a consent
2230
+ * the tool needed and did not get, an unknown name). A settled call did not
2231
+ * fail: the library decided not to dispatch it, as it does for a call a
2232
+ * permission policy denies or halts, and those brackets carry no `error`
2233
+ * either. Stamped here, it would register a tool failure in every
2234
+ * error-rate reader (a span status, a dashboard, an alert) on every
2235
+ * mid-batch pause, and say a second, false thing beside the marker, which
2236
+ * is the one owner of why there is no result (`src/core/README.md` · "One
2237
+ * owner of 'never dispatched' — in history and on the stream", the reader
2238
+ * table). No `status` either: that field is the TOOL's own word.
2239
+ */
2240
+ const bracketSettled = (scope, settlement) => {
2241
+ for (const { call, result } of settlement.settled) {
2242
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.tool_start', {
2243
+ toolName: call.name,
2244
+ toolCallId: call.id,
2245
+ args: peelCall(call).args,
2246
+ parallelCount: settlement.size,
2247
+ notDispatched: notDispatchedMarker(settlement.paused),
2248
+ });
2249
+ (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.stream.tool_end', {
2250
+ toolCallId: call.id,
2251
+ result,
2252
+ durationMs: 0,
2253
+ notDispatched: notDispatchedMarker(settlement.paused),
2254
+ });
2255
+ }
2256
+ };
2032
2257
  // Resolve a tool's declared credential (declare-and-push) and execute it,
2033
2258
  // emitting the same credential.* events as the main loop. Used by the
2034
2259
  // check-in RESUME path when a human APPROVES — the tool never ran at pause
@@ -2354,15 +2579,24 @@ function buildToolCallsHandler(deps) {
2354
2579
  // came from (9.102.0; before, only the last batch resolved and an
2355
2580
  // offered older id filed as `unknownId`). Read through the same
2356
2581
  // per-call peel the loop below applies (a tool that owns the name
2357
- // declares nothing). Gated: unarmed, not one line runs.
2582
+ // declares nothing). A ruled-out standing whose result THIS door
2583
+ // recorded as an absence (`declareCoverage`'s rows on
2584
+ // `coverageDeclared`, never a second reading of a return) AND the
2585
+ // model was served as one (the served string — the door records the
2586
+ // return before the after-tool chain, the ceiling and placement act,
2587
+ // so a denied, refused or ticketed result files nothing) gets its
2588
+ // `unsettled-by-absence` row immediately after it, in the same write,
2589
+ // worded from what was served (9.113.0, `findings/unsettled.ts`; the
2590
+ // key is read only for such a standing); the standing rows pass
2591
+ // through untouched. Gated: unarmed, not one line runs.
2358
2592
  if (deps.findings === true) {
2359
2593
  const known = (0, offer_js_1.knownResults)([...(scope.history ?? [])], [...(scope.toolResults ?? [])]);
2360
- (0, ledger_js_2.recordFindings)(scope, toolCalls.flatMap((tc) => {
2594
+ (0, ledger_js_2.recordFindings)(scope, (0, unsettled_js_1.withUnsettledRows)(toolCalls.flatMap((tc) => {
2361
2595
  const declared = peelCall(tc).findings;
2362
2596
  return declared?.previous !== undefined
2363
2597
  ? (0, ledger_js_2.standingRowsFrom)(known, declared, { toolCallId: tc.id }, iteration)
2364
2598
  : [];
2365
- }));
2599
+ }), known, () => [...(scope.coverageDeclared ?? [])]));
2366
2600
  }
2367
2601
  scope.toolResults = [];
2368
2602
  // ── THE TOWERS AT DISPATCH (9.110.0) — one corpus per batch ────────
@@ -3095,6 +3329,9 @@ function buildToolCallsHandler(deps) {
3095
3329
  await endCall(tc.id);
3096
3330
  }
3097
3331
  catch (err) {
3332
+ // Set when a raise declared a miss the door could not file:
3333
+ // the call then errors with this text and does not pause.
3334
+ let raisedMissError;
3098
3335
  if ((0, pause_js_1.isPauseRequest)(err)) {
3099
3336
  // The typed half of the question (9.24.0): a tool that raised
3100
3337
  // `askHuman({ question, component })` nominated a screen
@@ -3112,51 +3349,90 @@ function buildToolCallsHandler(deps) {
3112
3349
  await assertComponentDeliverable(scope, tc.name, rawComponent, `askHuman in tool '${tc.name}'`);
3113
3350
  }
3114
3351
  }
3115
- // A pause has NOT settled this call — it is waiting for a
3116
- // person, and the resources it opened are what the resume
3117
- // needs. No `'call'` teardown here, deliberately.
3118
- //
3119
- // Commit partial state so resume() can find history intact.
3120
- scope.history = newHistory;
3121
- scope.pausedToolCallId = tc.id;
3122
- scope.pausedToolName = tc.name;
3123
- scope.pausedToolStartMs = startMs;
3124
- // The args the tool WAS RUNNING WITH (post-transform), for the
3125
- // after-tool moment on the far side of the pause (8.13.0) —
3126
- // the same reason the three sibling pauses carry theirs.
3127
- scope.pausedToolArgs = callArgs;
3128
3352
  const declaration = typeof err.data === 'object' && err.data !== null
3129
3353
  ? err.data.inputRequest
3130
3354
  : undefined;
3131
- const awaitingInput = declaration === undefined
3132
- ? undefined
3133
- : (0, inputRequest_js_1.stampInputRequest)((0, inputRequest_js_1.validateInputDeclaration)(declaration), `${deps.currentRun?.().runId ?? scope.turnStartMs}:${tc.id}`, {
3134
- originalRequest: scope.userMessage,
3135
- toolCallId: tc.id,
3136
- ...(scope.currentSkillId !== undefined && {
3137
- skillId: scope.currentSkillId,
3138
- }),
3139
- ...(scope.turnRoute?.offered !== undefined && {
3140
- offeredSkillIds: [...scope.turnRoute.offered],
3141
- }),
3142
- });
3143
- // Returning a defined value triggers footprintjs pause —
3144
- // the returned object becomes the checkpoint's pauseData.
3145
- return {
3146
- toolCallId: tc.id,
3147
- toolName: tc.name,
3148
- ...(awaitingInput !== undefined
3149
- ? { question: awaitingInput.question, awaitingInput }
3150
- : typeof err.data === 'object' && err.data !== null
3151
- ? err.data
3152
- : { data: err.data }),
3355
+ // A lookup that pauses still declares what it looked at
3356
+ // (9.114.0): the miss it is asking about is filed HERE, the
3357
+ // raise site, FIRST — the one moment the declaration's
3358
+ // `absence` is read. So a declaration that CARRIES one is
3359
+ // judged before anything is written for the pause, and a miss
3360
+ // the door cannot file errors the call below, as the same value
3361
+ // returned would, with nothing written for a pause. A MALFORMED
3362
+ // declaration still leaves the committed record it always left,
3363
+ // whether or not it carried `absence`: its error leaves the
3364
+ // stage only after the pause writes are made, so a hand-raised
3365
+ // request (a `pauseHere`/`askHuman` that never went through
3366
+ // `requestInput`) fails with the in-flight batch on the record.
3367
+ // `null` is the field omitted (`inputRequest.ts` ·
3368
+ // `validateInputDeclaration`).
3369
+ //
3370
+ // The pause writes: partial state, so resume() can find the
3371
+ // history intact.
3372
+ const writePause = () => {
3373
+ scope.history = newHistory;
3374
+ scope.pausedToolCallId = tc.id;
3375
+ scope.pausedToolName = tc.name;
3376
+ scope.pausedToolStartMs = startMs;
3377
+ // The args the tool WAS RUNNING WITH (post-transform), for
3378
+ // the after-tool moment on the far side of the pause
3379
+ // (8.13.0) — the same reason the three sibling pauses carry
3380
+ // theirs.
3381
+ scope.pausedToolArgs = callArgs;
3153
3382
  };
3383
+ const carriesAbsence = typeof declaration === 'object' &&
3384
+ declaration !== null &&
3385
+ declaration.absence != null;
3386
+ let declared;
3387
+ if (carriesAbsence) {
3388
+ try {
3389
+ declared = (0, inputRequest_js_1.validateInputDeclaration)(declaration);
3390
+ }
3391
+ catch (invalid) {
3392
+ writePause();
3393
+ throw invalid;
3394
+ }
3395
+ }
3396
+ raisedMissError =
3397
+ declared?.absence === undefined
3398
+ ? undefined
3399
+ : declareRaisedAbsence(scope, { toolName: tc.name, toolCallId: tc.id, iteration }, callArgs, declared.absence, newHistory);
3400
+ if (raisedMissError === undefined) {
3401
+ // A pause has NOT settled this call — it is waiting for a
3402
+ // person, and the resources it opened are what the resume
3403
+ // needs. No `'call'` teardown here, deliberately.
3404
+ writePause();
3405
+ const awaitingInput = declaration === undefined
3406
+ ? undefined
3407
+ : (0, inputRequest_js_1.stampInputRequest)(declared ?? (0, inputRequest_js_1.validateInputDeclaration)(declaration), `${deps.currentRun?.().runId ?? scope.turnStartMs}:${tc.id}`, {
3408
+ originalRequest: scope.userMessage,
3409
+ toolCallId: tc.id,
3410
+ ...(scope.currentSkillId !== undefined && {
3411
+ skillId: scope.currentSkillId,
3412
+ }),
3413
+ ...(scope.turnRoute?.offered !== undefined && {
3414
+ offeredSkillIds: [...scope.turnRoute.offered],
3415
+ }),
3416
+ });
3417
+ // Returning a defined value triggers footprintjs pause —
3418
+ // the returned object becomes the checkpoint's pauseData.
3419
+ return {
3420
+ toolCallId: tc.id,
3421
+ toolName: tc.name,
3422
+ ...(awaitingInput !== undefined
3423
+ ? { question: awaitingInput.question, awaitingInput }
3424
+ : typeof err.data === 'object' && err.data !== null
3425
+ ? err.data
3426
+ : { data: err.data }),
3427
+ };
3428
+ }
3154
3429
  }
3155
3430
  // A tool that threw still RAN, and may have opened the thing it
3156
- // was about to close.
3431
+ // was about to close. A raise whose miss could not be filed is
3432
+ // settled here too — the returned path's error, not a pause.
3157
3433
  await endCall(tc.id);
3158
3434
  error = true;
3159
- result = err instanceof Error ? err.message : String(err);
3435
+ result = raisedMissError ?? (err instanceof Error ? err.message : String(err));
3160
3436
  }
3161
3437
  }
3162
3438
  }
@@ -3934,10 +4210,13 @@ function buildToolCallsHandler(deps) {
3934
4210
  askResultStr += applyToolEffects(scope, { toolName, toolCallId, iteration }, resumeEnvelope, askTransition);
3935
4211
  emitTransitionConflict(scope, iteration, askTransition);
3936
4212
  }
3937
- const askHistory = [
4213
+ // The batch settlement (9.113.0): the answered call's result, then the
4214
+ // siblings the pause left un-dispatched, each settled — never run.
4215
+ const askSettlement = settleBatch([
3938
4216
  ...scope.history,
3939
4217
  { role: 'tool', content: askResultStr, toolCallId, toolName },
3940
- ];
4218
+ ], { toolName, toolCallId });
4219
+ const askHistory = askSettlement.history;
3941
4220
  scope.history = askHistory;
3942
4221
  scope.lastToolResult = {
3943
4222
  toolName,
@@ -3958,10 +4237,14 @@ function buildToolCallsHandler(deps) {
3958
4237
  ...(error === true && { error: true }),
3959
4238
  ...(resumeEnvelope?.status !== undefined && { status: resumeEnvelope.status }),
3960
4239
  });
4240
+ bracketSettled(scope, askSettlement);
3961
4241
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.iteration_end', {
3962
4242
  turnIndex: 0,
3963
4243
  iterIndex: iteration,
3964
- toolCallCount: 1,
4244
+ // The brackets THIS leg closed: the answered call's, plus one per
4245
+ // settled sibling. The calls before the paused one closed theirs on
4246
+ // the leg that paused, which ended in a checkpoint, not here.
4247
+ toolCallCount: 1 + askSettlement.settled.length,
3965
4248
  history: askHistory,
3966
4249
  });
3967
4250
  scope.iteration = iteration + 1;
@@ -4078,10 +4361,12 @@ function buildToolCallsHandler(deps) {
4078
4361
  decisionResultStr += applyToolEffects(scope, { toolName, toolCallId, iteration }, resumeEnvelope, decisionTransition);
4079
4362
  emitTransitionConflict(scope, iteration, decisionTransition);
4080
4363
  }
4081
- const decisionHistory = [
4364
+ // The batch settlement (9.113.0) — the ask path's twin.
4365
+ const decisionSettlement = settleBatch([
4082
4366
  ...scope.history,
4083
4367
  { role: 'tool', content: decisionResultStr, toolCallId, toolName },
4084
- ];
4368
+ ], { toolName, toolCallId });
4369
+ const decisionHistory = decisionSettlement.history;
4085
4370
  scope.history = decisionHistory;
4086
4371
  // Drives `on-tool-return` triggers, same as the execute path.
4087
4372
  scope.lastToolResult = {
@@ -4103,10 +4388,12 @@ function buildToolCallsHandler(deps) {
4103
4388
  ...(error === true && { error: true }),
4104
4389
  ...(resumeEnvelope?.status !== undefined && { status: resumeEnvelope.status }),
4105
4390
  });
4391
+ bracketSettled(scope, decisionSettlement);
4106
4392
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.iteration_end', {
4107
4393
  turnIndex: 0,
4108
4394
  iterIndex: iteration,
4109
- toolCallCount: 1,
4395
+ // The brackets this leg closed — see the ask path's twin.
4396
+ toolCallCount: 1 + decisionSettlement.settled.length,
4110
4397
  history: decisionHistory,
4111
4398
  });
4112
4399
  scope.iteration = iteration + 1;
@@ -4188,10 +4475,12 @@ function buildToolCallsHandler(deps) {
4188
4475
  consentResultStr += applyToolEffects(scope, { toolName, toolCallId, iteration }, consentEnvelope, consentTransition);
4189
4476
  emitTransitionConflict(scope, iteration, consentTransition);
4190
4477
  }
4191
- const consentHistory = [
4478
+ // The batch settlement (9.113.0) — the ask path's twin.
4479
+ const consentSettlement = settleBatch([
4192
4480
  ...scope.history,
4193
4481
  { role: 'tool', content: consentResultStr, toolCallId, toolName },
4194
- ];
4482
+ ], { toolName, toolCallId });
4483
+ const consentHistory = consentSettlement.history;
4195
4484
  scope.history = consentHistory;
4196
4485
  scope.lastToolResult = {
4197
4486
  toolName,
@@ -4212,10 +4501,12 @@ function buildToolCallsHandler(deps) {
4212
4501
  ...(error === true && { error: true }),
4213
4502
  ...(consentEnvelope?.status !== undefined && { status: consentEnvelope.status }),
4214
4503
  });
4504
+ bracketSettled(scope, consentSettlement);
4215
4505
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.iteration_end', {
4216
4506
  turnIndex: 0,
4217
4507
  iterIndex: iteration,
4218
- toolCallCount: 1,
4508
+ // The brackets this leg closed — see the ask path's twin.
4509
+ toolCallCount: 1 + consentSettlement.settled.length,
4219
4510
  history: consentHistory,
4220
4511
  });
4221
4512
  scope.iteration = iteration + 1;
@@ -4293,7 +4584,10 @@ function buildToolCallsHandler(deps) {
4293
4584
  if (deps.stepPlanFor) {
4294
4585
  resultStr += applyStepReturn(scope, { toolName, toolCallId, iteration });
4295
4586
  }
4296
- const newHistory = [
4587
+ // The batch settlement (9.113.0) — the door a `requestInput` answer
4588
+ // comes back through, and the one most likely to meet a batch: a tool
4589
+ // that asks a person mid-lookup, batched with the lookups after it.
4590
+ const pauseSettlement = settleBatch([
4297
4591
  ...scope.history,
4298
4592
  {
4299
4593
  role: 'tool',
@@ -4301,7 +4595,8 @@ function buildToolCallsHandler(deps) {
4301
4595
  toolCallId,
4302
4596
  toolName,
4303
4597
  },
4304
- ];
4598
+ ], { toolName, toolCallId });
4599
+ const newHistory = pauseSettlement.history;
4305
4600
  scope.history = newHistory;
4306
4601
  // Drives `on-tool-return` triggers, same as every other dispatch path.
4307
4602
  scope.lastToolResult = { toolName, result: resultStr };
@@ -4317,10 +4612,12 @@ function buildToolCallsHandler(deps) {
4317
4612
  result: pauseCapped.result,
4318
4613
  durationMs: Date.now() - startMs,
4319
4614
  });
4615
+ bracketSettled(scope, pauseSettlement);
4320
4616
  (0, typedEmit_js_1.typedEmit)(scope, 'agentfootprint.agent.iteration_end', {
4321
4617
  turnIndex: 0,
4322
4618
  iterIndex: iteration,
4323
- toolCallCount: 1,
4619
+ // The brackets this leg closed — see the ask path's twin.
4620
+ toolCallCount: 1 + pauseSettlement.settled.length,
4324
4621
  // Plain local array — see the matching note on the execute path.
4325
4622
  history: newHistory,
4326
4623
  });