@iowarp/clio-coder 0.3.3 → 0.3.6

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 (370) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/CONTRIBUTING.md +7 -7
  3. package/README.md +3 -3
  4. package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
  5. package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
  10. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  11. package/dist/chunk-3BPUFZDL.js +37 -0
  12. package/dist/chunk-43AOLP7E.js +375 -0
  13. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  14. package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
  15. package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
  16. package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
  17. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  18. package/dist/chunk-AOCYTWAV.js +449 -0
  19. package/dist/chunk-CFGTUFWB.js +67 -0
  20. package/dist/chunk-CJUB2JJ2.js +1478 -0
  21. package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
  22. package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
  23. package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
  24. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  25. package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
  26. package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
  27. package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
  28. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  29. package/dist/chunk-FYYLNIL5.js +313 -0
  30. package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
  31. package/dist/chunk-GEYXPTRF.js +613 -0
  32. package/dist/chunk-GOXNB3AO.js +261 -0
  33. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  34. package/dist/chunk-HWUFFB6L.js +83 -0
  35. package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
  36. package/dist/chunk-K7VKOLQQ.js +15 -0
  37. package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
  38. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  39. package/dist/chunk-LCGCVYZ4.js +57 -0
  40. package/dist/chunk-LL4KHSZI.js +22 -0
  41. package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
  42. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  43. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  44. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  45. package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
  46. package/dist/chunk-ODFEOB4F.js +1082 -0
  47. package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
  48. package/dist/chunk-OZNBF4L3.js +23 -0
  49. package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
  50. package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
  51. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  52. package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
  53. package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
  54. package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
  55. package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
  56. package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
  57. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  58. package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
  59. package/dist/chunk-TZSKNMZG.js +434 -0
  60. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  61. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  62. package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
  63. package/dist/chunk-W6GROXXM.js +69 -0
  64. package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
  65. package/dist/chunk-WHJYKASB.js +677 -0
  66. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  67. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  68. package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
  69. package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
  70. package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
  71. package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
  72. package/dist/chunk-ZGVHUX3M.js +66 -0
  73. package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
  74. package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
  75. package/dist/chunk-ZZMN5OM4.js +122 -0
  76. package/dist/cli/index.js +34 -30
  77. package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
  78. package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
  79. package/dist/codewiki/build-worker.js +4 -4
  80. package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
  81. package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
  82. package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
  83. package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
  84. package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
  85. package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
  86. package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
  87. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  88. package/dist/context-working-set-UX5KEP4J.js +1553 -0
  89. package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
  90. package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
  91. package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
  92. package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
  93. package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
  94. package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
  95. package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
  96. package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
  97. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
  98. package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
  99. package/dist/memory-7YKKR6UC.js +467 -0
  100. package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
  101. package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
  102. package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
  103. package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
  104. package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
  105. package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
  106. package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
  107. package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
  108. package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
  109. package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
  110. package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
  111. package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
  112. package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
  113. package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
  114. package/dist/verifiers-NCBTHHN2.js +1220 -0
  115. package/dist/verify-X5HDROLA.js +25 -0
  116. package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
  117. package/dist/worker/entry.js +90 -70
  118. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  119. package/docs/README.md +8 -7
  120. package/docs/acp.md +1 -1
  121. package/docs/alcf-provider.md +1 -1
  122. package/docs/architecture.md +2 -2
  123. package/docs/artifact-placement.md +1 -2
  124. package/docs/artifact-versions.md +1 -1
  125. package/docs/built-in-agents.md +1 -1
  126. package/docs/capacity-and-scheduling.md +1 -1
  127. package/docs/commands-and-modes.md +60 -26
  128. package/docs/config-knobs-audit.md +1 -2
  129. package/docs/configuration-and-targets.md +26 -1
  130. package/docs/context-engine.md +67 -13
  131. package/docs/context-working-set.md +194 -0
  132. package/docs/development-pipeline.md +1 -1
  133. package/docs/documentation-coverage.md +6 -6
  134. package/docs/documentation-guide.md +7 -6
  135. package/docs/environment-variables.md +2 -1
  136. package/docs/eval-runner.md +1 -1
  137. package/docs/evals-internal.md +4 -32
  138. package/docs/evidence-and-memory.md +139 -7
  139. package/docs/evolution.md +1 -1
  140. package/docs/exit-codes-and-output.md +1 -1
  141. package/docs/extensions-and-sharing.md +2 -2
  142. package/docs/fleet-dispatch.md +49 -8
  143. package/docs/glossary.md +21 -1
  144. package/docs/installation-and-lifecycle.md +2 -2
  145. package/docs/middleware-and-components.md +19 -2
  146. package/docs/model-catalog.md +7 -9
  147. package/docs/observability.md +4 -4
  148. package/docs/proactive-memory.md +26 -16
  149. package/docs/prompt-envelope-and-tools.md +7 -5
  150. package/docs/provider-adapter-cookbook.md +1 -1
  151. package/docs/release-cut-checklist.md +43 -40
  152. package/docs/safety-model.md +49 -8
  153. package/docs/scientific-validation.md +21 -3
  154. package/docs/session-lifecycle.md +3 -3
  155. package/docs/skills-marketplace.md +1 -1
  156. package/docs/tool-usage.md +79 -12
  157. package/docs/trace-store.md +1 -1
  158. package/docs/troubleshooting.md +1 -1
  159. package/docs/tui-design.md +38 -4
  160. package/docs/worker-dispatch-mechanics.md +11 -1
  161. package/package.json +13 -13
  162. package/skills/meta/clio-test/SKILL.md +20 -17
  163. package/skills/meta/clio-test/evals.md +3 -3
  164. package/skills/meta/clio-test/references/harness.md +35 -6
  165. package/skills/meta/clio-test/references/test-map.md +20 -10
  166. package/skills/registry.yaml +2 -2
  167. package/skills/skill-marketplace.json +1 -1
  168. package/src/cli/agents.ts +2 -3
  169. package/src/cli/argv.ts +14 -1
  170. package/src/cli/context-working-set.ts +513 -0
  171. package/src/cli/context.ts +8 -0
  172. package/src/cli/evidence.ts +20 -2
  173. package/src/cli/fleet.ts +15 -0
  174. package/src/cli/index.ts +5 -1
  175. package/src/cli/memory.ts +272 -10
  176. package/src/cli/modes/json-stream.ts +2 -2
  177. package/src/cli/modes/print.ts +12 -1
  178. package/src/cli/run.ts +22 -2
  179. package/src/cli/targets.ts +12 -3
  180. package/src/cli/usage.ts +55 -7
  181. package/src/cli/verifiers.ts +325 -0
  182. package/src/core/bash-exec.ts +39 -14
  183. package/src/core/bus-events.ts +22 -4
  184. package/src/core/config.ts +54 -0
  185. package/src/core/defaults.ts +50 -3
  186. package/src/core/response-model-id.ts +134 -0
  187. package/src/core/toml.ts +62 -0
  188. package/src/core/verification-scripts.ts +6 -0
  189. package/src/core/workspace-files.ts +0 -1
  190. package/src/domains/agents/builtins/architect.md +1 -1
  191. package/src/domains/agents/builtins/verifier.md +3 -0
  192. package/src/domains/agents/catalog.ts +5 -4
  193. package/src/domains/agents/recipe.ts +54 -14
  194. package/src/domains/agents/result-contract.ts +7 -4
  195. package/src/domains/config/classify.ts +1 -0
  196. package/src/domains/context/bootstrap.ts +36 -27
  197. package/src/domains/context/project-metadata.ts +19 -63
  198. package/src/domains/context/prompt-context.ts +8 -0
  199. package/src/domains/context/working-set/contract.ts +161 -0
  200. package/src/domains/context/working-set/defaults.ts +28 -0
  201. package/src/domains/context/working-set/engine.ts +203 -0
  202. package/src/domains/context/working-set/fold.ts +62 -0
  203. package/src/domains/context/working-set/horizon.ts +38 -0
  204. package/src/domains/context/working-set/marker.ts +103 -0
  205. package/src/domains/context/working-set/path-index.ts +436 -0
  206. package/src/domains/context/working-set/payload.ts +152 -0
  207. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  208. package/src/domains/context/working-set/policies/index.ts +20 -0
  209. package/src/domains/context/working-set/policies/structural.ts +160 -0
  210. package/src/domains/context/working-set/project.ts +132 -0
  211. package/src/domains/context/working-set/protect.ts +109 -0
  212. package/src/domains/context/working-set/recall.ts +177 -0
  213. package/src/domains/context/working-set/replay/controls.ts +112 -0
  214. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  215. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  216. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  217. package/src/domains/context/working-set/replay/report.ts +139 -0
  218. package/src/domains/context/working-set/replay/runner.ts +325 -0
  219. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  220. package/src/domains/context/working-set/replay/trace.ts +21 -0
  221. package/src/domains/context/working-set/visible.ts +54 -0
  222. package/src/domains/dispatch/budget-envelope.ts +396 -0
  223. package/src/domains/dispatch/contract.ts +2 -0
  224. package/src/domains/dispatch/extension.ts +81 -27
  225. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +4 -0
  227. package/src/domains/dispatch/state.ts +1 -0
  228. package/src/domains/dispatch/types.ts +10 -3
  229. package/src/domains/dispatch/validation.ts +14 -0
  230. package/src/domains/dispatch/worker-spawn.ts +14 -3
  231. package/src/domains/eval/metrics/evidence.ts +0 -116
  232. package/src/domains/eval/metrics/invariants.ts +1 -1
  233. package/src/domains/eval/runners/clio-run.ts +1 -10
  234. package/src/domains/eval/runners/external-command.ts +2 -29
  235. package/src/domains/eval/schema/suite.ts +0 -7
  236. package/src/domains/eval/suites/run.ts +1 -7
  237. package/src/domains/evidence/build.ts +112 -45
  238. package/src/domains/evidence/eval.ts +24 -7
  239. package/src/domains/evidence/index.ts +53 -0
  240. package/src/domains/evidence/ordering.ts +12 -0
  241. package/src/domains/evidence/run-trust.ts +221 -0
  242. package/src/domains/evidence/store.ts +46 -6
  243. package/src/domains/evidence/trust-status.ts +854 -0
  244. package/src/domains/evidence/types.ts +26 -0
  245. package/src/domains/memory/index.ts +22 -0
  246. package/src/domains/memory/operations.ts +58 -1
  247. package/src/domains/memory/promotion.ts +281 -0
  248. package/src/domains/memory/prompt-section.ts +25 -5
  249. package/src/domains/memory/proposal.ts +51 -7
  250. package/src/domains/memory/task-bank.ts +3 -2
  251. package/src/domains/memory/task-memory-handoff.ts +181 -24
  252. package/src/domains/memory/task-memory-policy.ts +3 -1
  253. package/src/domains/memory/types.ts +37 -0
  254. package/src/domains/memory/validate.ts +178 -0
  255. package/src/domains/middleware/memory-intervention.ts +38 -25
  256. package/src/domains/middleware/runtime.ts +6 -0
  257. package/src/domains/middleware/skills-reminder.ts +19 -4
  258. package/src/domains/middleware/stalled-turn.ts +208 -5
  259. package/src/domains/middleware/types.ts +10 -0
  260. package/src/domains/observability/contract.ts +6 -1
  261. package/src/domains/observability/cost.ts +20 -4
  262. package/src/domains/observability/extension.ts +2 -2
  263. package/src/domains/providers/index.ts +3 -0
  264. package/src/domains/providers/model-discovery.ts +9 -0
  265. package/src/domains/providers/runtime-resolution.ts +38 -1
  266. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  267. package/src/domains/providers/types/context-window-slots.ts +18 -0
  268. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  269. package/src/domains/safety/autonomy.ts +1 -1
  270. package/src/domains/safety/call-target.ts +211 -14
  271. package/src/domains/safety/decision-presentation.ts +268 -0
  272. package/src/domains/safety/default-path-policy.ts +8 -0
  273. package/src/domains/safety/finish-contract.ts +4 -3
  274. package/src/domains/safety/policy-engine.ts +48 -6
  275. package/src/domains/safety/redaction.ts +73 -0
  276. package/src/domains/session/compaction/compact.ts +23 -1
  277. package/src/domains/session/compaction/cut-point.ts +2 -0
  278. package/src/domains/session/compaction/tokens.ts +16 -1
  279. package/src/domains/session/context-ledger.ts +12 -1
  280. package/src/domains/session/decision-board.ts +4 -0
  281. package/src/domains/session/entries.ts +110 -1
  282. package/src/domains/session/history.ts +68 -19
  283. package/src/domains/session/manager.ts +9 -2
  284. package/src/domains/session/migrations/index.ts +22 -3
  285. package/src/domains/session/usage.ts +24 -7
  286. package/src/engine/acp/event-mapper.ts +7 -0
  287. package/src/engine/acp/server.ts +32 -2
  288. package/src/engine/agent.ts +18 -1
  289. package/src/engine/apis/lmstudio.ts +25 -4
  290. package/src/engine/apis/openai-completions.ts +147 -22
  291. package/src/engine/claude/sdk-runtime.ts +8 -2
  292. package/src/engine/claude/tool-safety.ts +13 -0
  293. package/src/engine/loop-guard.ts +27 -3
  294. package/src/engine/session.ts +9 -3
  295. package/src/engine/worker-events.ts +4 -3
  296. package/src/engine/worker-runtime.ts +59 -54
  297. package/src/entry/orchestrator.ts +34 -5
  298. package/src/interactive/chat-loop-messages.ts +40 -6
  299. package/src/interactive/chat-loop.ts +13 -0
  300. package/src/interactive/chat-panel.ts +17 -1
  301. package/src/interactive/chat-renderer.ts +49 -24
  302. package/src/interactive/clio-editor.ts +44 -7
  303. package/src/interactive/context-meter.ts +10 -0
  304. package/src/interactive/context-overlay.ts +120 -7
  305. package/src/interactive/context-recall-command.ts +110 -0
  306. package/src/interactive/cost-overlay.ts +39 -8
  307. package/src/interactive/dispatch-board.ts +212 -35
  308. package/src/interactive/footer/widgets.ts +13 -0
  309. package/src/interactive/interactive-application.ts +6 -1
  310. package/src/interactive/interactive-input-runtime.ts +11 -1
  311. package/src/interactive/interactive-presentation.ts +11 -1
  312. package/src/interactive/interactive-slash-runtime.ts +37 -1
  313. package/src/interactive/memory-overlay.ts +89 -4
  314. package/src/interactive/model-session-replay.ts +21 -0
  315. package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
  316. package/src/interactive/overlay-frame.ts +5 -2
  317. package/src/interactive/overlay-general-openers.ts +46 -1
  318. package/src/interactive/overlay-key-routing.ts +41 -1
  319. package/src/interactive/overlay-lifecycle.ts +11 -4
  320. package/src/interactive/overlay-permission-lifecycle.ts +23 -8
  321. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  322. package/src/interactive/overlay-transitions.ts +11 -0
  323. package/src/interactive/overlays/ask-user.ts +74 -30
  324. package/src/interactive/overlays/decisions.ts +3 -1
  325. package/src/interactive/permission-hint.ts +35 -0
  326. package/src/interactive/permission-overlay.ts +95 -45
  327. package/src/interactive/renderers/tool-execution.ts +37 -51
  328. package/src/interactive/session-last-turn.ts +8 -1
  329. package/src/interactive/session-transcript.ts +2 -2
  330. package/src/interactive/session-usage-reseed.ts +36 -10
  331. package/src/interactive/slash-commands.ts +31 -4
  332. package/src/interactive/status/summary.ts +5 -0
  333. package/src/interactive/status/types.ts +5 -0
  334. package/src/interactive/terminal-lease.ts +1 -0
  335. package/src/interactive/turn-context.ts +333 -110
  336. package/src/interactive/turn-middleware.ts +7 -6
  337. package/src/interactive/turn-runtime.ts +37 -8
  338. package/src/interactive/turn-state.ts +3 -0
  339. package/src/interactive/worker-progress.ts +440 -0
  340. package/src/interactive/worker-stream.ts +51 -110
  341. package/src/tools/agent-tools.ts +39 -7
  342. package/src/tools/ask-user.ts +21 -1
  343. package/src/tools/bash.ts +144 -82
  344. package/src/tools/builtin-tool-catalog.ts +11 -5
  345. package/src/tools/context/index.ts +107 -5
  346. package/src/tools/context/surface.ts +3 -2
  347. package/src/tools/core-bootstrap.ts +21 -0
  348. package/src/tools/dispatch-arguments.ts +8 -0
  349. package/src/tools/dispatch-event-text.ts +19 -0
  350. package/src/tools/dispatch-runner.ts +9 -7
  351. package/src/tools/dispatch.ts +24 -1
  352. package/src/tools/monitor.ts +43 -20
  353. package/src/tools/registry.ts +72 -10
  354. package/src/tools/result-disposition.ts +706 -0
  355. package/src/tools/result-shaping.ts +321 -20
  356. package/src/tools/safe-exec.ts +2 -0
  357. package/src/tools/verify/authoring.ts +1120 -0
  358. package/src/tools/verify/catalog.ts +346 -0
  359. package/src/tools/verify/index.ts +13 -3
  360. package/src/tools/verify/scripts.ts +135 -37
  361. package/src/tools/verify/surface.ts +9 -5
  362. package/src/tools/worker-evidence.ts +54 -12
  363. package/src/worker/spec-contract.ts +43 -3
  364. package/dist/chunk-J7CWMCQD.js +0 -255
  365. package/dist/chunk-T6YILFSB.js +0 -80
  366. package/dist/chunk-VAKQQHWR.js +0 -434
  367. package/dist/chunk-VPAYEGVX.js +0 -184
  368. package/dist/chunk-XBXAASKX.js +0 -18
  369. package/dist/memory-WFZMGYHX.js +0 -236
  370. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
@@ -8,6 +8,13 @@
8
8
  * to a bus, or renders; the chat panel owns presentation and the wiring owns
9
9
  * I/O, so every sequence below is testable as a pure fold.
10
10
  *
11
+ * What a worker is saying and doing is not decided here. That is the canonical
12
+ * {@link WorkerProgressSnapshot} projection in `worker-progress.ts`, which the
13
+ * Fleet Runs board reads from the same events, so the two surfaces cannot drift
14
+ * on the answer tail, the tool names, or what a call is touching. This module
15
+ * owns the half the board has no use for: which assignment an event belongs to,
16
+ * which attempt is current, and what the receipt sealed.
17
+ *
11
18
  * Three rules the fold enforces rather than documents:
12
19
  *
13
20
  * - Tool *names* only. Names come exclusively from the `clio_*` telemetry
@@ -34,10 +41,16 @@ import type {
34
41
  DispatchStartedPayload,
35
42
  RunAbortedPayload,
36
43
  } from "../core/bus-events.js";
37
- import { durableAssistantTextFromEvent, WORKER_OUTPUT_MAX_BYTES } from "../domains/dispatch/event-pump.js";
38
44
  import type { RunKind } from "../domains/dispatch/types.js";
39
45
  import type { WorkerRunOrigin, WorkerRunRuntime, WorkerRunRuntimeKind } from "../domains/session/index.js";
40
- import { truncateUtf8 } from "../tools/truncate-utf8.js";
46
+ import { createWorkerProgressFold, type WorkerProgressFold, type WorkerProgressSnapshot } from "./worker-progress.js";
47
+
48
+ export {
49
+ boundSettledText,
50
+ WORKER_LIVE_TAIL_LINES,
51
+ WORKER_TOOL_NAME_LIMIT,
52
+ } from "./worker-progress.js";
53
+ export type { WorkerProgressSnapshot };
41
54
 
42
55
  export interface WorkerAttempt {
43
56
  runId: string;
@@ -95,6 +108,8 @@ export interface WorkerEntryState {
95
108
  droppedLines: number;
96
109
  /** Distinct tool names in first-use order, bounded. */
97
110
  tools: string[];
111
+ /** Canonical live projection. Absent only on receipt-based session replay. */
112
+ progress?: WorkerProgressSnapshot;
98
113
  /** Every attempt of this assignment, oldest first. */
99
114
  attempts: WorkerAttempt[];
100
115
  pending: boolean;
@@ -143,23 +158,6 @@ export interface WorkerStream {
143
158
  reset(): void;
144
159
  }
145
160
 
146
- /**
147
- * Lines of worker prose kept while a run is live. The tail is what a streaming
148
- * answer is about, so the head is what gets dropped; once the run settles the
149
- * body is replaced by the receipt-sealed answer and anchors at the head, which
150
- * is the same rule the thinking block already follows.
151
- */
152
- export const WORKER_LIVE_TAIL_LINES = 40;
153
-
154
- /** Distinct tool names carried on an entry. The receipt's call count carries the total. */
155
- export const WORKER_TOOL_NAME_LIMIT = 8;
156
-
157
- const WORKER_TEXT_TRUNCATION_MARKER = "";
158
-
159
- function isRecord(value: unknown): value is Record<string, unknown> {
160
- return typeof value === "object" && value !== null && !Array.isArray(value);
161
- }
162
-
163
161
  function nonEmptyString(value: unknown): string | undefined {
164
162
  return typeof value === "string" && value.trim().length > 0 ? value : undefined;
165
163
  }
@@ -202,58 +200,6 @@ export function workerTargetLabel(runtime: WorkerRunRuntime): string {
202
200
  return runtime.targetId ?? runtime.wireModelId ?? "unknown";
203
201
  }
204
202
 
205
- /**
206
- * Incremental assistant prose carried by one worker event.
207
- *
208
- * Native workers slim `message_update` down to `assistantMessageEvent.delta`
209
- * before it crosses the NDJSON seam (src/worker/event-projection.ts); the ACP
210
- * mapper emits a top-level `text_delta` carrying `text`. Both spellings are
211
- * read here so ACP peers need no separate UI path.
212
- */
213
- function textDelta(event: unknown): string {
214
- if (!isRecord(event)) return "";
215
- if (event.type === "message_update") {
216
- const assistantEvent = isRecord(event.assistantMessageEvent) ? event.assistantMessageEvent : null;
217
- if (assistantEvent?.type !== "text_delta") return "";
218
- return typeof assistantEvent.delta === "string" ? assistantEvent.delta : "";
219
- }
220
- if (event.type !== "text_delta") return "";
221
- if (typeof event.delta === "string") return event.delta;
222
- return typeof event.text === "string" ? event.text : "";
223
- }
224
-
225
- /** Tool name from Clio's own telemetry. Never from `tool_execution_*`, whose args are the call's arguments. */
226
- function toolName(event: unknown): string | undefined {
227
- if (!isRecord(event)) return undefined;
228
- if (event.type !== "clio_tool_start" && event.type !== "clio_tool_finish") return undefined;
229
- const payload = isRecord(event.payload) ? event.payload : null;
230
- return nonEmptyString(payload?.tool);
231
- }
232
-
233
- function lineCount(text: string): number {
234
- if (text.length === 0) return 0;
235
- let lines = 1;
236
- for (let index = 0; index < text.length; index += 1) {
237
- if (text[index] === "\n") lines += 1;
238
- }
239
- return lines;
240
- }
241
-
242
- /** Keep the newest `WORKER_LIVE_TAIL_LINES` lines; report what that cost. */
243
- function boundLiveText(text: string): { text: string; dropped: number } {
244
- const lines = text.split("\n");
245
- if (lines.length <= WORKER_LIVE_TAIL_LINES) return { text, dropped: 0 };
246
- const dropped = lines.length - WORKER_LIVE_TAIL_LINES;
247
- return { text: lines.slice(dropped).join("\n"), dropped };
248
- }
249
-
250
- /** Head-anchored byte bound for a settled answer, matching the receipt's own bound. */
251
- export function boundSettledText(text: string): { text: string; dropped: number } {
252
- const bounded = truncateUtf8(text, WORKER_OUTPUT_MAX_BYTES, WORKER_TEXT_TRUNCATION_MARKER);
253
- if (bounded === text) return { text, dropped: 0 };
254
- return { text: bounded, dropped: Math.max(0, lineCount(text) - lineCount(bounded)) };
255
- }
256
-
257
203
  /**
258
204
  * Terminal facts a lifecycle payload can supply on its own. Used only when the
259
205
  * sealed receipt is unreadable, so the block still reports an honest outcome
@@ -294,8 +240,21 @@ export function createWorkerStream(options: WorkerStreamOptions = {}): WorkerStr
294
240
  const attemptByAssignment = new Map<string, number>();
295
241
  /** Every attempt run id to its assignment, so progress and terminal events find their entry. */
296
242
  const assignmentByRun = new Map<string, string>();
297
- /** Durable answer text observed live, per attempt; the receipt wins when it is readable. */
298
- const durableTextByRun = new Map<string, string>();
243
+ /**
244
+ * The canonical progress projection per assignment. One fold spans every
245
+ * attempt of an assignment, because a failover keeps streaming into the block
246
+ * the operator is already reading.
247
+ */
248
+ const progressByAssignment = new Map<string, WorkerProgressFold>();
249
+
250
+ /** Copy the canonical projection onto the entry fields the block renders. */
251
+ const applyProgress = (entry: WorkerEntryState, fold: WorkerProgressFold): void => {
252
+ const snapshot = fold.snapshot();
253
+ entry.text = snapshot.tailText;
254
+ entry.droppedLines = snapshot.droppedLines;
255
+ entry.tools = [...snapshot.toolNames];
256
+ entry.progress = snapshot;
257
+ };
299
258
 
300
259
  /** The entry a run id addresses, and only while that run is the entry's current attempt. */
301
260
  const currentEntryForRun = (runId: unknown): WorkerEntryState | undefined => {
@@ -315,11 +274,10 @@ export function createWorkerStream(options: WorkerStreamOptions = {}): WorkerStr
315
274
  // Terminal truth is the sealed answer. A run whose receipt could not be
316
275
  // read keeps whatever durable text its own stream produced, and a run that
317
276
  // produced none keeps the live tail rather than blanking the block.
318
- const settled = nonEmptyString(facts.text) ?? nonEmptyString(durableTextByRun.get(entry.runId));
319
- if (settled !== undefined) {
320
- const bounded = boundSettledText(settled);
321
- entry.text = bounded.text;
322
- entry.droppedLines = bounded.dropped;
277
+ const fold = progressByAssignment.get(entry.assignmentId);
278
+ if (fold !== undefined) {
279
+ fold.settle(nonEmptyString(facts.text));
280
+ applyProgress(entry, fold);
323
281
  }
324
282
  return { kind: "updated", entry };
325
283
  };
@@ -343,10 +301,16 @@ export function createWorkerStream(options: WorkerStreamOptions = {}): WorkerStr
343
301
  delete existing.receipt;
344
302
  existing.attempts.push({ runId, targetLabel: workerTargetLabel(runtime) });
345
303
  assignmentByRun.set(runId, assignmentId);
304
+ const progress = progressByAssignment.get(assignmentId);
305
+ if (progress !== undefined) {
306
+ progress.restart();
307
+ applyProgress(existing, progress);
308
+ }
346
309
  return { kind: "updated", entry: existing };
347
310
  }
348
311
  if (payload.requestOrigin !== "user" && payload.requestOrigin !== "agent") return null;
349
312
  attemptByAssignment.set(assignmentId, payload.attempt);
313
+ const progress = createWorkerProgressFold();
350
314
  const entry: WorkerEntryState = {
351
315
  assignmentId,
352
316
  runId,
@@ -356,49 +320,26 @@ export function createWorkerStream(options: WorkerStreamOptions = {}): WorkerStr
356
320
  text: "",
357
321
  droppedLines: 0,
358
322
  tools: [],
323
+ progress: progress.snapshot(),
359
324
  attempts: [{ runId, targetLabel: workerTargetLabel(runtime) }],
360
325
  pending: true,
361
326
  ...(payload.parentToolCallId !== undefined ? { parentToolCallId: payload.parentToolCallId } : {}),
362
327
  };
363
328
  byAssignment.set(assignmentId, entry);
364
329
  assignmentByRun.set(runId, assignmentId);
330
+ progressByAssignment.set(assignmentId, progress);
365
331
  return { kind: "created", entry };
366
332
  },
367
333
 
368
334
  progress(payload): WorkerStreamChange | null {
369
335
  const entry = currentEntryForRun(payload.runId);
370
336
  if (entry === undefined || !entry.pending) return null;
371
- const event = payload.event;
372
- let changed = false;
373
-
374
- const delta = textDelta(event);
375
- if (delta.length > 0) {
376
- const bounded = boundLiveText(entry.text + delta);
377
- entry.text = bounded.text;
378
- entry.droppedLines += bounded.dropped;
379
- changed = true;
380
- }
381
-
382
- // A durable message_end is the answer as the receipt will seal it. An
383
- // ACP peer that streamed no deltas reaches the transcript only here.
384
- const durable = durableAssistantTextFromEvent(event);
385
- if (durable.trim().length > 0) {
386
- durableTextByRun.set(entry.runId, durable);
387
- if (delta.length === 0 && entry.text.trim().length === 0) {
388
- const bounded = boundLiveText(durable);
389
- entry.text = bounded.text;
390
- entry.droppedLines += bounded.dropped;
391
- }
392
- changed = true;
393
- }
394
-
395
- const tool = toolName(event);
396
- if (tool !== undefined && !entry.tools.includes(tool) && entry.tools.length < WORKER_TOOL_NAME_LIMIT) {
397
- entry.tools.push(tool);
398
- changed = true;
399
- }
400
-
401
- return changed ? { kind: "updated", entry } : null;
337
+ const fold = progressByAssignment.get(entry.assignmentId);
338
+ // Everything the block shows about the stream comes from the canonical
339
+ // projection, so an event that moved nothing visible repaints nothing.
340
+ if (fold === undefined || !fold.observe(payload.event)) return null;
341
+ applyProgress(entry, fold);
342
+ return { kind: "updated", entry };
402
343
  },
403
344
 
404
345
  completed(payload): WorkerStreamChange | null {
@@ -440,7 +381,7 @@ export function createWorkerStream(options: WorkerStreamOptions = {}): WorkerStr
440
381
  byAssignment.clear();
441
382
  attemptByAssignment.clear();
442
383
  assignmentByRun.clear();
443
- durableTextByRun.clear();
384
+ progressByAssignment.clear();
444
385
  },
445
386
  };
446
387
  }
@@ -22,12 +22,14 @@ import { type SkillActivation, skillActivationFromToolDetails } from "../core/sk
22
22
  import type { ToolName } from "../core/tool-names.js";
23
23
  import { ToolNames } from "../core/tool-names.js";
24
24
  import type { ResolvedRuntimeTarget } from "../domains/providers/index.js";
25
+ import { type CallActionDescriptor, describeCallAction } from "../domains/safety/call-target.js";
25
26
  import type { SafetyDecision } from "../domains/safety/contract.js";
26
27
  import { formatModelRejection } from "../domains/safety/rejection-feedback.js";
27
28
  import { validateEngineToolArguments } from "../engine/ai.js";
28
29
  import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "../engine/types.js";
29
30
  import { applyToolProfile, type ToolProfileName } from "./profiles.js";
30
31
  import type { ToolInvokeOptions, ToolRegistry, ToolResult, ToolSpec } from "./registry.js";
32
+ import { isDispositionedToolResultError, toolResultContextText } from "./result-disposition.js";
31
33
 
32
34
  /**
33
35
  * Lightweight per-call observability hook. Default no-op so unused
@@ -44,6 +46,12 @@ export type ToolOutcome = "ok" | "error" | "blocked";
44
46
 
45
47
  export interface ToolStartEvent {
46
48
  tool: string;
49
+ /**
50
+ * The engine's id for this call, when the producer has one. New producers
51
+ * put the same id on start and finish so concurrent calls of one tool remain
52
+ * independently attributable. Optional for direct callers and old streams.
53
+ */
54
+ toolCallId?: string;
47
55
  posture: "operating";
48
56
  /**
49
57
  * Wall-clock anchor for the instant the call began, for a human correlating
@@ -52,6 +60,14 @@ export interface ToolStartEvent {
52
60
  * event is measured on that process's monotonic clock instead.
53
61
  */
54
62
  startedAt: number;
63
+ /**
64
+ * What this call is doing, as a bounded redacted descriptor composed here
65
+ * where the arguments are trusted. This is the only account of a worker's
66
+ * arguments that may cross the NDJSON stdout seam; the arguments themselves
67
+ * never do, so an operator surface reads a verb and an object it can show,
68
+ * never an argument object it would have to sanitize itself.
69
+ */
70
+ action?: CallActionDescriptor;
55
71
  }
56
72
 
57
73
  export interface ToolFinishEvent {
@@ -99,10 +115,10 @@ type WorkerToolOkDetails = { kind: "ok" } & Record<string, unknown>;
99
115
  function projectToolResult(result: ToolResult): WorkerAgentToolResult {
100
116
  const details = { ...(result.details ?? {}), kind: result.kind } as { kind: "ok" } | { kind: "error" };
101
117
  if (result.kind === "error") {
102
- return { content: [{ type: "text", text: result.message }], details };
118
+ return { content: [{ type: "text", text: toolResultContextText(result) }], details };
103
119
  }
104
120
  return {
105
- content: [{ type: "text", text: result.output }],
121
+ content: [{ type: "text", text: toolResultContextText(result) }],
106
122
  details,
107
123
  ...(result.terminate === true ? { terminate: true } : {}),
108
124
  };
@@ -119,6 +135,8 @@ interface RunValidatedToolCallInput {
119
135
  signal?: AbortSignal;
120
136
  telemetry?: ToolTelemetry;
121
137
  invokeOptions?: Partial<ToolInvokeOptions>;
138
+ /** Agent loops can preserve canonical failure envelopes and classify them after execution. */
139
+ returnDispositionedErrors?: boolean;
122
140
  }
123
141
 
124
142
  async function runValidatedToolCall(input: RunValidatedToolCallInput): Promise<WorkerAgentToolResult> {
@@ -127,11 +145,21 @@ async function runValidatedToolCall(input: RunValidatedToolCallInput): Promise<W
127
145
  // spans the call, so `durationMs` survives a clock correction mid-tool.
128
146
  const startedAt = Date.now();
129
147
  const startedAtClock = performance.now();
130
- telemetry?.onStart?.({ tool: spec.name, posture: "operating", startedAt });
131
- // Stamped onto every finish event so a consumer can join this authoritative
132
- // outcome to the engine's `tool_execution_end` for the same call.
148
+ // Stamped onto both lifecycle events so a concurrent finish resolves only
149
+ // the start for its own engine call. Direct callers may legitimately omit it.
133
150
  const callId = input.invokeOptions?.toolCallId;
134
151
  const withCallId = callId === undefined ? {} : { toolCallId: callId };
152
+ // The one seam that holds validated arguments and publishes telemetry, so it
153
+ // is where the redacted descriptor is composed. Everything downstream of here
154
+ // sees the descriptor and never the arguments.
155
+ const action = describeCallAction(spec.name, args);
156
+ telemetry?.onStart?.({
157
+ tool: spec.name,
158
+ ...withCallId,
159
+ posture: "operating",
160
+ startedAt,
161
+ ...(action !== null ? { action } : {}),
162
+ });
135
163
  const invokeOpts: ToolInvokeOptions = {};
136
164
  if (input.invokeOptions) Object.assign(invokeOpts, input.invokeOptions);
137
165
  if (signal) invokeOpts.signal = signal;
@@ -183,13 +211,16 @@ async function runValidatedToolCall(input: RunValidatedToolCallInput): Promise<W
183
211
  reason: verdict.result.message,
184
212
  decision: verdict.decision,
185
213
  });
186
- throw new Error(verdict.result.message);
214
+ if (input.returnDispositionedErrors === true && isDispositionedToolResultError(verdict.result)) {
215
+ return projectToolResult(verdict.result);
216
+ }
217
+ throw new Error(toolResultContextText(verdict.result));
187
218
  }
188
219
  const toolDetails = isRecord(verdict.result.details) ? verdict.result.details : {};
189
220
  const skillActivation =
190
221
  spec.name === ToolNames.Context ? skillActivationFromToolDetails(toolDetails, input.invokeOptions?.turnId) : null;
191
222
  const result: AgentToolResult<WorkerToolOkDetails> = {
192
- content: [{ type: "text", text: verdict.result.output }],
223
+ content: [{ type: "text", text: toolResultContextText(verdict.result) }],
193
224
  details: { ...toolDetails, kind: "ok" },
194
225
  };
195
226
  if (verdict.result.terminate === true) {
@@ -291,6 +322,7 @@ function toAgentTool(
291
322
  spec,
292
323
  args: params as Record<string, unknown>,
293
324
  registry,
325
+ returnDispositionedErrors: true,
294
326
  };
295
327
  if (signal) callInput.signal = signal;
296
328
  if (telemetry) callInput.telemetry = telemetry;
@@ -5,6 +5,7 @@ import { Type } from "typebox";
5
5
  import { ToolNames } from "../core/tool-names.js";
6
6
  import { clioStateDir } from "../core/xdg.js";
7
7
  import { type AutonomyExposure, DEFAULT_AUTONOMY_EXPOSURE } from "../domains/safety/autonomy.js";
8
+ import { classifyDecisionPresentation, decisionFactsForAnswer } from "../domains/safety/decision-presentation.js";
8
9
  import { StringEnum } from "../engine/ai.js";
9
10
  import type {
10
11
  AskUserToolPolicy,
@@ -57,6 +58,7 @@ export interface AskUserResult {
57
58
 
58
59
  export interface AskUserCall {
59
60
  action: AskUserAction;
61
+ exposure?: AutonomyExposure;
60
62
  mode?: AskUserMode;
61
63
  questions?: AskUserQuestion[];
62
64
  decisions?: AskUserDecision[];
@@ -284,6 +286,7 @@ export function normalizeAskUserCall(args: Record<string, unknown>): { call?: As
284
286
  return {
285
287
  call: {
286
288
  action: "ask",
289
+ exposure: exposure.exposure ?? DEFAULT_AUTONOMY_EXPOSURE,
287
290
  ...(mode.mode ? { mode: mode.mode } : {}),
288
291
  questions: questions.questions,
289
292
  ...(summary ? { summary } : {}),
@@ -319,6 +322,7 @@ function createStandalonePolicy(options?: ToolInvokeOptions): AskUserToolPolicy
319
322
  updatedAt: now,
320
323
  ...(options?.sessionId ? { sessionId: options.sessionId } : {}),
321
324
  ...(options?.turnId ? { turnId: options.turnId } : {}),
325
+ exposure: DEFAULT_AUTONOMY_EXPOSURE,
322
326
  rounds: [],
323
327
  decisions: [],
324
328
  inFlight: false,
@@ -335,6 +339,13 @@ function hydratePolicy(policy: AskUserToolPolicy, options?: ToolInvokeOptions):
335
339
  if (options?.turnId && !policy.turnId) policy.turnId = options.turnId;
336
340
  }
337
341
 
342
+ /** Once an interview is outward, a later local round cannot lower its replay tier. */
343
+ function mergePolicyExposure(policy: AskUserToolPolicy, exposure: AutonomyExposure): AutonomyExposure {
344
+ const merged = policy.exposure === "outward" || exposure === "outward" ? "outward" : "local";
345
+ policy.exposure = merged;
346
+ return merged;
347
+ }
348
+
338
349
  function transcriptQuestions(questions: ReadonlyArray<AskUserQuestion>): AskUserTranscriptQuestion[] {
339
350
  return questions.map((question) => ({
340
351
  question: question.question,
@@ -455,6 +466,7 @@ async function persistAskUserTranscript(
455
466
  ...(policy.endedAt ? { endedAt: policy.endedAt } : {}),
456
467
  ...(policy.sessionId ? { sessionId: policy.sessionId } : {}),
457
468
  ...(policy.turnId ? { turnId: policy.turnId } : {}),
469
+ exposure: policy.exposure ?? DEFAULT_AUTONOMY_EXPOSURE,
458
470
  ...(policy.summary ? { summary: policy.summary } : {}),
459
471
  decisions: policy.decisions,
460
472
  rounds: policy.rounds,
@@ -478,6 +490,7 @@ function compactInterview(
478
490
  rounds: policy.rounds.length,
479
491
  max_rounds: policy.maxCalls,
480
492
  transcript_path: policy.transcriptPath ?? null,
493
+ exposure: policy.exposure ?? DEFAULT_AUTONOMY_EXPOSURE,
481
494
  latest_answers: latestAnswers,
482
495
  decisions: policy.decisions,
483
496
  ...(policy.summary ? { summary: policy.summary } : {}),
@@ -591,6 +604,7 @@ export function createAskUserTool(deps: AskUserToolDeps = {}): ToolSpec {
591
604
  return completeInterview(policy, "complete", options, call.summary, call.decisions ?? []);
592
605
  }
593
606
  const questions = call.questions ?? [];
607
+ const exposure = mergePolicyExposure(policy, call.exposure ?? DEFAULT_AUTONOMY_EXPOSURE);
594
608
  if (call.max_rounds !== undefined) {
595
609
  const nextLimit = policy.callCount === 0 ? call.max_rounds : Math.max(policy.maxCalls, call.max_rounds);
596
610
  policy.maxCalls = Math.max(nextLimit, policy.callCount + 1);
@@ -632,7 +646,13 @@ export function createAskUserTool(deps: AskUserToolDeps = {}): ToolSpec {
632
646
  if (call.summary) policy.summary = call.summary;
633
647
  const handler = deps.askUser ?? defaultAskUserHandler;
634
648
  try {
635
- const result = normalizeAskUserResult(questions, await handler(questions, options));
649
+ const result = normalizeAskUserResult(
650
+ questions,
651
+ await handler(questions, {
652
+ ...options,
653
+ decisionPresentation: classifyDecisionPresentation(decisionFactsForAnswer(exposure)),
654
+ }),
655
+ );
636
656
  const answeredAt = new Date().toISOString();
637
657
  policy.callCount += 1;
638
658
  policy.askedQuestionKeys.add(key);