@caupulican/pi-adaptative 0.81.39 → 0.81.41

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 (884) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +3 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +4 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
  13. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
  14. package/dist/cli/args.d.ts +4 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +31 -1
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-directory-layout.d.ts +15 -0
  19. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  20. package/dist/core/agent-directory-layout.js +72 -0
  21. package/dist/core/agent-directory-layout.js.map +1 -0
  22. package/dist/core/agent-paths.d.ts +25 -2
  23. package/dist/core/agent-paths.d.ts.map +1 -1
  24. package/dist/core/agent-paths.js +79 -4
  25. package/dist/core/agent-paths.js.map +1 -1
  26. package/dist/core/agent-session-contracts.d.ts +293 -0
  27. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  28. package/dist/core/agent-session-contracts.js +26 -0
  29. package/dist/core/agent-session-contracts.js.map +1 -0
  30. package/dist/core/agent-session-runtime.d.ts +52 -8
  31. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  32. package/dist/core/agent-session-runtime.js +400 -79
  33. package/dist/core/agent-session-runtime.js.map +1 -1
  34. package/dist/core/agent-session-services.d.ts +1 -0
  35. package/dist/core/agent-session-services.d.ts.map +1 -1
  36. package/dist/core/agent-session-services.js +1 -0
  37. package/dist/core/agent-session-services.js.map +1 -1
  38. package/dist/core/agent-session.d.ts +74 -518
  39. package/dist/core/agent-session.d.ts.map +1 -1
  40. package/dist/core/agent-session.js +370 -1432
  41. package/dist/core/agent-session.js.map +1 -1
  42. package/dist/core/auth-storage.d.ts.map +1 -1
  43. package/dist/core/auth-storage.js +3 -1
  44. package/dist/core/auth-storage.js.map +1 -1
  45. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  46. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  47. package/dist/core/autonomy/approval-gate.js +6 -28
  48. package/dist/core/autonomy/approval-gate.js.map +1 -1
  49. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  50. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  51. package/dist/core/autonomy/bounded-completion.js +1 -1
  52. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  53. package/dist/core/autonomy/contracts.d.ts +20 -12
  54. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  55. package/dist/core/autonomy/contracts.js.map +1 -1
  56. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  57. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  58. package/dist/core/autonomy/foreground-envelope.js +8 -25
  59. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  60. package/dist/core/autonomy/gates.d.ts.map +1 -1
  61. package/dist/core/autonomy/gates.js +8 -10
  62. package/dist/core/autonomy/gates.js.map +1 -1
  63. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  64. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  65. package/dist/core/autonomy/lane-private-paths.js +16 -0
  66. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  67. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  68. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  69. package/dist/core/autonomy/lane-tool-surface.js +48 -9
  70. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  71. package/dist/core/autonomy/lane-tracker.d.ts +14 -0
  72. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  73. package/dist/core/autonomy/lane-tracker.js +38 -0
  74. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  75. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  76. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  77. package/dist/core/autonomy/risk-assessment.js +1 -123
  78. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  79. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  80. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  81. package/dist/core/autonomy/session-lane-record.js +16 -29
  82. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  83. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  84. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  85. package/dist/core/autonomy/telemetry-events.js +1 -1
  86. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  87. package/dist/core/autonomy-telemetry.d.ts +7 -7
  88. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  89. package/dist/core/autonomy-telemetry.js +9 -9
  90. package/dist/core/autonomy-telemetry.js.map +1 -1
  91. package/dist/core/background-lane-controller.d.ts +56 -236
  92. package/dist/core/background-lane-controller.d.ts.map +1 -1
  93. package/dist/core/background-lane-controller.js +141 -1273
  94. package/dist/core/background-lane-controller.js.map +1 -1
  95. package/dist/core/bedrock-sso-login.d.ts +16 -0
  96. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  97. package/dist/core/bedrock-sso-login.js +98 -0
  98. package/dist/core/bedrock-sso-login.js.map +1 -0
  99. package/dist/core/capability-contract.d.ts +4 -0
  100. package/dist/core/capability-contract.d.ts.map +1 -0
  101. package/dist/core/capability-contract.js +28 -0
  102. package/dist/core/capability-contract.js.map +1 -0
  103. package/dist/core/compaction-controller.d.ts +90 -0
  104. package/dist/core/compaction-controller.d.ts.map +1 -0
  105. package/dist/core/compaction-controller.js +452 -0
  106. package/dist/core/compaction-controller.js.map +1 -0
  107. package/dist/core/compaction-support.d.ts +13 -17
  108. package/dist/core/compaction-support.d.ts.map +1 -1
  109. package/dist/core/compaction-support.js +3 -3
  110. package/dist/core/compaction-support.js.map +1 -1
  111. package/dist/core/context/context-artifacts.d.ts +6 -2
  112. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  113. package/dist/core/context/context-artifacts.js +34 -2
  114. package/dist/core/context/context-artifacts.js.map +1 -1
  115. package/dist/core/context/context-store-retention.d.ts +8 -2
  116. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  117. package/dist/core/context/context-store-retention.js +158 -35
  118. package/dist/core/context/context-store-retention.js.map +1 -1
  119. package/dist/core/context/okf-memory.d.ts.map +1 -1
  120. package/dist/core/context/okf-memory.js +9 -11
  121. package/dist/core/context/okf-memory.js.map +1 -1
  122. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  123. package/dist/core/context/sqlite-runtime-index.js +6 -8
  124. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  125. package/dist/core/context-gc.d.ts +3 -0
  126. package/dist/core/context-gc.d.ts.map +1 -1
  127. package/dist/core/context-gc.js +10 -5
  128. package/dist/core/context-gc.js.map +1 -1
  129. package/dist/core/context-pipeline.d.ts +1 -1
  130. package/dist/core/context-pipeline.d.ts.map +1 -1
  131. package/dist/core/context-pipeline.js +16 -37
  132. package/dist/core/context-pipeline.js.map +1 -1
  133. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  134. package/dist/core/cost/cost-summary.js +5 -3
  135. package/dist/core/cost/cost-summary.js.map +1 -1
  136. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  137. package/dist/core/cost/daily-usage.js +4 -5
  138. package/dist/core/cost/daily-usage.js.map +1 -1
  139. package/dist/core/default-tool-surface.d.ts.map +1 -1
  140. package/dist/core/default-tool-surface.js +2 -0
  141. package/dist/core/default-tool-surface.js.map +1 -1
  142. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  143. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  144. package/dist/core/delegation/managed-lane-controller.js +217 -0
  145. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  146. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  147. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-claim.js +98 -0
  149. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  150. package/dist/core/delegation/worker-actions.d.ts +7 -5
  151. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  152. package/dist/core/delegation/worker-actions.js +20 -4
  153. package/dist/core/delegation/worker-actions.js.map +1 -1
  154. package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
  155. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  156. package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
  157. package/dist/core/delegation/worker-claim.js.map +1 -0
  158. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  159. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  160. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  161. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  162. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  163. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  164. package/dist/core/delegation/worker-delegation-request.js +2 -0
  165. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  166. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  167. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  168. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  169. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  170. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  171. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  172. package/dist/core/delegation/worker-execution-policy.js +160 -0
  173. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  174. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  175. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  176. package/dist/core/delegation/worker-lane-projection.js +100 -0
  177. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  178. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  179. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  180. package/dist/core/delegation/worker-lifecycle.js +339 -0
  181. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  182. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  183. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  184. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  185. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  186. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  187. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  188. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  189. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  190. package/dist/core/delegation/worker-runner.d.ts +25 -14
  191. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  192. package/dist/core/delegation/worker-runner.js +122 -53
  193. package/dist/core/delegation/worker-runner.js.map +1 -1
  194. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  195. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  196. package/dist/core/delegation/worker-task-label.js +11 -0
  197. package/dist/core/delegation/worker-task-label.js.map +1 -0
  198. package/dist/core/doctor.d.ts +8 -0
  199. package/dist/core/doctor.d.ts.map +1 -1
  200. package/dist/core/doctor.js +32 -1
  201. package/dist/core/doctor.js.map +1 -1
  202. package/dist/core/extension-import-authority.d.ts +6 -0
  203. package/dist/core/extension-import-authority.d.ts.map +1 -0
  204. package/dist/core/extension-import-authority.js +10 -0
  205. package/dist/core/extension-import-authority.js.map +1 -0
  206. package/dist/core/extensions/index.d.ts +1 -1
  207. package/dist/core/extensions/index.d.ts.map +1 -1
  208. package/dist/core/extensions/index.js.map +1 -1
  209. package/dist/core/extensions/loader.d.ts +5 -1
  210. package/dist/core/extensions/loader.d.ts.map +1 -1
  211. package/dist/core/extensions/loader.js +52 -18
  212. package/dist/core/extensions/loader.js.map +1 -1
  213. package/dist/core/extensions/runner.d.ts +3 -0
  214. package/dist/core/extensions/runner.d.ts.map +1 -1
  215. package/dist/core/extensions/runner.js +20 -5
  216. package/dist/core/extensions/runner.js.map +1 -1
  217. package/dist/core/extensions/stale-context.d.ts +2 -0
  218. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  219. package/dist/core/extensions/stale-context.js +2 -0
  220. package/dist/core/extensions/stale-context.js.map +1 -0
  221. package/dist/core/extensions/storage.d.ts +8 -0
  222. package/dist/core/extensions/storage.d.ts.map +1 -0
  223. package/dist/core/extensions/storage.js +28 -0
  224. package/dist/core/extensions/storage.js.map +1 -0
  225. package/dist/core/extensions/types.d.ts +78 -21
  226. package/dist/core/extensions/types.d.ts.map +1 -1
  227. package/dist/core/extensions/types.js.map +1 -1
  228. package/dist/core/failure-corpus.d.ts +1 -15
  229. package/dist/core/failure-corpus.d.ts.map +1 -1
  230. package/dist/core/failure-corpus.js +9 -37
  231. package/dist/core/failure-corpus.js.map +1 -1
  232. package/dist/core/foreground-recovery-controller.d.ts +53 -0
  233. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  234. package/dist/core/foreground-recovery-controller.js +111 -0
  235. package/dist/core/foreground-recovery-controller.js.map +1 -0
  236. package/dist/core/gateways/channel-provider.d.ts +3 -0
  237. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  238. package/dist/core/gateways/channel-provider.js +31 -6
  239. package/dist/core/gateways/channel-provider.js.map +1 -1
  240. package/dist/core/goal-loop-controller.d.ts +14 -9
  241. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  242. package/dist/core/goal-loop-controller.js +47 -75
  243. package/dist/core/goal-loop-controller.js.map +1 -1
  244. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  245. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  246. package/dist/core/goals/compact-goal-context.js +59 -0
  247. package/dist/core/goals/compact-goal-context.js.map +1 -0
  248. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  249. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  250. package/dist/core/goals/goal-acceptance.js +27 -0
  251. package/dist/core/goals/goal-acceptance.js.map +1 -0
  252. package/dist/core/goals/goal-auto-continue-controller.d.ts +28 -0
  253. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  254. package/dist/core/goals/goal-auto-continue-controller.js +90 -0
  255. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  256. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  257. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  258. package/dist/core/goals/goal-continuation-controller.js +52 -11
  259. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  260. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  261. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  262. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  263. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  264. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  265. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  266. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  267. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  268. package/dist/core/goals/goal-lifecycle.d.ts +43 -0
  269. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  270. package/dist/core/goals/goal-lifecycle.js +102 -0
  271. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  272. package/dist/core/goals/goal-record.d.ts +17 -0
  273. package/dist/core/goals/goal-record.d.ts.map +1 -0
  274. package/dist/core/goals/goal-record.js +31 -0
  275. package/dist/core/goals/goal-record.js.map +1 -0
  276. package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
  277. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  278. package/dist/core/goals/goal-runtime-snapshot.js +10 -8
  279. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  280. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  281. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  282. package/dist/core/goals/goal-session-controller.js +128 -0
  283. package/dist/core/goals/goal-session-controller.js.map +1 -0
  284. package/dist/core/goals/goal-state.d.ts +46 -25
  285. package/dist/core/goals/goal-state.d.ts.map +1 -1
  286. package/dist/core/goals/goal-state.js +91 -24
  287. package/dist/core/goals/goal-state.js.map +1 -1
  288. package/dist/core/goals/goal-tool-core.d.ts +9 -10
  289. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  290. package/dist/core/goals/goal-tool-core.js +60 -75
  291. package/dist/core/goals/goal-tool-core.js.map +1 -1
  292. package/dist/core/goals/session-goal-state.d.ts +20 -12
  293. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  294. package/dist/core/goals/session-goal-state.js +133 -33
  295. package/dist/core/goals/session-goal-state.js.map +1 -1
  296. package/dist/core/human-input-controller.d.ts +47 -0
  297. package/dist/core/human-input-controller.d.ts.map +1 -0
  298. package/dist/core/human-input-controller.js +181 -0
  299. package/dist/core/human-input-controller.js.map +1 -0
  300. package/dist/core/human-input.d.ts +100 -0
  301. package/dist/core/human-input.d.ts.map +1 -0
  302. package/dist/core/human-input.js +362 -0
  303. package/dist/core/human-input.js.map +1 -0
  304. package/dist/core/index.d.ts +9 -1
  305. package/dist/core/index.d.ts.map +1 -1
  306. package/dist/core/index.js +9 -1
  307. package/dist/core/index.js.map +1 -1
  308. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  309. package/dist/core/install-telemetry.d.ts.map +1 -0
  310. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  311. package/dist/core/install-telemetry.js.map +1 -0
  312. package/dist/core/keybindings.d.ts +17 -1
  313. package/dist/core/keybindings.d.ts.map +1 -1
  314. package/dist/core/keybindings.js +24 -6
  315. package/dist/core/keybindings.js.map +1 -1
  316. package/dist/core/learning/learning-audit.d.ts +2 -4
  317. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  318. package/dist/core/learning/learning-audit.js +9 -29
  319. package/dist/core/learning/learning-audit.js.map +1 -1
  320. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  321. package/dist/core/learning/learning-gate.js +1 -6
  322. package/dist/core/learning/learning-gate.js.map +1 -1
  323. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  324. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  325. package/dist/core/learning/session-learning-decision.js +9 -29
  326. package/dist/core/learning/session-learning-decision.js.map +1 -1
  327. package/dist/core/local-runtime-controller.d.ts +1 -1
  328. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  329. package/dist/core/local-runtime-controller.js.map +1 -1
  330. package/dist/core/memory-controller.d.ts.map +1 -1
  331. package/dist/core/memory-controller.js +4 -4
  332. package/dist/core/memory-controller.js.map +1 -1
  333. package/dist/core/model-capability.d.ts +0 -19
  334. package/dist/core/model-capability.d.ts.map +1 -1
  335. package/dist/core/model-capability.js +1 -19
  336. package/dist/core/model-capability.js.map +1 -1
  337. package/dist/core/model-registry.d.ts +6 -1
  338. package/dist/core/model-registry.d.ts.map +1 -1
  339. package/dist/core/model-registry.js +13 -5
  340. package/dist/core/model-registry.js.map +1 -1
  341. package/dist/core/model-resolver.d.ts +17 -2
  342. package/dist/core/model-resolver.d.ts.map +1 -1
  343. package/dist/core/model-resolver.js +38 -25
  344. package/dist/core/model-resolver.js.map +1 -1
  345. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  346. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  347. package/dist/core/model-router/intent-classifier.js +1 -156
  348. package/dist/core/model-router/intent-classifier.js.map +1 -1
  349. package/dist/core/model-router-controller.d.ts +1 -1
  350. package/dist/core/model-router-controller.d.ts.map +1 -1
  351. package/dist/core/model-router-controller.js +2 -2
  352. package/dist/core/model-router-controller.js.map +1 -1
  353. package/dist/core/model-selection-controller.d.ts +5 -5
  354. package/dist/core/model-selection-controller.d.ts.map +1 -1
  355. package/dist/core/model-selection-controller.js.map +1 -1
  356. package/dist/core/model-tool-protocol.d.ts +23 -0
  357. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  358. package/dist/core/model-tool-protocol.js +43 -0
  359. package/dist/core/model-tool-protocol.js.map +1 -0
  360. package/dist/core/models/adaptation-store.d.ts +4 -6
  361. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  362. package/dist/core/models/adaptation-store.js +95 -83
  363. package/dist/core/models/adaptation-store.js.map +1 -1
  364. package/dist/core/models/fitness-store.d.ts +2 -12
  365. package/dist/core/models/fitness-store.d.ts.map +1 -1
  366. package/dist/core/models/fitness-store.js +84 -57
  367. package/dist/core/models/fitness-store.js.map +1 -1
  368. package/dist/core/models/host-state-store.d.ts +34 -0
  369. package/dist/core/models/host-state-store.d.ts.map +1 -0
  370. package/dist/core/models/host-state-store.js +86 -0
  371. package/dist/core/models/host-state-store.js.map +1 -0
  372. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  373. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  374. package/dist/core/orchestration/agent-resume.js +90 -0
  375. package/dist/core/orchestration/agent-resume.js.map +1 -0
  376. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  377. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  378. package/dist/core/orchestration/capability-gateway.js +152 -0
  379. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  380. package/dist/core/orchestration/contracts.d.ts +343 -0
  381. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  382. package/dist/core/orchestration/contracts.js +135 -0
  383. package/dist/core/orchestration/contracts.js.map +1 -0
  384. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  385. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  386. package/dist/core/orchestration/delegation-ledger.js +200 -0
  387. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  388. package/dist/core/orchestration/event-store.d.ts +83 -0
  389. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  390. package/dist/core/orchestration/event-store.js +560 -0
  391. package/dist/core/orchestration/event-store.js.map +1 -0
  392. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  393. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  394. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  395. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  396. package/dist/core/orchestration/model-binding.d.ts +15 -0
  397. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  398. package/dist/core/orchestration/model-binding.js +29 -0
  399. package/dist/core/orchestration/model-binding.js.map +1 -0
  400. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  401. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  402. package/dist/core/orchestration/policy-compiler.js +191 -0
  403. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  404. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  405. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  406. package/dist/core/orchestration/policy-gate.js +24 -0
  407. package/dist/core/orchestration/policy-gate.js.map +1 -0
  408. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  409. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  410. package/dist/core/orchestration/profile-registry.js +393 -0
  411. package/dist/core/orchestration/profile-registry.js.map +1 -0
  412. package/dist/core/orchestration/profile-store.d.ts +31 -0
  413. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  414. package/dist/core/orchestration/profile-store.js +136 -0
  415. package/dist/core/orchestration/profile-store.js.map +1 -0
  416. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  417. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  418. package/dist/core/orchestration/risk-budget.js +48 -0
  419. package/dist/core/orchestration/risk-budget.js.map +1 -0
  420. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  421. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  422. package/dist/core/orchestration/task-runtime.js +1600 -0
  423. package/dist/core/orchestration/task-runtime.js.map +1 -0
  424. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  425. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  426. package/dist/core/orchestration/work-state-projection.js +116 -0
  427. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  428. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  429. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  430. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  431. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  432. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  433. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  434. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  435. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  436. package/dist/core/package-manager.d.ts.map +1 -1
  437. package/dist/core/package-manager.js +20 -3
  438. package/dist/core/package-manager.js.map +1 -1
  439. package/dist/core/process-identity.d.ts +11 -0
  440. package/dist/core/process-identity.d.ts.map +1 -0
  441. package/dist/core/process-identity.js +26 -0
  442. package/dist/core/process-identity.js.map +1 -0
  443. package/dist/core/process-matrix/codes.d.ts +14 -3
  444. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  445. package/dist/core/process-matrix/codes.js.map +1 -1
  446. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  447. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  448. package/dist/core/process-matrix/resume-launcher.js +62 -0
  449. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  450. package/dist/core/process-matrix/runtime.d.ts +37 -22
  451. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  452. package/dist/core/process-matrix/runtime.js +399 -76
  453. package/dist/core/process-matrix/runtime.js.map +1 -1
  454. package/dist/core/process-matrix/store.d.ts +5 -2
  455. package/dist/core/process-matrix/store.d.ts.map +1 -1
  456. package/dist/core/process-matrix/store.js +123 -14
  457. package/dist/core/process-matrix/store.js.map +1 -1
  458. package/dist/core/process-matrix/supervisor.d.ts +10 -7
  459. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  460. package/dist/core/process-matrix/supervisor.js +45 -14
  461. package/dist/core/process-matrix/supervisor.js.map +1 -1
  462. package/dist/core/profile-filter-controller.d.ts +8 -1
  463. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  464. package/dist/core/profile-filter-controller.js +23 -5
  465. package/dist/core/profile-filter-controller.js.map +1 -1
  466. package/dist/core/profile-registry.d.ts.map +1 -1
  467. package/dist/core/profile-registry.js +6 -8
  468. package/dist/core/profile-registry.js.map +1 -1
  469. package/dist/core/prompt-templates.d.ts +1 -0
  470. package/dist/core/prompt-templates.d.ts.map +1 -1
  471. package/dist/core/prompt-templates.js +18 -29
  472. package/dist/core/prompt-templates.js.map +1 -1
  473. package/dist/core/reflection-controller.d.ts +5 -5
  474. package/dist/core/reflection-controller.d.ts.map +1 -1
  475. package/dist/core/reflection-controller.js +5 -2
  476. package/dist/core/reflection-controller.js.map +1 -1
  477. package/dist/core/reload-blockers.d.ts.map +1 -1
  478. package/dist/core/reload-blockers.js +6 -8
  479. package/dist/core/reload-blockers.js.map +1 -1
  480. package/dist/core/request-auth.d.ts +7 -0
  481. package/dist/core/request-auth.d.ts.map +1 -0
  482. package/dist/core/request-auth.js +8 -0
  483. package/dist/core/request-auth.js.map +1 -0
  484. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  485. package/dist/core/research/evidence-bundle.js +1 -6
  486. package/dist/core/research/evidence-bundle.js.map +1 -1
  487. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  488. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  489. package/dist/core/research/lane-model-resolver.js +65 -0
  490. package/dist/core/research/lane-model-resolver.js.map +1 -0
  491. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  492. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  493. package/dist/core/research/model-fitness-controller.js +106 -0
  494. package/dist/core/research/model-fitness-controller.js.map +1 -0
  495. package/dist/core/research/model-fitness.d.ts +1 -1
  496. package/dist/core/research/model-fitness.d.ts.map +1 -1
  497. package/dist/core/research/model-fitness.js +4 -4
  498. package/dist/core/research/model-fitness.js.map +1 -1
  499. package/dist/core/research/research-gate.d.ts.map +1 -1
  500. package/dist/core/research/research-gate.js +7 -7
  501. package/dist/core/research/research-gate.js.map +1 -1
  502. package/dist/core/research/research-lane-controller.d.ts +62 -0
  503. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  504. package/dist/core/research/research-lane-controller.js +292 -0
  505. package/dist/core/research/research-lane-controller.js.map +1 -0
  506. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  507. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  508. package/dist/core/research/session-evidence-bundle.js +10 -46
  509. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  510. package/dist/core/resource-loader.d.ts.map +1 -1
  511. package/dist/core/resource-loader.js +23 -8
  512. package/dist/core/resource-loader.js.map +1 -1
  513. package/dist/core/risk-classifier.d.ts +6 -0
  514. package/dist/core/risk-classifier.d.ts.map +1 -0
  515. package/dist/core/risk-classifier.js +233 -0
  516. package/dist/core/risk-classifier.js.map +1 -0
  517. package/dist/core/runtime-builder.d.ts +41 -23
  518. package/dist/core/runtime-builder.d.ts.map +1 -1
  519. package/dist/core/runtime-builder.js +365 -253
  520. package/dist/core/runtime-builder.js.map +1 -1
  521. package/dist/core/sdk.d.ts +6 -3
  522. package/dist/core/sdk.d.ts.map +1 -1
  523. package/dist/core/sdk.js +68 -25
  524. package/dist/core/sdk.js.map +1 -1
  525. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  526. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  527. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  528. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  529. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  530. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  531. package/dist/core/secrets/secret-dotenv.js +183 -0
  532. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  533. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  534. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  535. package/dist/core/secrets/secret-vault-format.js +397 -0
  536. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  537. package/dist/core/secrets/secret-vault.d.ts +72 -0
  538. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  539. package/dist/core/secrets/secret-vault.js +671 -0
  540. package/dist/core/secrets/secret-vault.js.map +1 -0
  541. package/dist/core/session-analytics.d.ts +4 -23
  542. package/dist/core/session-analytics.d.ts.map +1 -1
  543. package/dist/core/session-analytics.js +67 -70
  544. package/dist/core/session-analytics.js.map +1 -1
  545. package/dist/core/session-image-store.d.ts +33 -0
  546. package/dist/core/session-image-store.d.ts.map +1 -0
  547. package/dist/core/session-image-store.js +283 -0
  548. package/dist/core/session-image-store.js.map +1 -0
  549. package/dist/core/session-role.d.ts +11 -4
  550. package/dist/core/session-role.d.ts.map +1 -1
  551. package/dist/core/session-role.js +24 -5
  552. package/dist/core/session-role.js.map +1 -1
  553. package/dist/core/session-snapshot.d.ts +34 -0
  554. package/dist/core/session-snapshot.d.ts.map +1 -0
  555. package/dist/core/session-snapshot.js +68 -0
  556. package/dist/core/session-snapshot.js.map +1 -0
  557. package/dist/core/session-supervision-runtime.d.ts +31 -0
  558. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  559. package/dist/core/session-supervision-runtime.js +97 -0
  560. package/dist/core/session-supervision-runtime.js.map +1 -0
  561. package/dist/core/session-tree-navigator.d.ts +4 -6
  562. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  563. package/dist/core/session-tree-navigator.js +4 -1
  564. package/dist/core/session-tree-navigator.js.map +1 -1
  565. package/dist/core/settings-manager.d.ts +10 -5
  566. package/dist/core/settings-manager.d.ts.map +1 -1
  567. package/dist/core/settings-manager.js +81 -29
  568. package/dist/core/settings-manager.js.map +1 -1
  569. package/dist/core/slash-commands.d.ts.map +1 -1
  570. package/dist/core/slash-commands.js +2 -2
  571. package/dist/core/slash-commands.js.map +1 -1
  572. package/dist/core/tasks/session-task-state.d.ts +2 -4
  573. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  574. package/dist/core/tasks/session-task-state.js +10 -28
  575. package/dist/core/tasks/session-task-state.js.map +1 -1
  576. package/dist/core/tasks/task-projection.d.ts +20 -0
  577. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  578. package/dist/core/tasks/task-projection.js +47 -0
  579. package/dist/core/tasks/task-projection.js.map +1 -0
  580. package/dist/core/tasks/task-state.d.ts +4 -0
  581. package/dist/core/tasks/task-state.d.ts.map +1 -1
  582. package/dist/core/tasks/task-state.js +28 -11
  583. package/dist/core/tasks/task-state.js.map +1 -1
  584. package/dist/core/tool-capability-policy.d.ts +13 -0
  585. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  586. package/dist/core/tool-capability-policy.js +86 -0
  587. package/dist/core/tool-capability-policy.js.map +1 -0
  588. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  589. package/dist/core/tool-gate-controller.js +8 -2
  590. package/dist/core/tool-gate-controller.js.map +1 -1
  591. package/dist/core/tool-protocol-controller.d.ts +89 -0
  592. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  593. package/dist/core/tool-protocol-controller.js +512 -0
  594. package/dist/core/tool-protocol-controller.js.map +1 -0
  595. package/dist/core/tool-recovery-log-records.d.ts +2 -3
  596. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  597. package/dist/core/tool-recovery-log-records.js +9 -35
  598. package/dist/core/tool-recovery-log-records.js.map +1 -1
  599. package/dist/core/tool-recovery-stats.d.ts +21 -1
  600. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  601. package/dist/core/tool-recovery-stats.js.map +1 -1
  602. package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
  603. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  604. package/dist/core/tool-selection/tool-performance-store.js +97 -138
  605. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  606. package/dist/core/tools/ask-question.d.ts +124 -0
  607. package/dist/core/tools/ask-question.d.ts.map +1 -0
  608. package/dist/core/tools/ask-question.js +693 -0
  609. package/dist/core/tools/ask-question.js.map +1 -0
  610. package/dist/core/tools/bash.d.ts +5 -0
  611. package/dist/core/tools/bash.d.ts.map +1 -1
  612. package/dist/core/tools/bash.js +59 -5
  613. package/dist/core/tools/bash.js.map +1 -1
  614. package/dist/core/tools/delegate-status.d.ts +31 -3
  615. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  616. package/dist/core/tools/delegate-status.js +148 -29
  617. package/dist/core/tools/delegate-status.js.map +1 -1
  618. package/dist/core/tools/delegate.d.ts +15 -13
  619. package/dist/core/tools/delegate.d.ts.map +1 -1
  620. package/dist/core/tools/delegate.js +106 -23
  621. package/dist/core/tools/delegate.js.map +1 -1
  622. package/dist/core/tools/extensionify.d.ts.map +1 -1
  623. package/dist/core/tools/extensionify.js +1 -0
  624. package/dist/core/tools/extensionify.js.map +1 -1
  625. package/dist/core/tools/git-filter.d.ts +1 -8
  626. package/dist/core/tools/git-filter.d.ts.map +1 -1
  627. package/dist/core/tools/git-filter.js +2 -63
  628. package/dist/core/tools/git-filter.js.map +1 -1
  629. package/dist/core/tools/goal.d.ts +10 -8
  630. package/dist/core/tools/goal.d.ts.map +1 -1
  631. package/dist/core/tools/goal.js +106 -28
  632. package/dist/core/tools/goal.js.map +1 -1
  633. package/dist/core/tools/index.d.ts +1 -0
  634. package/dist/core/tools/index.d.ts.map +1 -1
  635. package/dist/core/tools/index.js +1 -0
  636. package/dist/core/tools/index.js.map +1 -1
  637. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  638. package/dist/core/tools/model-fitness.js +2 -2
  639. package/dist/core/tools/model-fitness.js.map +1 -1
  640. package/dist/core/tools/orchestration-panel.d.ts +40 -0
  641. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  642. package/dist/core/tools/orchestration-panel.js +124 -0
  643. package/dist/core/tools/orchestration-panel.js.map +1 -0
  644. package/dist/core/tools/output-accumulator.d.ts +11 -0
  645. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  646. package/dist/core/tools/output-accumulator.js +36 -3
  647. package/dist/core/tools/output-accumulator.js.map +1 -1
  648. package/dist/core/tools/python.d.ts +2 -0
  649. package/dist/core/tools/python.d.ts.map +1 -1
  650. package/dist/core/tools/python.js +3 -1
  651. package/dist/core/tools/python.js.map +1 -1
  652. package/dist/core/tools/read.d.ts.map +1 -1
  653. package/dist/core/tools/read.js +1 -1
  654. package/dist/core/tools/read.js.map +1 -1
  655. package/dist/core/tools/run-process.d.ts +26 -0
  656. package/dist/core/tools/run-process.d.ts.map +1 -0
  657. package/dist/core/tools/run-process.js +138 -0
  658. package/dist/core/tools/run-process.js.map +1 -0
  659. package/dist/core/tools/search-command-guard.d.ts +14 -0
  660. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  661. package/dist/core/tools/search-command-guard.js +333 -0
  662. package/dist/core/tools/search-command-guard.js.map +1 -0
  663. package/dist/core/tools/secret-store.d.ts +38 -0
  664. package/dist/core/tools/secret-store.d.ts.map +1 -0
  665. package/dist/core/tools/secret-store.js +412 -0
  666. package/dist/core/tools/secret-store.js.map +1 -0
  667. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  668. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  669. package/dist/core/tools/shell-command-parser.js +113 -0
  670. package/dist/core/tools/shell-command-parser.js.map +1 -0
  671. package/dist/core/tools/task-steps.d.ts +2 -0
  672. package/dist/core/tools/task-steps.d.ts.map +1 -1
  673. package/dist/core/tools/task-steps.js +99 -0
  674. package/dist/core/tools/task-steps.js.map +1 -1
  675. package/dist/core/tools/tmux-dispatch.d.ts +3 -5
  676. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  677. package/dist/core/tools/tmux-dispatch.js +4 -4
  678. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  679. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  680. package/dist/core/tools/windows-shell-engine.js +4 -6
  681. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  682. package/dist/core/util/atomic-file.d.ts +6 -2
  683. package/dist/core/util/atomic-file.d.ts.map +1 -1
  684. package/dist/core/util/atomic-file.js +4 -4
  685. package/dist/core/util/atomic-file.js.map +1 -1
  686. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  687. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  688. package/dist/core/util/bounded-jsonl.js +75 -0
  689. package/dist/core/util/bounded-jsonl.js.map +1 -0
  690. package/dist/core/util/value-guards.d.ts +5 -0
  691. package/dist/core/util/value-guards.d.ts.map +1 -0
  692. package/dist/core/util/value-guards.js +12 -0
  693. package/dist/core/util/value-guards.js.map +1 -0
  694. package/dist/core/worktree-sync/store.d.ts +3 -3
  695. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  696. package/dist/core/worktree-sync/store.js +10 -5
  697. package/dist/core/worktree-sync/store.js.map +1 -1
  698. package/dist/index.d.ts +15 -4
  699. package/dist/index.d.ts.map +1 -1
  700. package/dist/index.js +14 -3
  701. package/dist/index.js.map +1 -1
  702. package/dist/main.d.ts.map +1 -1
  703. package/dist/main.js +149 -51
  704. package/dist/main.js.map +1 -1
  705. package/dist/migrations.d.ts +4 -6
  706. package/dist/migrations.d.ts.map +1 -1
  707. package/dist/migrations.js +186 -28
  708. package/dist/migrations.js.map +1 -1
  709. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  710. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  711. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  712. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  713. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  714. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  715. package/dist/modes/interactive/clipboard-input.js +44 -6
  716. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  717. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  718. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  719. package/dist/modes/interactive/components/activity-lane.js +304 -0
  720. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  721. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  722. package/dist/modes/interactive/components/assistant-message.js +19 -10
  723. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  724. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  725. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  726. package/dist/modes/interactive/components/expandable-text.js +17 -0
  727. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  728. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  729. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  730. package/dist/modes/interactive/components/extension-editor.js +30 -21
  731. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  732. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  733. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  734. package/dist/modes/interactive/components/extension-input.js +6 -1
  735. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  736. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  737. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  738. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  739. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  740. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  741. package/dist/modes/interactive/components/settings-selector.js +6 -6
  742. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  743. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  744. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  745. package/dist/modes/interactive/components/tool-execution.js +53 -20
  746. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  747. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  748. package/dist/modes/interactive/components/tool-group.js +3 -0
  749. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  750. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  751. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  752. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  753. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  754. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  755. package/dist/modes/interactive/config-backup.js +5 -4
  756. package/dist/modes/interactive/config-backup.js.map +1 -1
  757. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  758. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  759. package/dist/modes/interactive/extension-ui-host.js +77 -15
  760. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  761. package/dist/modes/interactive/external-editor.d.ts +15 -0
  762. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  763. package/dist/modes/interactive/external-editor.js +27 -19
  764. package/dist/modes/interactive/external-editor.js.map +1 -1
  765. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  766. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  767. package/dist/modes/interactive/history-reload-math.js +10 -5
  768. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  769. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  770. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  771. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  772. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  773. package/dist/modes/interactive/interactive-mode.d.ts +22 -24
  774. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  775. package/dist/modes/interactive/interactive-mode.js +245 -595
  776. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  777. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  778. package/dist/modes/interactive/key-handlers.js +1 -1
  779. package/dist/modes/interactive/key-handlers.js.map +1 -1
  780. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  781. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  782. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  783. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  784. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  785. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  786. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  787. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  788. package/dist/modes/interactive/report-commands.js +21 -0
  789. package/dist/modes/interactive/report-commands.js.map +1 -1
  790. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  791. package/dist/modes/interactive/resource-display.js +8 -2
  792. package/dist/modes/interactive/resource-display.js.map +1 -1
  793. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  794. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  795. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  796. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  797. package/dist/modes/interactive/session-flow-commands.d.ts +27 -8
  798. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  799. package/dist/modes/interactive/session-flow-commands.js +150 -64
  800. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  801. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  802. package/dist/modes/interactive/session-io-commands.js +16 -6
  803. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  804. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  805. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  806. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  807. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  808. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  809. package/dist/modes/interactive/startup-checks.js +1 -1
  810. package/dist/modes/interactive/startup-checks.js.map +1 -1
  811. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  812. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  813. package/dist/modes/interactive/usage-commands.js +225 -0
  814. package/dist/modes/interactive/usage-commands.js.map +1 -0
  815. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  816. package/dist/modes/rpc/rpc-mode.js +82 -23
  817. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  818. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  819. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  820. package/dist/modes/rpc/rpc-types.js +138 -1
  821. package/dist/modes/rpc/rpc-types.js.map +1 -1
  822. package/dist/utils/clipboard-image.d.ts.map +1 -1
  823. package/dist/utils/clipboard-image.js +2 -13
  824. package/dist/utils/clipboard-image.js.map +1 -1
  825. package/dist/utils/clipboard-native.d.ts +1 -0
  826. package/dist/utils/clipboard-native.d.ts.map +1 -1
  827. package/dist/utils/clipboard-native.js.map +1 -1
  828. package/dist/utils/clipboard.d.ts +1 -0
  829. package/dist/utils/clipboard.d.ts.map +1 -1
  830. package/dist/utils/clipboard.js +52 -1
  831. package/dist/utils/clipboard.js.map +1 -1
  832. package/dist/utils/platform.d.ts +3 -0
  833. package/dist/utils/platform.d.ts.map +1 -0
  834. package/dist/utils/platform.js +8 -0
  835. package/dist/utils/platform.js.map +1 -0
  836. package/dist/utils/shell.d.ts.map +1 -1
  837. package/dist/utils/shell.js +5 -3
  838. package/dist/utils/shell.js.map +1 -1
  839. package/dist/utils/version-check.d.ts.map +1 -1
  840. package/dist/utils/version-check.js +3 -1
  841. package/dist/utils/version-check.js.map +1 -1
  842. package/dist/utils/work-directory.d.ts +11 -0
  843. package/dist/utils/work-directory.d.ts.map +1 -1
  844. package/dist/utils/work-directory.js +30 -9
  845. package/dist/utils/work-directory.js.map +1 -1
  846. package/docs/UI_POLISH_ORCHESTRATION.md +38 -0
  847. package/docs/UI_QUALITY_ORCHESTRATION.md +28 -0
  848. package/docs/docs.json +4 -0
  849. package/docs/extensions.md +62 -2
  850. package/docs/harness-architecture.md +156 -0
  851. package/docs/keybindings.md +11 -1
  852. package/docs/process-matrix.md +59 -26
  853. package/docs/providers.md +9 -1
  854. package/docs/rpc.md +45 -2
  855. package/docs/sessions.md +15 -0
  856. package/docs/settings.md +125 -11
  857. package/docs/task-steps.md +8 -0
  858. package/docs/telemetry.md +19 -0
  859. package/docs/tmux-agent-manager.md +10 -3
  860. package/docs/ui-reference/README.md +9 -0
  861. package/docs/ui-reference/orchestration-after.txt +14 -0
  862. package/docs/ui-reference/orchestration-before.txt +13 -0
  863. package/docs/ui-reference/orchestration-reference.txt +16 -0
  864. package/docs/usage.md +22 -2
  865. package/docs/work-directory.md +19 -8
  866. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  867. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  868. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  869. package/examples/extensions/question.ts +34 -245
  870. package/examples/extensions/questionnaire.ts +41 -407
  871. package/examples/extensions/sandbox/package-lock.json +2 -2
  872. package/examples/extensions/sandbox/package.json +1 -1
  873. package/examples/extensions/with-deps/package-lock.json +2 -2
  874. package/examples/extensions/with-deps/package.json +1 -1
  875. package/npm-shrinkwrap.json +13 -13
  876. package/package.json +4 -4
  877. package/dist/core/delegation/session-worker-result.d.ts +0 -46
  878. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  879. package/dist/core/delegation/session-worker-result.js +0 -113
  880. package/dist/core/delegation/session-worker-result.js.map +0 -1
  881. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  882. package/dist/core/delegation/worker-result.js.map +0 -1
  883. package/dist/core/telemetry.d.ts.map +0 -1
  884. package/dist/core/telemetry.js.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { isPlainRecord } from "../util/value-guards.js";
1
2
  function cloneJsonValue(value) {
2
3
  if (Array.isArray(value)) {
3
4
  return value.map(cloneJsonValue);
@@ -10,12 +11,6 @@ function cloneJsonValue(value) {
10
11
  function cloneJsonObject(value) {
11
12
  return Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));
12
13
  }
13
- function isPlainRecord(value) {
14
- if (!value || typeof value !== "object" || Array.isArray(value))
15
- return false;
16
- const prototype = Object.getPrototypeOf(value);
17
- return prototype === Object.prototype || prototype === null;
18
- }
19
14
  function isJsonValue(value) {
20
15
  if (value === null || typeof value === "string" || typeof value === "boolean") {
21
16
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"evidence-bundle.js","sourceRoot":"","sources":["../../../src/core/research/evidence-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EvidenceBundle, EvidenceRef, Finding, JsonObject, JsonValue } from \"../autonomy/contracts.ts\";\n\nfunction cloneJsonValue(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cloneJsonValue);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n\t}\n\treturn value;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n\t\treturn true;\n\t}\n\tif (typeof value === \"number\") {\n\t\treturn Number.isFinite(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isJsonValue);\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn isJsonObject(value);\n\t}\n\treturn false;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n\tif (!isPlainRecord(value)) {\n\t\treturn false;\n\t}\n\treturn Object.values(value).every(isJsonValue);\n}\n\nfunction cloneEvidenceRef(source: EvidenceRef): EvidenceRef {\n\treturn {\n\t\t...source,\n\t\tmetadata: source.metadata ? cloneJsonObject(source.metadata) : undefined,\n\t};\n}\n\nfunction cloneFinding(finding: Finding): Finding {\n\treturn {\n\t\t...finding,\n\t\tevidenceIds: [...finding.evidenceIds],\n\t};\n}\n\nexport function createEvidenceBundle(args: {\n\tquery: string;\n\tsources: readonly EvidenceRef[];\n\tfindings: readonly Finding[];\n\tnow?: string;\n}): EvidenceBundle {\n\treturn {\n\t\tquery: args.query,\n\t\tsources: args.sources.map(cloneEvidenceRef),\n\t\tfindings: args.findings.map(cloneFinding),\n\t\tcreatedAt: args.now,\n\t};\n}\n\nexport function cloneEvidenceBundleForStorage(bundle: EvidenceBundle): EvidenceBundle {\n\treturn {\n\t\tquery: bundle.query,\n\t\tsources: bundle.sources.map(cloneEvidenceRef),\n\t\tfindings: bundle.findings.map(cloneFinding),\n\t\tcreatedAt: bundle.createdAt,\n\t};\n}\n\nexport function isEvidenceBundle(value: unknown): value is EvidenceBundle {\n\tif (!isPlainRecord(value)) return false;\n\tconst bundle = value as Record<string, unknown>;\n\n\tif (typeof bundle.query !== \"string\") return false;\n\tif (bundle.createdAt !== undefined && typeof bundle.createdAt !== \"string\") return false;\n\n\tif (!Array.isArray(bundle.sources)) return false;\n\tfor (const source of bundle.sources) {\n\t\tif (!isPlainRecord(source)) return false;\n\t\tconst ref = source as Record<string, unknown>;\n\t\tif (typeof ref.id !== \"string\") return false;\n\t\tif (\n\t\t\ttypeof ref.kind !== \"string\" ||\n\t\t\t![\"workspace\", \"transcript\", \"automata\", \"web\", \"user\", \"tool\"].includes(ref.kind)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof ref.trusted !== \"boolean\") return false;\n\t\tif (ref.title !== undefined && typeof ref.title !== \"string\") return false;\n\t\tif (ref.uri !== undefined && typeof ref.uri !== \"string\") return false;\n\t\tif (ref.excerpt !== undefined && typeof ref.excerpt !== \"string\") return false;\n\t\tif (ref.metadata !== undefined && !isJsonObject(ref.metadata)) return false;\n\t}\n\n\tif (!Array.isArray(bundle.findings)) return false;\n\tfor (const finding of bundle.findings) {\n\t\tif (!isPlainRecord(finding)) return false;\n\t\tconst f = finding as Record<string, unknown>;\n\t\tif (typeof f.id !== \"string\") return false;\n\t\tif (typeof f.summary !== \"string\") return false;\n\t\tif (f.confidence !== undefined && (typeof f.confidence !== \"number\" || !Number.isFinite(f.confidence)))\n\t\t\treturn false;\n\t\tif (!Array.isArray(f.evidenceIds) || !f.evidenceIds.every((id) => typeof id === \"string\")) return false;\n\t}\n\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"evidence-bundle.js","sourceRoot":"","sources":["../../../src/core/research/evidence-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EvidenceBundle, EvidenceRef, Finding, JsonObject, JsonValue } from \"../autonomy/contracts.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\n\nfunction cloneJsonValue(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cloneJsonValue);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n\t}\n\treturn value;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n\t\treturn true;\n\t}\n\tif (typeof value === \"number\") {\n\t\treturn Number.isFinite(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isJsonValue);\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn isJsonObject(value);\n\t}\n\treturn false;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n\tif (!isPlainRecord(value)) {\n\t\treturn false;\n\t}\n\treturn Object.values(value).every(isJsonValue);\n}\n\nfunction cloneEvidenceRef(source: EvidenceRef): EvidenceRef {\n\treturn {\n\t\t...source,\n\t\tmetadata: source.metadata ? cloneJsonObject(source.metadata) : undefined,\n\t};\n}\n\nfunction cloneFinding(finding: Finding): Finding {\n\treturn {\n\t\t...finding,\n\t\tevidenceIds: [...finding.evidenceIds],\n\t};\n}\n\nexport function createEvidenceBundle(args: {\n\tquery: string;\n\tsources: readonly EvidenceRef[];\n\tfindings: readonly Finding[];\n\tnow?: string;\n}): EvidenceBundle {\n\treturn {\n\t\tquery: args.query,\n\t\tsources: args.sources.map(cloneEvidenceRef),\n\t\tfindings: args.findings.map(cloneFinding),\n\t\tcreatedAt: args.now,\n\t};\n}\n\nexport function cloneEvidenceBundleForStorage(bundle: EvidenceBundle): EvidenceBundle {\n\treturn {\n\t\tquery: bundle.query,\n\t\tsources: bundle.sources.map(cloneEvidenceRef),\n\t\tfindings: bundle.findings.map(cloneFinding),\n\t\tcreatedAt: bundle.createdAt,\n\t};\n}\n\nexport function isEvidenceBundle(value: unknown): value is EvidenceBundle {\n\tif (!isPlainRecord(value)) return false;\n\tconst bundle = value as Record<string, unknown>;\n\n\tif (typeof bundle.query !== \"string\") return false;\n\tif (bundle.createdAt !== undefined && typeof bundle.createdAt !== \"string\") return false;\n\n\tif (!Array.isArray(bundle.sources)) return false;\n\tfor (const source of bundle.sources) {\n\t\tif (!isPlainRecord(source)) return false;\n\t\tconst ref = source as Record<string, unknown>;\n\t\tif (typeof ref.id !== \"string\") return false;\n\t\tif (\n\t\t\ttypeof ref.kind !== \"string\" ||\n\t\t\t![\"workspace\", \"transcript\", \"automata\", \"web\", \"user\", \"tool\"].includes(ref.kind)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof ref.trusted !== \"boolean\") return false;\n\t\tif (ref.title !== undefined && typeof ref.title !== \"string\") return false;\n\t\tif (ref.uri !== undefined && typeof ref.uri !== \"string\") return false;\n\t\tif (ref.excerpt !== undefined && typeof ref.excerpt !== \"string\") return false;\n\t\tif (ref.metadata !== undefined && !isJsonObject(ref.metadata)) return false;\n\t}\n\n\tif (!Array.isArray(bundle.findings)) return false;\n\tfor (const finding of bundle.findings) {\n\t\tif (!isPlainRecord(finding)) return false;\n\t\tconst f = finding as Record<string, unknown>;\n\t\tif (typeof f.id !== \"string\") return false;\n\t\tif (typeof f.summary !== \"string\") return false;\n\t\tif (f.confidence !== undefined && (typeof f.confidence !== \"number\" || !Number.isFinite(f.confidence)))\n\t\t\treturn false;\n\t\tif (!Array.isArray(f.evidenceIds) || !f.evidenceIds.every((id) => typeof id === \"string\")) return false;\n\t}\n\n\treturn true;\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import type { Api, Model } from "@caupulican/pi-ai";
2
+ import { type ModelCapabilityProfile } from "../model-capability.ts";
3
+ import type { ModelRegistry } from "../model-registry.ts";
4
+ import type { NormalizedProfile } from "../profile-registry.ts";
5
+ import type { SettingsManager } from "../settings-manager.ts";
6
+ export interface LaneModelResolverDeps {
7
+ getCwd(): string;
8
+ getModel(): Model<Api> | undefined;
9
+ getModelRegistry(): ModelRegistry;
10
+ getSettingsManager(): SettingsManager;
11
+ isModelExhausted(model: Model<Api>): boolean;
12
+ }
13
+ export type LaneShipment = {
14
+ ok: true;
15
+ model: Model<Api>;
16
+ laneProfile?: NormalizedProfile;
17
+ } | {
18
+ ok: false;
19
+ skipReason: string;
20
+ };
21
+ export declare function clampLaneMaxUsd(settingsMaxUsd: number, foregroundMaxEstimatedUsd?: number): number;
22
+ /** Shared provider-neutral model/profile resolution for research and fitness lanes. */
23
+ export declare class LaneModelResolver {
24
+ private readonly deps;
25
+ constructor(deps: LaneModelResolverDeps);
26
+ capabilityProfile(model: Model<Api>): ModelCapabilityProfile;
27
+ resolveModel(configuredPattern: string | undefined): Model<Api> | undefined;
28
+ resolveShipment(laneSettings: {
29
+ model?: string;
30
+ profile?: string;
31
+ }, missingModelReason: string): LaneShipment;
32
+ }
33
+ //# sourceMappingURL=lane-model-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane-model-resolver.d.ts","sourceRoot":"","sources":["../../../src/core/research/lane-model-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAgC,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACrC,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACnC,gBAAgB,IAAI,aAAa,CAAC;IAClC,kBAAkB,IAAI,eAAe,CAAC;IACtC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;CAC7C;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAAC,WAAW,CAAC,EAAE,iBAAiB,CAAA;CAAE,GAChE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,yBAAyB,CAAC,EAAE,MAAM,GAAG,MAAM,CAElG;AAED,uFAAuF;AACvF,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAE7C,YAAY,IAAI,EAAE,qBAAqB,EAEtC;IAED,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,sBAAsB,CAK3D;IAED,YAAY,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAY1E;IAED,eAAe,CAAC,YAAY,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,kBAAkB,EAAE,MAAM,GAAG,YAAY,CA2B5G;CACD","sourcesContent":["import type { Api, Model } from \"@caupulican/pi-ai\";\nimport { deriveModelCapabilityProfile, type ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { ModelRegistry } from \"../model-registry.ts\";\nimport { resolveCliModel } from \"../model-resolver.ts\";\nimport type { NormalizedProfile } from \"../profile-registry.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\n\nexport interface LaneModelResolverDeps {\n\tgetCwd(): string;\n\tgetModel(): Model<Api> | undefined;\n\tgetModelRegistry(): ModelRegistry;\n\tgetSettingsManager(): SettingsManager;\n\tisModelExhausted(model: Model<Api>): boolean;\n}\n\nexport type LaneShipment =\n\t| { ok: true; model: Model<Api>; laneProfile?: NormalizedProfile }\n\t| { ok: false; skipReason: string };\n\nexport function clampLaneMaxUsd(settingsMaxUsd: number, foregroundMaxEstimatedUsd?: number): number {\n\treturn Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);\n}\n\n/** Shared provider-neutral model/profile resolution for research and fitness lanes. */\nexport class LaneModelResolver {\n\tprivate readonly deps: LaneModelResolverDeps;\n\n\tconstructor(deps: LaneModelResolverDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tcapabilityProfile(model: Model<Api>): ModelCapabilityProfile {\n\t\treturn deriveModelCapabilityProfile({\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t});\n\t}\n\n\tresolveModel(configuredPattern: string | undefined): Model<Api> | undefined {\n\t\tif (configuredPattern) {\n\t\t\tconst resolved = resolveCliModel({\n\t\t\t\tcliModel: configuredPattern,\n\t\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t\t});\n\t\t\tif (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\t\treturn resolved.model;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.deps.getModel() ?? undefined;\n\t}\n\n\tresolveShipment(laneSettings: { model?: string; profile?: string }, missingModelReason: string): LaneShipment {\n\t\tlet laneProfile: NormalizedProfile | undefined;\n\t\tif (laneSettings.profile) {\n\t\t\tconst profileRef = laneSettings.profile.trim();\n\t\t\tconst registry = this.deps.getSettingsManager().getProfileRegistry();\n\t\t\tlaneProfile =\n\t\t\t\tprofileRef.startsWith(\"./\") || profileRef.startsWith(\"../\")\n\t\t\t\t\t? registry.resolveProfileRef(profileRef, this.deps.getCwd())\n\t\t\t\t\t: registry.getProfile(profileRef);\n\t\t\tif (!laneProfile) return { ok: false, skipReason: \"lane_profile_not_found\" };\n\t\t}\n\n\t\tlet model: Model<Api> | undefined;\n\t\tif (laneSettings.model) {\n\t\t\tmodel = this.resolveModel(laneSettings.model);\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t} else if (laneProfile?.model) {\n\t\t\tmodel = this.resolveModel(laneProfile.model);\n\t\t\tif (!model) return { ok: false, skipReason: \"no_lane_profile_model\" };\n\t\t} else {\n\t\t\tmodel = this.deps.getModel() ?? undefined;\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t}\n\t\tif (this.deps.isModelExhausted(model)) {\n\t\t\treturn { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };\n\t\t}\n\t\treturn { ok: true, model, laneProfile };\n\t}\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import { deriveModelCapabilityProfile } from "../model-capability.js";
2
+ import { resolveCliModel } from "../model-resolver.js";
3
+ export function clampLaneMaxUsd(settingsMaxUsd, foregroundMaxEstimatedUsd) {
4
+ return Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);
5
+ }
6
+ /** Shared provider-neutral model/profile resolution for research and fitness lanes. */
7
+ export class LaneModelResolver {
8
+ deps;
9
+ constructor(deps) {
10
+ this.deps = deps;
11
+ }
12
+ capabilityProfile(model) {
13
+ return deriveModelCapabilityProfile({
14
+ contextWindow: model.contextWindow,
15
+ mode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,
16
+ });
17
+ }
18
+ resolveModel(configuredPattern) {
19
+ if (configuredPattern) {
20
+ const resolved = resolveCliModel({
21
+ cliModel: configuredPattern,
22
+ modelRegistry: this.deps.getModelRegistry(),
23
+ });
24
+ if (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {
25
+ return resolved.model;
26
+ }
27
+ return undefined;
28
+ }
29
+ return this.deps.getModel() ?? undefined;
30
+ }
31
+ resolveShipment(laneSettings, missingModelReason) {
32
+ let laneProfile;
33
+ if (laneSettings.profile) {
34
+ const profileRef = laneSettings.profile.trim();
35
+ const registry = this.deps.getSettingsManager().getProfileRegistry();
36
+ laneProfile =
37
+ profileRef.startsWith("./") || profileRef.startsWith("../")
38
+ ? registry.resolveProfileRef(profileRef, this.deps.getCwd())
39
+ : registry.getProfile(profileRef);
40
+ if (!laneProfile)
41
+ return { ok: false, skipReason: "lane_profile_not_found" };
42
+ }
43
+ let model;
44
+ if (laneSettings.model) {
45
+ model = this.resolveModel(laneSettings.model);
46
+ if (!model)
47
+ return { ok: false, skipReason: missingModelReason };
48
+ }
49
+ else if (laneProfile?.model) {
50
+ model = this.resolveModel(laneProfile.model);
51
+ if (!model)
52
+ return { ok: false, skipReason: "no_lane_profile_model" };
53
+ }
54
+ else {
55
+ model = this.deps.getModel() ?? undefined;
56
+ if (!model)
57
+ return { ok: false, skipReason: missingModelReason };
58
+ }
59
+ if (this.deps.isModelExhausted(model)) {
60
+ return { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };
61
+ }
62
+ return { ok: true, model, laneProfile };
63
+ }
64
+ }
65
+ //# sourceMappingURL=lane-model-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane-model-resolver.js","sourceRoot":"","sources":["../../../src/core/research/lane-model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, Model } from \"@caupulican/pi-ai\";\nimport { deriveModelCapabilityProfile, type ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { ModelRegistry } from \"../model-registry.ts\";\nimport { resolveCliModel } from \"../model-resolver.ts\";\nimport type { NormalizedProfile } from \"../profile-registry.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\n\nexport interface LaneModelResolverDeps {\n\tgetCwd(): string;\n\tgetModel(): Model<Api> | undefined;\n\tgetModelRegistry(): ModelRegistry;\n\tgetSettingsManager(): SettingsManager;\n\tisModelExhausted(model: Model<Api>): boolean;\n}\n\nexport type LaneShipment =\n\t| { ok: true; model: Model<Api>; laneProfile?: NormalizedProfile }\n\t| { ok: false; skipReason: string };\n\nexport function clampLaneMaxUsd(settingsMaxUsd: number, foregroundMaxEstimatedUsd?: number): number {\n\treturn Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);\n}\n\n/** Shared provider-neutral model/profile resolution for research and fitness lanes. */\nexport class LaneModelResolver {\n\tprivate readonly deps: LaneModelResolverDeps;\n\n\tconstructor(deps: LaneModelResolverDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tcapabilityProfile(model: Model<Api>): ModelCapabilityProfile {\n\t\treturn deriveModelCapabilityProfile({\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t});\n\t}\n\n\tresolveModel(configuredPattern: string | undefined): Model<Api> | undefined {\n\t\tif (configuredPattern) {\n\t\t\tconst resolved = resolveCliModel({\n\t\t\t\tcliModel: configuredPattern,\n\t\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t\t});\n\t\t\tif (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\t\treturn resolved.model;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.deps.getModel() ?? undefined;\n\t}\n\n\tresolveShipment(laneSettings: { model?: string; profile?: string }, missingModelReason: string): LaneShipment {\n\t\tlet laneProfile: NormalizedProfile | undefined;\n\t\tif (laneSettings.profile) {\n\t\t\tconst profileRef = laneSettings.profile.trim();\n\t\t\tconst registry = this.deps.getSettingsManager().getProfileRegistry();\n\t\t\tlaneProfile =\n\t\t\t\tprofileRef.startsWith(\"./\") || profileRef.startsWith(\"../\")\n\t\t\t\t\t? registry.resolveProfileRef(profileRef, this.deps.getCwd())\n\t\t\t\t\t: registry.getProfile(profileRef);\n\t\t\tif (!laneProfile) return { ok: false, skipReason: \"lane_profile_not_found\" };\n\t\t}\n\n\t\tlet model: Model<Api> | undefined;\n\t\tif (laneSettings.model) {\n\t\t\tmodel = this.resolveModel(laneSettings.model);\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t} else if (laneProfile?.model) {\n\t\t\tmodel = this.resolveModel(laneProfile.model);\n\t\t\tif (!model) return { ok: false, skipReason: \"no_lane_profile_model\" };\n\t\t} else {\n\t\t\tmodel = this.deps.getModel() ?? undefined;\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t}\n\t\tif (this.deps.isModelExhausted(model)) {\n\t\t\treturn { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };\n\t\t}\n\t\treturn { ok: true, model, laneProfile };\n\t}\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type { Usage } from "@caupulican/pi-ai";
2
+ import type { IsolatedCompletionOptions, IsolatedCompletionResult } from "../agent-session.ts";
3
+ import { type StoredFitnessReport } from "../models/fitness-store.ts";
4
+ import type { LaneModelResolver } from "./lane-model-resolver.ts";
5
+ import { type ModelFitnessReport } from "./model-fitness.ts";
6
+ export interface ModelFitnessControllerDeps {
7
+ isDisposed(): boolean;
8
+ getSessionId(): string;
9
+ getAgentDir(): string;
10
+ addSpawnedUsage(usage: Usage, opts: {
11
+ label?: string;
12
+ sourceSessionId?: string;
13
+ reportId: string;
14
+ }): string | undefined;
15
+ runIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;
16
+ }
17
+ /** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */
18
+ export declare class ModelFitnessController {
19
+ private readonly abortController;
20
+ private readonly deps;
21
+ private readonly models;
22
+ constructor(deps: ModelFitnessControllerDeps, models: LaneModelResolver);
23
+ abort(): void;
24
+ run(args: {
25
+ model: string;
26
+ trials?: number;
27
+ toolCallId?: string;
28
+ }): Promise<{
29
+ started: true;
30
+ model: string;
31
+ report: ModelFitnessReport;
32
+ } | {
33
+ started: false;
34
+ skipReason: string;
35
+ }>;
36
+ getStoredReports(): StoredFitnessReport[];
37
+ }
38
+ //# sourceMappingURL=model-fitness-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-fitness-controller.d.ts","sourceRoot":"","sources":["../../../src/core/research/model-fitness-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/F,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,KAAK,kBAAkB,EAAwB,MAAM,oBAAoB,CAAC;AAEnF,MAAM,WAAW,0BAA0B;IAC1C,UAAU,IAAI,OAAO,CAAC;IACtB,YAAY,IAAI,MAAM,CAAC;IACvB,WAAW,IAAI,MAAM,CAAC;IACtB,eAAe,CACd,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAClE,MAAM,GAAG,SAAS,CAAC;IACtB,qBAAqB,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC1F;AAOD,0FAA0F;AAC1F,qBAAa,sBAAsB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;IACzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C,YAAY,IAAI,EAAE,0BAA0B,EAAE,MAAM,EAAE,iBAAiB,EAGtE;IAED,KAAK,IAAI,IAAI,CAEZ;IAEK,GAAG,CAAC,IAAI,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,kBAAkB,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CA2EjH;IAED,gBAAgB,IAAI,mBAAmB,EAAE,CAMxC;CACD","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\nimport type { IsolatedCompletionOptions, IsolatedCompletionResult } from \"../agent-session.ts\";\nimport { FitnessStore, type StoredFitnessReport } from \"../models/fitness-store.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport type { LaneModelResolver } from \"./lane-model-resolver.ts\";\nimport { type ModelFitnessReport, runModelFitnessProbe } from \"./model-fitness.ts\";\n\nexport interface ModelFitnessControllerDeps {\n\tisDisposed(): boolean;\n\tgetSessionId(): string;\n\tgetAgentDir(): string;\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts: { label?: string; sourceSessionId?: string; reportId: string },\n\t): string | undefined;\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\nfunction deriveSpawnedUsageReportId(kind: string, sessionId: string, identity: string): string {\n\tconst digest = createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 16);\n\treturn `${kind}:${sessionId}:${digest}`;\n}\n\n/** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */\nexport class ModelFitnessController {\n\tprivate readonly abortController = new AbortController();\n\tprivate readonly deps: ModelFitnessControllerDeps;\n\tprivate readonly models: LaneModelResolver;\n\n\tconstructor(deps: ModelFitnessControllerDeps, models: LaneModelResolver) {\n\t\tthis.deps = deps;\n\t\tthis.models = models;\n\t}\n\n\tabort(): void {\n\t\tthis.abortController.abort();\n\t}\n\n\tasync run(args: {\n\t\tmodel: string;\n\t\ttrials?: number;\n\t\ttoolCallId?: string;\n\t}): Promise<{ started: true; model: string; report: ModelFitnessReport } | { started: false; skipReason: string }> {\n\t\tif (this.deps.isDisposed()) return { started: false, skipReason: \"session_disposed\" };\n\t\tconst resolved = this.models.resolveModel(args.model.trim() || undefined);\n\t\tif (!resolved) return { started: false, skipReason: \"model_unresolved_or_unauthenticated\" };\n\t\tconst capability = this.models.capabilityProfile(resolved);\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"lane\",\n\t\t\t`fitness:${resolved.provider}/${resolved.id}`,\n\t\t);\n\t\ttry {\n\t\t\tconst spent: Usage = {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\tconst report = await runModelFitnessProbe({\n\t\t\t\ttrials: args.trials,\n\t\t\t\tsignal: this.abortController.signal,\n\t\t\t\tcapacityProbe:\n\t\t\t\t\tresolved.provider === \"ollama\" && resolved.contextWindow > 0\n\t\t\t\t\t\t? { registeredContextWindow: resolved.contextWindow }\n\t\t\t\t\t\t: undefined,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst callStarted = Date.now();\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel: resolved,\n\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\tmaxTokens: capability.laneMaxOutputTokens,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\tlaneKind: \"fitness\",\n\t\t\t\t\t});\n\t\t\t\t\tconst callMs = Date.now() - callStarted;\n\t\t\t\t\tspent.input += completion.usage.input;\n\t\t\t\t\tspent.output += completion.usage.output;\n\t\t\t\t\tspent.cacheRead += completion.usage.cacheRead;\n\t\t\t\t\tspent.cacheWrite += completion.usage.cacheWrite;\n\t\t\t\t\tspent.totalTokens += completion.usage.totalTokens;\n\t\t\t\t\tspent.cost.input += completion.usage.cost.input;\n\t\t\t\t\tspent.cost.output += completion.usage.cost.output;\n\t\t\t\t\tspent.cost.cacheRead += completion.usage.cost.cacheRead;\n\t\t\t\t\tspent.cost.cacheWrite += completion.usage.cost.cacheWrite;\n\t\t\t\t\tspent.cost.total += completion.usage.cost.total;\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\toutputTokens: completion.usage.output,\n\t\t\t\t\t\tevalMs: callMs,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst modelRef = `${resolved.provider}/${resolved.id}`;\n\t\t\tif (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {\n\t\t\t\tconst identity = args.toolCallId\n\t\t\t\t\t? `toolcall:${args.toolCallId}`\n\t\t\t\t\t: `${modelRef} ${args.trials ?? \"default\"}`;\n\t\t\t\tconst reportId = deriveSpawnedUsageReportId(\"model-fitness\", this.deps.getSessionId(), identity);\n\t\t\t\tthis.deps.addSpawnedUsage(spent, { label: \"model-fitness\", reportId });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (!this.deps.isDisposed()) FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);\n\t\t\t} catch {\n\t\t\t\t// Best-effort persistence must not fail the probe.\n\t\t\t}\n\t\t\treturn { started: true, model: modelRef, report };\n\t\t} finally {\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\tgetStoredReports(): StoredFitnessReport[] {\n\t\ttry {\n\t\t\treturn FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,106 @@
1
+ import { createHash } from "node:crypto";
2
+ import { FitnessStore } from "../models/fitness-store.js";
3
+ import { registerInFlightWork } from "../reload-blockers.js";
4
+ import { runModelFitnessProbe } from "./model-fitness.js";
5
+ function deriveSpawnedUsageReportId(kind, sessionId, identity) {
6
+ const digest = createHash("sha256").update(identity).digest("hex").slice(0, 16);
7
+ return `${kind}:${sessionId}:${digest}`;
8
+ }
9
+ /** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */
10
+ export class ModelFitnessController {
11
+ abortController = new AbortController();
12
+ deps;
13
+ models;
14
+ constructor(deps, models) {
15
+ this.deps = deps;
16
+ this.models = models;
17
+ }
18
+ abort() {
19
+ this.abortController.abort();
20
+ }
21
+ async run(args) {
22
+ if (this.deps.isDisposed())
23
+ return { started: false, skipReason: "session_disposed" };
24
+ const resolved = this.models.resolveModel(args.model.trim() || undefined);
25
+ if (!resolved)
26
+ return { started: false, skipReason: "model_unresolved_or_unauthenticated" };
27
+ const capability = this.models.capabilityProfile(resolved);
28
+ const deregisterInFlight = registerInFlightWork(this.deps.getAgentDir(), "lane", `fitness:${resolved.provider}/${resolved.id}`);
29
+ try {
30
+ const spent = {
31
+ input: 0,
32
+ output: 0,
33
+ cacheRead: 0,
34
+ cacheWrite: 0,
35
+ totalTokens: 0,
36
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
37
+ };
38
+ const report = await runModelFitnessProbe({
39
+ trials: args.trials,
40
+ signal: this.abortController.signal,
41
+ capacityProbe: resolved.provider === "ollama" && resolved.contextWindow > 0
42
+ ? { registeredContextWindow: resolved.contextWindow }
43
+ : undefined,
44
+ complete: async ({ systemPrompt, userPrompt, signal }) => {
45
+ const callStarted = Date.now();
46
+ const completion = await this.deps.runIsolatedCompletion({
47
+ systemPrompt,
48
+ messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
49
+ model: resolved,
50
+ thinkingLevel: "off",
51
+ maxTokens: capability.laneMaxOutputTokens,
52
+ signal,
53
+ cacheRetention: "short",
54
+ laneKind: "fitness",
55
+ });
56
+ const callMs = Date.now() - callStarted;
57
+ spent.input += completion.usage.input;
58
+ spent.output += completion.usage.output;
59
+ spent.cacheRead += completion.usage.cacheRead;
60
+ spent.cacheWrite += completion.usage.cacheWrite;
61
+ spent.totalTokens += completion.usage.totalTokens;
62
+ spent.cost.input += completion.usage.cost.input;
63
+ spent.cost.output += completion.usage.cost.output;
64
+ spent.cost.cacheRead += completion.usage.cost.cacheRead;
65
+ spent.cost.cacheWrite += completion.usage.cost.cacheWrite;
66
+ spent.cost.total += completion.usage.cost.total;
67
+ return {
68
+ text: completion.text,
69
+ costUsd: completion.usage.cost.total,
70
+ stopReason: String(completion.stopReason),
71
+ outputTokens: completion.usage.output,
72
+ evalMs: callMs,
73
+ };
74
+ },
75
+ });
76
+ const modelRef = `${resolved.provider}/${resolved.id}`;
77
+ if (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {
78
+ const identity = args.toolCallId
79
+ ? `toolcall:${args.toolCallId}`
80
+ : `${modelRef} ${args.trials ?? "default"}`;
81
+ const reportId = deriveSpawnedUsageReportId("model-fitness", this.deps.getSessionId(), identity);
82
+ this.deps.addSpawnedUsage(spent, { label: "model-fitness", reportId });
83
+ }
84
+ try {
85
+ if (!this.deps.isDisposed())
86
+ FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);
87
+ }
88
+ catch {
89
+ // Best-effort persistence must not fail the probe.
90
+ }
91
+ return { started: true, model: modelRef, report };
92
+ }
93
+ finally {
94
+ deregisterInFlight();
95
+ }
96
+ }
97
+ getStoredReports() {
98
+ try {
99
+ return FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();
100
+ }
101
+ catch {
102
+ return [];
103
+ }
104
+ }
105
+ }
106
+ //# sourceMappingURL=model-fitness-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-fitness-controller.js","sourceRoot":"","sources":["../../../src/core/research/model-fitness-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\nimport type { IsolatedCompletionOptions, IsolatedCompletionResult } from \"../agent-session.ts\";\nimport { FitnessStore, type StoredFitnessReport } from \"../models/fitness-store.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport type { LaneModelResolver } from \"./lane-model-resolver.ts\";\nimport { type ModelFitnessReport, runModelFitnessProbe } from \"./model-fitness.ts\";\n\nexport interface ModelFitnessControllerDeps {\n\tisDisposed(): boolean;\n\tgetSessionId(): string;\n\tgetAgentDir(): string;\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts: { label?: string; sourceSessionId?: string; reportId: string },\n\t): string | undefined;\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\nfunction deriveSpawnedUsageReportId(kind: string, sessionId: string, identity: string): string {\n\tconst digest = createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 16);\n\treturn `${kind}:${sessionId}:${digest}`;\n}\n\n/** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */\nexport class ModelFitnessController {\n\tprivate readonly abortController = new AbortController();\n\tprivate readonly deps: ModelFitnessControllerDeps;\n\tprivate readonly models: LaneModelResolver;\n\n\tconstructor(deps: ModelFitnessControllerDeps, models: LaneModelResolver) {\n\t\tthis.deps = deps;\n\t\tthis.models = models;\n\t}\n\n\tabort(): void {\n\t\tthis.abortController.abort();\n\t}\n\n\tasync run(args: {\n\t\tmodel: string;\n\t\ttrials?: number;\n\t\ttoolCallId?: string;\n\t}): Promise<{ started: true; model: string; report: ModelFitnessReport } | { started: false; skipReason: string }> {\n\t\tif (this.deps.isDisposed()) return { started: false, skipReason: \"session_disposed\" };\n\t\tconst resolved = this.models.resolveModel(args.model.trim() || undefined);\n\t\tif (!resolved) return { started: false, skipReason: \"model_unresolved_or_unauthenticated\" };\n\t\tconst capability = this.models.capabilityProfile(resolved);\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"lane\",\n\t\t\t`fitness:${resolved.provider}/${resolved.id}`,\n\t\t);\n\t\ttry {\n\t\t\tconst spent: Usage = {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\tconst report = await runModelFitnessProbe({\n\t\t\t\ttrials: args.trials,\n\t\t\t\tsignal: this.abortController.signal,\n\t\t\t\tcapacityProbe:\n\t\t\t\t\tresolved.provider === \"ollama\" && resolved.contextWindow > 0\n\t\t\t\t\t\t? { registeredContextWindow: resolved.contextWindow }\n\t\t\t\t\t\t: undefined,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst callStarted = Date.now();\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel: resolved,\n\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\tmaxTokens: capability.laneMaxOutputTokens,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\tlaneKind: \"fitness\",\n\t\t\t\t\t});\n\t\t\t\t\tconst callMs = Date.now() - callStarted;\n\t\t\t\t\tspent.input += completion.usage.input;\n\t\t\t\t\tspent.output += completion.usage.output;\n\t\t\t\t\tspent.cacheRead += completion.usage.cacheRead;\n\t\t\t\t\tspent.cacheWrite += completion.usage.cacheWrite;\n\t\t\t\t\tspent.totalTokens += completion.usage.totalTokens;\n\t\t\t\t\tspent.cost.input += completion.usage.cost.input;\n\t\t\t\t\tspent.cost.output += completion.usage.cost.output;\n\t\t\t\t\tspent.cost.cacheRead += completion.usage.cost.cacheRead;\n\t\t\t\t\tspent.cost.cacheWrite += completion.usage.cost.cacheWrite;\n\t\t\t\t\tspent.cost.total += completion.usage.cost.total;\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\toutputTokens: completion.usage.output,\n\t\t\t\t\t\tevalMs: callMs,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst modelRef = `${resolved.provider}/${resolved.id}`;\n\t\t\tif (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {\n\t\t\t\tconst identity = args.toolCallId\n\t\t\t\t\t? `toolcall:${args.toolCallId}`\n\t\t\t\t\t: `${modelRef} ${args.trials ?? \"default\"}`;\n\t\t\t\tconst reportId = deriveSpawnedUsageReportId(\"model-fitness\", this.deps.getSessionId(), identity);\n\t\t\t\tthis.deps.addSpawnedUsage(spent, { label: \"model-fitness\", reportId });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (!this.deps.isDisposed()) FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);\n\t\t\t} catch {\n\t\t\t\t// Best-effort persistence must not fail the probe.\n\t\t\t}\n\t\t\treturn { started: true, model: modelRef, report };\n\t\t} finally {\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\tgetStoredReports(): StoredFitnessReport[] {\n\t\ttry {\n\t\t\treturn FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Model fitness probe: measures whether a candidate model can actually drive the harness's
3
- * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by
3
+ * subagent contracts — the research lane, the delegated-worker lane, and the routing judge — by
4
4
  * running each real runner against the model and scoring parse/success rates plus judge
5
5
  * discrimination. Provider-free: the completion executor is injected, so this works against any
6
6
  * registered model (local Ollama models included) and against faux providers in tests.
@@ -1 +1 @@
1
- {"version":3,"file":"model-fitness.d.ts","sourceRoot":"","sources":["../../../src/core/research/model-fitness.ts"],"names":[],"mappings":"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","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { CapabilityEnvelope } from \"../autonomy/contracts.ts\";\nimport { CURATION_DIGEST_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\nimport { runWorker } from \"../delegation/worker-runner.ts\";\nimport { runRouteJudge } from \"../model-router/route-judge.ts\";\nimport { runResearch } from \"./research-runner.ts\";\n\n/**\n * Model fitness probe: measures whether a candidate model can actually drive the harness's\n * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by\n * running each real runner against the model and scoring parse/success rates plus judge\n * discrimination. Provider-free: the completion executor is injected, so this works against any\n * registered model (local Ollama models included) and against faux providers in tests.\n */\n\nexport interface FitnessCompletion {\n\ttext: string;\n\tcostUsd: number;\n\tstopReason: string;\n\t/** Output tokens generated (for tok/s). Optional: providers that don't report it are skipped. */\n\toutputTokens?: number;\n\t/** Pure generation time in ms (e.g. Ollama eval_duration). Falls back to wall-clock if absent. */\n\tevalMs?: number;\n}\n\nexport type FitnessComplete = (args: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<FitnessCompletion>;\n\nexport interface JudgeFitnessPrompt {\n\tprompt: string;\n\t/** True when the prompt is planning-shaped and must never route cheap. */\n\tplanning: boolean;\n}\n\n/** Default judge probe set: three planning-shaped prompts, three trivial lookups. */\nexport const DEFAULT_JUDGE_FITNESS_PROMPTS: readonly JudgeFitnessPrompt[] = [\n\t{ prompt: \"how should we plan the migration of the session storage layer?\", planning: true },\n\t{ prompt: \"design an approach for splitting the settings manager\", planning: true },\n\t{ prompt: \"draft a roadmap for the autonomy rework\", planning: true },\n\t{ prompt: \"what does the resolvePath function return?\", planning: false },\n\t{ prompt: \"list the files in the delegation module\", planning: false },\n\t{ prompt: \"why is this test flaky?\", planning: false },\n];\n\nexport interface CapacityProbeOptions {\n\tregisteredContextWindow: number;\n\t/** Smallest candidate window to try before declaring the capacity unknown. Default 1024. */\n\tminContextWindow?: number;\n}\n\nexport interface ModelFitnessOptions {\n\tcomplete: FitnessComplete;\n\t/** Trials per lane surface. Default 3. */\n\ttrials?: number;\n\t/** Wall-clock budget per call in ms. Default 120000. */\n\tmaxWallClockMs?: number;\n\tjudgePrompts?: readonly JudgeFitnessPrompt[];\n\t/** Optional local-model capacity lane: measures the actually served context window. */\n\tcapacityProbe?: CapacityProbeOptions;\n\tsignal?: AbortSignal;\n\t/** Injected clock for latency measurement (test seam). Defaults to Date.now. */\n\tnow?: () => number;\n}\n\nexport interface LaneFitnessScore {\n\tsucceeded: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the surface's calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface JudgeFitnessScore {\n\tparsed: number;\n\tplanningElevated: number;\n\tplanningTotal: number;\n\ttrivialCheap: number;\n\ttrivialTotal: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the judge calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface CapacityFitnessScore {\n\tregisteredContextWindow: number;\n\tservedContextWindow: number;\n\toutcomes: string[];\n\tmeanMs: number;\n}\n\nexport interface ModelFitnessReport {\n\ttrials: number;\n\t/** Aggregate output tokens/second across ALL probe calls (the headline speed number). */\n\ttokensPerSecond?: number;\n\tresearch: LaneFitnessScore;\n\tworker: LaneFitnessScore;\n\tjudge: JudgeFitnessScore;\n\t/** Heavy-lifter surface: can the model formulate a structured search plan? */\n\tsearch: LaneFitnessScore;\n\t/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */\n\ttoolCall: LaneFitnessScore;\n\t/** Curator surface: can the model digest a context chunk to strict JSON WITHOUT losing key facts? */\n\tdigest: LaneFitnessScore;\n\t/** Local-model capacity lane: measured context window the server actually serves. */\n\tcapacity?: CapacityFitnessScore;\n\ttotalCostUsd: number;\n}\n\n/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */\nexport const SEARCH_PROBE_SYSTEM_PROMPT = [\n\t\"You plan code searches for a coding agent. You never answer the question yourself.\",\n\t\"Given a question about a codebase, respond with STRICT JSON only - no prose:\",\n\t'{\"queries\":[{\"pattern\":\"<regex or literal to grep>\",\"glob\":\"<file glob like **/*.ts>\"}]}',\n\t\"Return 1 to 4 queries, most specific first.\",\n].join(\"\\n\");\n\nexport const TOOL_CALL_PROBE_SYSTEM_PROMPT = [\n\t\"You operate tools for a coding agent. You have exactly one tool:\",\n\t\"grep(pattern: string, path: string) - search files under a path for a pattern.\",\n\t\"Respond to every task with STRICT JSON only - no prose:\",\n\t'{\"tool\":\"grep\",\"arguments\":{\"pattern\":\"<pattern>\",\"path\":\"<path>\"}}',\n].join(\"\\n\");\n\nexport const CAPACITY_PROBE_SYSTEM_PROMPT = [\n\t\"You are a context-window capacity probe for a local model server.\",\n\t\"Find the unique NEEDLE token in the user's text and echo that token only.\",\n\t\"Do not summarize, explain, or add punctuation.\",\n].join(\"\\n\");\n\nconst SEARCH_PROBE_TASKS: readonly string[] = [\n\t\"Where is the retry/backoff logic for HTTP requests implemented?\",\n\t\"Which files define the settings for background research?\",\n\t\"Find where session entries of type custom are appended.\",\n];\n\n// The probe measures the REAL curation contract — same prompt the BrainCurator ships.\nexport { CURATION_DIGEST_SYSTEM_PROMPT as DIGEST_PROBE_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\n\n/**\n * Digest probe chunks each carry a NONCE identifier that cannot be guessed from the\n * instructions: acceptance requires the digest to RETAIN the nonce verbatim, so the score\n * measures extraction fidelity, not narration (a model cannot pass by paraphrasing).\n */\nconst DIGEST_PROBE_TASKS: readonly { chunk: string; nonce: string }[] = [\n\t{\n\t\tnonce: \"retryWithJitter_zx41\",\n\t\tchunk: [\n\t\t\t\"grep results for 'retry' under src/http:\",\n\t\t\t\"src/http/client.ts:88: export function retryWithJitter_zx41(fn, attempts = 3) {\",\n\t\t\t\"src/http/client.ts:112: // exponential backoff capped at 30s\",\n\t\t\t\"src/http/pool.ts:41: client.retry = false\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"ERR_QM_7734\",\n\t\tchunk: [\n\t\t\t\"$ npm run migrate\",\n\t\t\t\"migrating 14 files...\",\n\t\t\t\"error ERR_QM_7734: column 'owner_id' missing on table sessions (migration 0009)\",\n\t\t\t\"exit code 1\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"v3.9.2-hotfix.1\",\n\t\tchunk: [\n\t\t\t\"read package.json (34 lines):\",\n\t\t\t' \"name\": \"acme-billing\",',\n\t\t\t' \"version\": \"v3.9.2-hotfix.1\",',\n\t\t\t' \"engines\": { \"node\": \">=22\" },',\n\t\t].join(\"\\n\"),\n\t},\n];\n\nfunction parseDigest(text: string, nonce: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst digest = (parsed as { digest?: unknown }).digest;\n\tif (typeof digest !== \"string\") return false;\n\tconst trimmed = digest.trim();\n\t// Bounded and faithful: short enough to be a stub annotation, still carrying the nonce fact.\n\treturn trimmed.length > 0 && trimmed.length <= 240 && trimmed.includes(nonce);\n}\n\nconst TOOL_CALL_PROBE_TASKS: readonly string[] = [\n\t\"Find usages of the function resolveCliModel under src/.\",\n\t\"Search for the string 'budget_exhausted' in the core directory.\",\n\t\"Locate where LaneTracker is instantiated under src/core.\",\n];\n\nfunction parseSearchPlan(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst queries = (parsed as { queries?: unknown }).queries;\n\tif (!Array.isArray(queries) || queries.length === 0 || queries.length > 8) return false;\n\treturn queries.every(\n\t\t(query) =>\n\t\t\tquery &&\n\t\t\ttypeof query === \"object\" &&\n\t\t\ttypeof (query as { pattern?: unknown }).pattern === \"string\" &&\n\t\t\t(query as { pattern: string }).pattern.trim().length > 0,\n\t);\n}\n\nfunction parseToolCall(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst record = parsed as { tool?: unknown; arguments?: unknown };\n\tif (record.tool !== \"grep\") return false;\n\tconst args = record.arguments;\n\tif (!args || typeof args !== \"object\" || Array.isArray(args)) return false;\n\tconst pattern = (args as { pattern?: unknown }).pattern;\n\tconst path = (args as { path?: unknown }).path;\n\treturn (\n\t\ttypeof pattern === \"string\" && pattern.trim().length > 0 && typeof path === \"string\" && path.trim().length > 0\n\t);\n}\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction fitnessEnvelope(): CapabilityEnvelope {\n\treturn {\n\t\tid: \"model-fitness-probe\",\n\t\tcapabilities: [\"research\", \"read_files\", \"memory_read\"],\n\t\tmaxEstimatedUsd: 1,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\nfunction buildCapacityProbePrompt(targetTokens: number, startNeedle: string, endNeedle: string): string {\n\tconst targetChars = Math.max(\n\t\tstartNeedle.length + endNeedle.length + 64,\n\t\ttargetTokens * 4 - CAPACITY_PROBE_SYSTEM_PROMPT.length,\n\t);\n\tconst prefix = `CAPACITY PROBE START\\n${startNeedle}\\n`;\n\tconst suffix = `\\n${endNeedle}\\nCAPACITY PROBE END`;\n\tconst fillerLength = Math.max(0, targetChars - prefix.length - suffix.length);\n\treturn `${prefix}${\"x \".repeat(Math.ceil(fillerLength / 2)).slice(0, fillerLength)}${suffix}`;\n}\n\nasync function measureServedContextWindow(args: {\n\tprobe: CapacityProbeOptions;\n\tcomplete: FitnessComplete;\n\tmaxWallClockMs: number;\n\tsignal?: AbortSignal;\n\tnow: () => number;\n}): Promise<{ score: CapacityFitnessScore; costUsd: number }> {\n\tconst registered = Math.max(1, Math.floor(args.probe.registeredContextWindow));\n\tconst minWindow = Math.max(1, Math.floor(args.probe.minContextWindow ?? 1024));\n\tconst nonce = `${registered.toString(16).toUpperCase()}_${minWindow.toString(16).toUpperCase()}`;\n\tconst startNeedle = `NEEDLE_START_${nonce}`;\n\tconst endNeedle = `NEEDLE_END_${nonce}`;\n\tconst score: CapacityFitnessScore = {\n\t\tregisteredContextWindow: registered,\n\t\tservedContextWindow: 0,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tlet candidate = registered;\n\tlet costUsd = 0;\n\tlet calls = 0;\n\twhile (candidate >= minWindow) {\n\t\tconst started = args.now();\n\t\tcalls++;\n\t\tconst bounded = await runBoundedCompletion({\n\t\t\tmaxWallClockMs: args.maxWallClockMs,\n\t\t\tsignal: args.signal,\n\t\t\texecute: (signal) =>\n\t\t\t\targs.complete({\n\t\t\t\t\tsystemPrompt: CAPACITY_PROBE_SYSTEM_PROMPT,\n\t\t\t\t\tuserPrompt: buildCapacityProbePrompt(candidate, startNeedle, endNeedle),\n\t\t\t\t\tsignal,\n\t\t\t\t}),\n\t\t});\n\t\tscore.meanMs += args.now() - started;\n\t\tif (bounded.completion) costUsd += bounded.completion.costUsd;\n\t\tconst output = bounded.completion?.text.trim() ?? \"\";\n\t\tconst recalled = !bounded.failure && output.includes(startNeedle) && output.includes(endNeedle);\n\t\tscore.outcomes.push(`${candidate}:${recalled ? \"ok\" : (bounded.failure?.status ?? \"miss\")}`);\n\t\tif (recalled) {\n\t\t\tscore.servedContextWindow = candidate;\n\t\t\tbreak;\n\t\t}\n\t\tcandidate = Math.floor(candidate / 2);\n\t}\n\tif (score.servedContextWindow === 0) score.servedContextWindow = minWindow;\n\tscore.meanMs = calls > 0 ? Math.round(score.meanMs / calls) : 0;\n\treturn { score, costUsd };\n}\n\nexport async function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport> {\n\tconst trials = Math.max(1, Math.min(options.trials ?? 3, 20));\n\tconst maxWallClockMs = options.maxWallClockMs ?? 120_000;\n\tconst judgePrompts = options.judgePrompts ?? DEFAULT_JUDGE_FITNESS_PROMPTS;\n\tconst now = options.now ?? Date.now;\n\tlet totalCostUsd = 0;\n\n\t// Token-speed instrumentation: the lane runners' own contracts carry text/cost only, so the\n\t// completer is wrapped once here and generation stats are accumulated per surface.\n\tconst overallSpeed = { tokens: 0, evalMs: 0 };\n\tlet surfaceSpeed = { tokens: 0, evalMs: 0 };\n\tconst complete: FitnessComplete = async (args) => {\n\t\tconst completion = await options.complete(args);\n\t\tconst tokens = completion.outputTokens ?? 0;\n\t\tconst evalMs = completion.evalMs ?? 0;\n\t\tif (tokens > 0 && evalMs > 0) {\n\t\t\tsurfaceSpeed.tokens += tokens;\n\t\t\tsurfaceSpeed.evalMs += evalMs;\n\t\t\toverallSpeed.tokens += tokens;\n\t\t\toverallSpeed.evalMs += evalMs;\n\t\t}\n\t\treturn completion;\n\t};\n\tconst takeSurfaceSpeed = (): number | undefined => {\n\t\tconst speed =\n\t\t\tsurfaceSpeed.evalMs > 0 ? Math.round((surfaceSpeed.tokens / surfaceSpeed.evalMs) * 1000) : undefined;\n\t\tsurfaceSpeed = { tokens: 0, evalMs: 0 };\n\t\treturn speed;\n\t};\n\n\tconst research: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst result = await runResearch({\n\t\t\tquery: `fitness:probe requirements:req-${i}`,\n\t\t\tcontext: [\n\t\t\t\t\"Goal: add a retry helper to the HTTP client module\",\n\t\t\t\t\"Open requirements:\",\n\t\t\t\t\"- Find what retry/backoff conventions the codebase already uses\",\n\t\t\t\t\"- Identify which call sites would adopt the helper\",\n\t\t\t].join(\"\\n\"),\n\t\t\tenvelope: fitnessEnvelope(),\n\t\t\tmaxUsd: 1,\n\t\t\tmaxSources: 8,\n\t\t\tmaxFindings: 5,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tresearch.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tif (result.status === \"succeeded\") research.succeeded++;\n\t\tresearch.outcomes.push(`${result.status}/${result.reasonCode}`);\n\t}\n\tresearch.meanMs = Math.round(research.meanMs / trials);\n\tresearch.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst worker: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst outcome = await runWorker({\n\t\t\trequest: {\n\t\t\t\tid: `fitness-worker-${i}`,\n\t\t\t\tinstructions:\n\t\t\t\t\t\"Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.\",\n\t\t\t\troute: { tier: \"cheap\", risk: \"read-only\", confidence: 1, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\t\tenvelope: { id: `fitness-env-${i}`, capabilities: [\"read_files\"], maxEstimatedUsd: 1 },\n\t\t\t\tmaxEstimatedUsd: 1,\n\t\t\t},\n\t\t\tmaxUsd: 1,\n\t\t\tmaxWallClockMs,\n\t\t\tusageReportId: `fitness:${i}`,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tworker.meanMs += now() - started;\n\t\ttotalCostUsd += outcome.costUsd;\n\t\tif (outcome.result.status === \"completed\" && outcome.accepted) worker.succeeded++;\n\t\tworker.outcomes.push(`${outcome.result.status}/${outcome.reasonCode}`);\n\t}\n\tworker.meanMs = Math.round(worker.meanMs / trials);\n\tworker.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst judge: JudgeFitnessScore = {\n\t\tparsed: 0,\n\t\tplanningElevated: 0,\n\t\tplanningTotal: judgePrompts.filter((entry) => entry.planning).length,\n\t\ttrivialCheap: 0,\n\t\ttrivialTotal: judgePrompts.filter((entry) => !entry.planning).length,\n\t\ttotal: judgePrompts.length,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tfor (const entry of judgePrompts) {\n\t\tconst started = now();\n\t\tconst result = await runRouteJudge({\n\t\t\tprompt: entry.prompt,\n\t\t\tbaseline: { tier: \"cheap\", risk: \"read-only\", confidence: 0.5, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tjudge.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tconst tier = result.decision.tier;\n\t\tif (result.verdict) {\n\t\t\tjudge.parsed++;\n\t\t\t// A useful judge must both keep planning off the cheap tier AND actually send trivial\n\t\t\t// prompts there — all-medium verdicts are safe but save nothing.\n\t\t\tif (entry.planning && tier !== \"cheap\") judge.planningElevated++;\n\t\t\tif (!entry.planning && tier === \"cheap\") judge.trivialCheap++;\n\t\t}\n\t\tjudge.outcomes.push(\n\t\t\t`\"${entry.prompt.slice(0, 40)}\" -> ${tier}${result.fallbackReason ? ` (${result.fallbackReason})` : \"\"}`,\n\t\t);\n\t}\n\tjudge.meanMs = judgePrompts.length > 0 ? Math.round(judge.meanMs / judgePrompts.length) : 0;\n\tjudge.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst probeSurface = async (\n\t\tsystemPrompt: string,\n\t\ttasks: readonly string[],\n\t\taccepts: (text: string, taskIndex: number) => boolean,\n\t): Promise<LaneFitnessScore> => {\n\t\tconst score: LaneFitnessScore = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };\n\t\tfor (const [taskIndex, task] of tasks.entries()) {\n\t\t\tconst started = now();\n\t\t\t// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.\n\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\tmaxWallClockMs,\n\t\t\t\tsignal: options.signal,\n\t\t\t\texecute: (signal) => complete({ systemPrompt, userPrompt: task, signal }),\n\t\t\t});\n\t\t\tif (bounded.completion) totalCostUsd += bounded.completion.costUsd;\n\t\t\tif (bounded.failure || !bounded.completion) {\n\t\t\t\tscore.outcomes.push(bounded.failure ? bounded.failure.status : \"completion_error\");\n\t\t\t} else {\n\t\t\t\tconst ok = accepts(bounded.completion.text, taskIndex);\n\t\t\t\tif (ok) score.succeeded++;\n\t\t\t\tscore.outcomes.push(ok ? \"ok\" : \"unparseable_output\");\n\t\t\t}\n\t\t\tscore.meanMs += now() - started;\n\t\t}\n\t\tscore.meanMs = tasks.length > 0 ? Math.round(score.meanMs / tasks.length) : 0;\n\t\treturn score;\n\t};\n\n\tconst search = await probeSurface(SEARCH_PROBE_SYSTEM_PROMPT, SEARCH_PROBE_TASKS, parseSearchPlan);\n\tsearch.tokensPerSecond = takeSurfaceSpeed();\n\tconst toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);\n\ttoolCall.tokensPerSecond = takeSurfaceSpeed();\n\tconst digest = await probeSurface(\n\t\tCURATION_DIGEST_SYSTEM_PROMPT,\n\t\tDIGEST_PROBE_TASKS.map((task) => task.chunk),\n\t\t(text, taskIndex) => parseDigest(text, DIGEST_PROBE_TASKS[taskIndex]!.nonce),\n\t);\n\tdigest.tokensPerSecond = takeSurfaceSpeed();\n\n\tlet capacity: CapacityFitnessScore | undefined;\n\tif (options.capacityProbe) {\n\t\tconst result = await measureServedContextWindow({\n\t\t\tprobe: options.capacityProbe,\n\t\t\tcomplete,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tnow,\n\t\t});\n\t\tcapacity = result.score;\n\t\ttotalCostUsd += result.costUsd;\n\t}\n\n\tconst tokensPerSecond =\n\t\toverallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;\n\n\treturn { trials, tokensPerSecond, research, worker, judge, search, toolCall, digest, capacity, totalCostUsd };\n}\n\n/**\n * Pure verdict: true when the probe found ZERO successes on every LANE surface it actually graded\n * AND the judge (if it ran) also failed. A lane/judge with total 0 (i.e. never run) carries no\n * evidence and is excluded from the lane check — but at least one lane must actually have been\n * graded for an all-failed verdict at all: `gradedLanes.every(...)` is vacuously true over an\n * empty array, so a report where only the judge ran (every research/worker/search/toolCall/digest\n * lane is ungraded) is excluded explicitly rather than misread as \"all lanes failed\" on zero lane\n * evidence. An empty/degenerate report (nothing graded at all, lanes AND judge) is likewise never\n * mistaken for a failed one. This is the gate adoption flows must consult before assigning a role —\n * see `isProbeAllFailed` callers in interactive-mode.ts and agent-session.ts.\n */\nexport function isProbeAllFailed(report: ModelFitnessReport): boolean {\n\tconst lanes = [report.research, report.worker, report.search, report.toolCall, report.digest];\n\tconst gradedLanes = lanes.filter((lane) => lane.total > 0);\n\tconst judgeGraded = report.judge.total > 0;\n\tif (gradedLanes.length === 0 && !judgeGraded) return false;\n\tconst lanesAllFailed = gradedLanes.length > 0 && gradedLanes.every((lane) => lane.succeeded === 0);\n\tconst judgeFailed = !judgeGraded || report.judge.parsed === 0;\n\treturn lanesAllFailed && judgeFailed;\n}\n\n/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */\nexport function formatModelFitnessReport(model: string, report: ModelFitnessReport): string {\n\tconst speed = (tokensPerSecond: number | undefined) =>\n\t\ttokensPerSecond !== undefined ? `, ~${tokensPerSecond} tok/s` : \"\";\n\tconst lines = [\n\t\t`Model fitness: ${model} (${report.trials} trials/lane${speed(report.tokensPerSecond)})`,\n\t\t`- research lane: ${report.research.succeeded}/${report.research.total} succeeded, mean ${report.research.meanMs}ms${speed(report.research.tokensPerSecond)} [${report.research.outcomes.join(\", \")}]`,\n\t\t`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(\", \")}]`,\n\t\t`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,\n\t\t`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,\n\t\t`- digests: ${report.digest.succeeded}/${report.digest.total} faithful, mean ${report.digest.meanMs}ms${speed(report.digest.tokensPerSecond)}`,\n\t\t...(report.capacity\n\t\t\t? [\n\t\t\t\t\t`- capacity: served window ${report.capacity.servedContextWindow}/${report.capacity.registeredContextWindow} tokens, mean ${report.capacity.meanMs}ms`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,\n\t\t...report.judge.outcomes.map((outcome) => ` ${outcome}`),\n\t];\n\tif (report.totalCostUsd > 0) {\n\t\tlines.push(`- probe cost: $${report.totalCostUsd.toFixed(4)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"model-fitness.d.ts","sourceRoot":"","sources":["../../../src/core/research/model-fitness.ts"],"names":[],"mappings":"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","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { CapabilityEnvelope } from \"../autonomy/contracts.ts\";\nimport { CURATION_DIGEST_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\nimport { runWorker } from \"../delegation/worker-runner.ts\";\nimport { runRouteJudge } from \"../model-router/route-judge.ts\";\nimport { runResearch } from \"./research-runner.ts\";\n\n/**\n * Model fitness probe: measures whether a candidate model can actually drive the harness's\n * subagent contracts — the research lane, the delegated-worker lane, and the routing judge — by\n * running each real runner against the model and scoring parse/success rates plus judge\n * discrimination. Provider-free: the completion executor is injected, so this works against any\n * registered model (local Ollama models included) and against faux providers in tests.\n */\n\nexport interface FitnessCompletion {\n\ttext: string;\n\tcostUsd: number;\n\tstopReason: string;\n\t/** Output tokens generated (for tok/s). Optional: providers that don't report it are skipped. */\n\toutputTokens?: number;\n\t/** Pure generation time in ms (e.g. Ollama eval_duration). Falls back to wall-clock if absent. */\n\tevalMs?: number;\n}\n\nexport type FitnessComplete = (args: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<FitnessCompletion>;\n\nexport interface JudgeFitnessPrompt {\n\tprompt: string;\n\t/** True when the prompt is planning-shaped and must never route cheap. */\n\tplanning: boolean;\n}\n\n/** Default judge probe set: three planning-shaped prompts, three trivial lookups. */\nexport const DEFAULT_JUDGE_FITNESS_PROMPTS: readonly JudgeFitnessPrompt[] = [\n\t{ prompt: \"how should we plan the migration of the session storage layer?\", planning: true },\n\t{ prompt: \"design an approach for splitting the settings manager\", planning: true },\n\t{ prompt: \"draft a roadmap for the autonomy rework\", planning: true },\n\t{ prompt: \"what does the resolvePath function return?\", planning: false },\n\t{ prompt: \"list the files in the delegation module\", planning: false },\n\t{ prompt: \"why is this test flaky?\", planning: false },\n];\n\nexport interface CapacityProbeOptions {\n\tregisteredContextWindow: number;\n\t/** Smallest candidate window to try before declaring the capacity unknown. Default 1024. */\n\tminContextWindow?: number;\n}\n\nexport interface ModelFitnessOptions {\n\tcomplete: FitnessComplete;\n\t/** Trials per lane surface. Default 3. */\n\ttrials?: number;\n\t/** Wall-clock budget per call in ms. Default 120000. */\n\tmaxWallClockMs?: number;\n\tjudgePrompts?: readonly JudgeFitnessPrompt[];\n\t/** Optional local-model capacity lane: measures the actually served context window. */\n\tcapacityProbe?: CapacityProbeOptions;\n\tsignal?: AbortSignal;\n\t/** Injected clock for latency measurement (test seam). Defaults to Date.now. */\n\tnow?: () => number;\n}\n\nexport interface LaneFitnessScore {\n\tsucceeded: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the surface's calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface JudgeFitnessScore {\n\tparsed: number;\n\tplanningElevated: number;\n\tplanningTotal: number;\n\ttrivialCheap: number;\n\ttrivialTotal: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the judge calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface CapacityFitnessScore {\n\tregisteredContextWindow: number;\n\tservedContextWindow: number;\n\toutcomes: string[];\n\tmeanMs: number;\n}\n\nexport interface ModelFitnessReport {\n\ttrials: number;\n\t/** Aggregate output tokens/second across ALL probe calls (the headline speed number). */\n\ttokensPerSecond?: number;\n\tresearch: LaneFitnessScore;\n\tworker: LaneFitnessScore;\n\tjudge: JudgeFitnessScore;\n\t/** Heavy-lifter surface: can the model formulate a structured search plan? */\n\tsearch: LaneFitnessScore;\n\t/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */\n\ttoolCall: LaneFitnessScore;\n\t/** Curator surface: can the model digest a context chunk to strict JSON WITHOUT losing key facts? */\n\tdigest: LaneFitnessScore;\n\t/** Local-model capacity lane: measured context window the server actually serves. */\n\tcapacity?: CapacityFitnessScore;\n\ttotalCostUsd: number;\n}\n\n/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */\nexport const SEARCH_PROBE_SYSTEM_PROMPT = [\n\t\"You plan code searches for a coding agent. You never answer the question yourself.\",\n\t\"Given a question about a codebase, respond with STRICT JSON only - no prose:\",\n\t'{\"queries\":[{\"pattern\":\"<regex or literal to grep>\",\"glob\":\"<file glob like **/*.ts>\"}]}',\n\t\"Return 1 to 4 queries, most specific first.\",\n].join(\"\\n\");\n\nexport const TOOL_CALL_PROBE_SYSTEM_PROMPT = [\n\t\"You operate tools for a coding agent. You have exactly one tool:\",\n\t\"grep(pattern: string, path: string) - search files under a path for a pattern.\",\n\t\"Respond to every task with STRICT JSON only - no prose:\",\n\t'{\"tool\":\"grep\",\"arguments\":{\"pattern\":\"<pattern>\",\"path\":\"<path>\"}}',\n].join(\"\\n\");\n\nexport const CAPACITY_PROBE_SYSTEM_PROMPT = [\n\t\"You are a context-window capacity probe for a local model server.\",\n\t\"Find the unique NEEDLE token in the user's text and echo that token only.\",\n\t\"Do not summarize, explain, or add punctuation.\",\n].join(\"\\n\");\n\nconst SEARCH_PROBE_TASKS: readonly string[] = [\n\t\"Where is the retry/backoff logic for HTTP requests implemented?\",\n\t\"Which files define the settings for background research?\",\n\t\"Find where session entries of type custom are appended.\",\n];\n\n// The probe measures the REAL curation contract — same prompt the BrainCurator ships.\nexport { CURATION_DIGEST_SYSTEM_PROMPT as DIGEST_PROBE_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\n\n/**\n * Digest probe chunks each carry a NONCE identifier that cannot be guessed from the\n * instructions: acceptance requires the digest to RETAIN the nonce verbatim, so the score\n * measures extraction fidelity, not narration (a model cannot pass by paraphrasing).\n */\nconst DIGEST_PROBE_TASKS: readonly { chunk: string; nonce: string }[] = [\n\t{\n\t\tnonce: \"retryWithJitter_zx41\",\n\t\tchunk: [\n\t\t\t\"grep results for 'retry' under src/http:\",\n\t\t\t\"src/http/client.ts:88: export function retryWithJitter_zx41(fn, attempts = 3) {\",\n\t\t\t\"src/http/client.ts:112: // exponential backoff capped at 30s\",\n\t\t\t\"src/http/pool.ts:41: client.retry = false\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"ERR_QM_7734\",\n\t\tchunk: [\n\t\t\t\"$ npm run migrate\",\n\t\t\t\"migrating 14 files...\",\n\t\t\t\"error ERR_QM_7734: column 'owner_id' missing on table sessions (migration 0009)\",\n\t\t\t\"exit code 1\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"v3.9.2-hotfix.1\",\n\t\tchunk: [\n\t\t\t\"read package.json (34 lines):\",\n\t\t\t' \"name\": \"acme-billing\",',\n\t\t\t' \"version\": \"v3.9.2-hotfix.1\",',\n\t\t\t' \"engines\": { \"node\": \">=22\" },',\n\t\t].join(\"\\n\"),\n\t},\n];\n\nfunction parseDigest(text: string, nonce: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst digest = (parsed as { digest?: unknown }).digest;\n\tif (typeof digest !== \"string\") return false;\n\tconst trimmed = digest.trim();\n\t// Bounded and faithful: short enough to be a stub annotation, still carrying the nonce fact.\n\treturn trimmed.length > 0 && trimmed.length <= 240 && trimmed.includes(nonce);\n}\n\nconst TOOL_CALL_PROBE_TASKS: readonly string[] = [\n\t\"Find usages of the function resolveCliModel under src/.\",\n\t\"Search for the string 'budget_exhausted' in the core directory.\",\n\t\"Locate where LaneTracker is instantiated under src/core.\",\n];\n\nfunction parseSearchPlan(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst queries = (parsed as { queries?: unknown }).queries;\n\tif (!Array.isArray(queries) || queries.length === 0 || queries.length > 8) return false;\n\treturn queries.every(\n\t\t(query) =>\n\t\t\tquery &&\n\t\t\ttypeof query === \"object\" &&\n\t\t\ttypeof (query as { pattern?: unknown }).pattern === \"string\" &&\n\t\t\t(query as { pattern: string }).pattern.trim().length > 0,\n\t);\n}\n\nfunction parseToolCall(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst record = parsed as { tool?: unknown; arguments?: unknown };\n\tif (record.tool !== \"grep\") return false;\n\tconst args = record.arguments;\n\tif (!args || typeof args !== \"object\" || Array.isArray(args)) return false;\n\tconst pattern = (args as { pattern?: unknown }).pattern;\n\tconst path = (args as { path?: unknown }).path;\n\treturn (\n\t\ttypeof pattern === \"string\" && pattern.trim().length > 0 && typeof path === \"string\" && path.trim().length > 0\n\t);\n}\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction fitnessEnvelope(): CapabilityEnvelope {\n\treturn {\n\t\tid: \"model-fitness-probe\",\n\t\tcapabilities: [\"research.execute\", \"filesystem.read\", \"memory.query\"],\n\t\tmaxEstimatedUsd: 1,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\nfunction buildCapacityProbePrompt(targetTokens: number, startNeedle: string, endNeedle: string): string {\n\tconst targetChars = Math.max(\n\t\tstartNeedle.length + endNeedle.length + 64,\n\t\ttargetTokens * 4 - CAPACITY_PROBE_SYSTEM_PROMPT.length,\n\t);\n\tconst prefix = `CAPACITY PROBE START\\n${startNeedle}\\n`;\n\tconst suffix = `\\n${endNeedle}\\nCAPACITY PROBE END`;\n\tconst fillerLength = Math.max(0, targetChars - prefix.length - suffix.length);\n\treturn `${prefix}${\"x \".repeat(Math.ceil(fillerLength / 2)).slice(0, fillerLength)}${suffix}`;\n}\n\nasync function measureServedContextWindow(args: {\n\tprobe: CapacityProbeOptions;\n\tcomplete: FitnessComplete;\n\tmaxWallClockMs: number;\n\tsignal?: AbortSignal;\n\tnow: () => number;\n}): Promise<{ score: CapacityFitnessScore; costUsd: number }> {\n\tconst registered = Math.max(1, Math.floor(args.probe.registeredContextWindow));\n\tconst minWindow = Math.max(1, Math.floor(args.probe.minContextWindow ?? 1024));\n\tconst nonce = `${registered.toString(16).toUpperCase()}_${minWindow.toString(16).toUpperCase()}`;\n\tconst startNeedle = `NEEDLE_START_${nonce}`;\n\tconst endNeedle = `NEEDLE_END_${nonce}`;\n\tconst score: CapacityFitnessScore = {\n\t\tregisteredContextWindow: registered,\n\t\tservedContextWindow: 0,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tlet candidate = registered;\n\tlet costUsd = 0;\n\tlet calls = 0;\n\twhile (candidate >= minWindow) {\n\t\tconst started = args.now();\n\t\tcalls++;\n\t\tconst bounded = await runBoundedCompletion({\n\t\t\tmaxWallClockMs: args.maxWallClockMs,\n\t\t\tsignal: args.signal,\n\t\t\texecute: (signal) =>\n\t\t\t\targs.complete({\n\t\t\t\t\tsystemPrompt: CAPACITY_PROBE_SYSTEM_PROMPT,\n\t\t\t\t\tuserPrompt: buildCapacityProbePrompt(candidate, startNeedle, endNeedle),\n\t\t\t\t\tsignal,\n\t\t\t\t}),\n\t\t});\n\t\tscore.meanMs += args.now() - started;\n\t\tif (bounded.completion) costUsd += bounded.completion.costUsd;\n\t\tconst output = bounded.completion?.text.trim() ?? \"\";\n\t\tconst recalled = !bounded.failure && output.includes(startNeedle) && output.includes(endNeedle);\n\t\tscore.outcomes.push(`${candidate}:${recalled ? \"ok\" : (bounded.failure?.status ?? \"miss\")}`);\n\t\tif (recalled) {\n\t\t\tscore.servedContextWindow = candidate;\n\t\t\tbreak;\n\t\t}\n\t\tcandidate = Math.floor(candidate / 2);\n\t}\n\tif (score.servedContextWindow === 0) score.servedContextWindow = minWindow;\n\tscore.meanMs = calls > 0 ? Math.round(score.meanMs / calls) : 0;\n\treturn { score, costUsd };\n}\n\nexport async function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport> {\n\tconst trials = Math.max(1, Math.min(options.trials ?? 3, 20));\n\tconst maxWallClockMs = options.maxWallClockMs ?? 120_000;\n\tconst judgePrompts = options.judgePrompts ?? DEFAULT_JUDGE_FITNESS_PROMPTS;\n\tconst now = options.now ?? Date.now;\n\tlet totalCostUsd = 0;\n\n\t// Token-speed instrumentation: the lane runners' own contracts carry text/cost only, so the\n\t// completer is wrapped once here and generation stats are accumulated per surface.\n\tconst overallSpeed = { tokens: 0, evalMs: 0 };\n\tlet surfaceSpeed = { tokens: 0, evalMs: 0 };\n\tconst complete: FitnessComplete = async (args) => {\n\t\tconst completion = await options.complete(args);\n\t\tconst tokens = completion.outputTokens ?? 0;\n\t\tconst evalMs = completion.evalMs ?? 0;\n\t\tif (tokens > 0 && evalMs > 0) {\n\t\t\tsurfaceSpeed.tokens += tokens;\n\t\t\tsurfaceSpeed.evalMs += evalMs;\n\t\t\toverallSpeed.tokens += tokens;\n\t\t\toverallSpeed.evalMs += evalMs;\n\t\t}\n\t\treturn completion;\n\t};\n\tconst takeSurfaceSpeed = (): number | undefined => {\n\t\tconst speed =\n\t\t\tsurfaceSpeed.evalMs > 0 ? Math.round((surfaceSpeed.tokens / surfaceSpeed.evalMs) * 1000) : undefined;\n\t\tsurfaceSpeed = { tokens: 0, evalMs: 0 };\n\t\treturn speed;\n\t};\n\n\tconst research: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst result = await runResearch({\n\t\t\tquery: `fitness:probe requirements:req-${i}`,\n\t\t\tcontext: [\n\t\t\t\t\"Goal: add a retry helper to the HTTP client module\",\n\t\t\t\t\"Open requirements:\",\n\t\t\t\t\"- Find what retry/backoff conventions the codebase already uses\",\n\t\t\t\t\"- Identify which call sites would adopt the helper\",\n\t\t\t].join(\"\\n\"),\n\t\t\tenvelope: fitnessEnvelope(),\n\t\t\tmaxUsd: 1,\n\t\t\tmaxSources: 8,\n\t\t\tmaxFindings: 5,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tresearch.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tif (result.status === \"succeeded\") research.succeeded++;\n\t\tresearch.outcomes.push(`${result.status}/${result.reasonCode}`);\n\t}\n\tresearch.meanMs = Math.round(research.meanMs / trials);\n\tresearch.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst worker: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst outcome = await runWorker({\n\t\t\trequest: {\n\t\t\t\tid: `fitness-worker-${i}`,\n\t\t\t\tinstructions:\n\t\t\t\t\t\"Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.\",\n\t\t\t\troute: { tier: \"cheap\", risk: \"read-only\", confidence: 1, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\t\tenvelope: { id: `fitness-env-${i}`, capabilities: [\"filesystem.read\"], maxEstimatedUsd: 1 },\n\t\t\t\tmaxEstimatedUsd: 1,\n\t\t\t},\n\t\t\tmaxUsd: 1,\n\t\t\tmaxWallClockMs,\n\t\t\tusageReportId: `fitness:${i}`,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tworker.meanMs += now() - started;\n\t\ttotalCostUsd += outcome.costUsd;\n\t\tif (outcome.claim.status === \"completed\" && outcome.accepted) worker.succeeded++;\n\t\tworker.outcomes.push(`${outcome.claim.status}/${outcome.reasonCode}`);\n\t}\n\tworker.meanMs = Math.round(worker.meanMs / trials);\n\tworker.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst judge: JudgeFitnessScore = {\n\t\tparsed: 0,\n\t\tplanningElevated: 0,\n\t\tplanningTotal: judgePrompts.filter((entry) => entry.planning).length,\n\t\ttrivialCheap: 0,\n\t\ttrivialTotal: judgePrompts.filter((entry) => !entry.planning).length,\n\t\ttotal: judgePrompts.length,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tfor (const entry of judgePrompts) {\n\t\tconst started = now();\n\t\tconst result = await runRouteJudge({\n\t\t\tprompt: entry.prompt,\n\t\t\tbaseline: { tier: \"cheap\", risk: \"read-only\", confidence: 0.5, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tjudge.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tconst tier = result.decision.tier;\n\t\tif (result.verdict) {\n\t\t\tjudge.parsed++;\n\t\t\t// A useful judge must both keep planning off the cheap tier AND actually send trivial\n\t\t\t// prompts there — all-medium verdicts are safe but save nothing.\n\t\t\tif (entry.planning && tier !== \"cheap\") judge.planningElevated++;\n\t\t\tif (!entry.planning && tier === \"cheap\") judge.trivialCheap++;\n\t\t}\n\t\tjudge.outcomes.push(\n\t\t\t`\"${entry.prompt.slice(0, 40)}\" -> ${tier}${result.fallbackReason ? ` (${result.fallbackReason})` : \"\"}`,\n\t\t);\n\t}\n\tjudge.meanMs = judgePrompts.length > 0 ? Math.round(judge.meanMs / judgePrompts.length) : 0;\n\tjudge.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst probeSurface = async (\n\t\tsystemPrompt: string,\n\t\ttasks: readonly string[],\n\t\taccepts: (text: string, taskIndex: number) => boolean,\n\t): Promise<LaneFitnessScore> => {\n\t\tconst score: LaneFitnessScore = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };\n\t\tfor (const [taskIndex, task] of tasks.entries()) {\n\t\t\tconst started = now();\n\t\t\t// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.\n\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\tmaxWallClockMs,\n\t\t\t\tsignal: options.signal,\n\t\t\t\texecute: (signal) => complete({ systemPrompt, userPrompt: task, signal }),\n\t\t\t});\n\t\t\tif (bounded.completion) totalCostUsd += bounded.completion.costUsd;\n\t\t\tif (bounded.failure || !bounded.completion) {\n\t\t\t\tscore.outcomes.push(bounded.failure ? bounded.failure.status : \"completion_error\");\n\t\t\t} else {\n\t\t\t\tconst ok = accepts(bounded.completion.text, taskIndex);\n\t\t\t\tif (ok) score.succeeded++;\n\t\t\t\tscore.outcomes.push(ok ? \"ok\" : \"unparseable_output\");\n\t\t\t}\n\t\t\tscore.meanMs += now() - started;\n\t\t}\n\t\tscore.meanMs = tasks.length > 0 ? Math.round(score.meanMs / tasks.length) : 0;\n\t\treturn score;\n\t};\n\n\tconst search = await probeSurface(SEARCH_PROBE_SYSTEM_PROMPT, SEARCH_PROBE_TASKS, parseSearchPlan);\n\tsearch.tokensPerSecond = takeSurfaceSpeed();\n\tconst toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);\n\ttoolCall.tokensPerSecond = takeSurfaceSpeed();\n\tconst digest = await probeSurface(\n\t\tCURATION_DIGEST_SYSTEM_PROMPT,\n\t\tDIGEST_PROBE_TASKS.map((task) => task.chunk),\n\t\t(text, taskIndex) => parseDigest(text, DIGEST_PROBE_TASKS[taskIndex]!.nonce),\n\t);\n\tdigest.tokensPerSecond = takeSurfaceSpeed();\n\n\tlet capacity: CapacityFitnessScore | undefined;\n\tif (options.capacityProbe) {\n\t\tconst result = await measureServedContextWindow({\n\t\t\tprobe: options.capacityProbe,\n\t\t\tcomplete,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tnow,\n\t\t});\n\t\tcapacity = result.score;\n\t\ttotalCostUsd += result.costUsd;\n\t}\n\n\tconst tokensPerSecond =\n\t\toverallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;\n\n\treturn { trials, tokensPerSecond, research, worker, judge, search, toolCall, digest, capacity, totalCostUsd };\n}\n\n/**\n * Pure verdict: true when the probe found ZERO successes on every LANE surface it actually graded\n * AND the judge (if it ran) also failed. A lane/judge with total 0 (i.e. never run) carries no\n * evidence and is excluded from the lane check — but at least one lane must actually have been\n * graded for an all-failed verdict at all: `gradedLanes.every(...)` is vacuously true over an\n * empty array, so a report where only the judge ran (every research/worker/search/toolCall/digest\n * lane is ungraded) is excluded explicitly rather than misread as \"all lanes failed\" on zero lane\n * evidence. An empty/degenerate report (nothing graded at all, lanes AND judge) is likewise never\n * mistaken for a failed one. This is the gate adoption flows must consult before assigning a role —\n * see `isProbeAllFailed` callers in interactive-mode.ts and agent-session.ts.\n */\nexport function isProbeAllFailed(report: ModelFitnessReport): boolean {\n\tconst lanes = [report.research, report.worker, report.search, report.toolCall, report.digest];\n\tconst gradedLanes = lanes.filter((lane) => lane.total > 0);\n\tconst judgeGraded = report.judge.total > 0;\n\tif (gradedLanes.length === 0 && !judgeGraded) return false;\n\tconst lanesAllFailed = gradedLanes.length > 0 && gradedLanes.every((lane) => lane.succeeded === 0);\n\tconst judgeFailed = !judgeGraded || report.judge.parsed === 0;\n\treturn lanesAllFailed && judgeFailed;\n}\n\n/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */\nexport function formatModelFitnessReport(model: string, report: ModelFitnessReport): string {\n\tconst speed = (tokensPerSecond: number | undefined) =>\n\t\ttokensPerSecond !== undefined ? `, ~${tokensPerSecond} tok/s` : \"\";\n\tconst lines = [\n\t\t`Model fitness: ${model} (${report.trials} trials/lane${speed(report.tokensPerSecond)})`,\n\t\t`- research lane: ${report.research.succeeded}/${report.research.total} succeeded, mean ${report.research.meanMs}ms${speed(report.research.tokensPerSecond)} [${report.research.outcomes.join(\", \")}]`,\n\t\t`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(\", \")}]`,\n\t\t`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,\n\t\t`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,\n\t\t`- digests: ${report.digest.succeeded}/${report.digest.total} faithful, mean ${report.digest.meanMs}ms${speed(report.digest.tokensPerSecond)}`,\n\t\t...(report.capacity\n\t\t\t? [\n\t\t\t\t\t`- capacity: served window ${report.capacity.servedContextWindow}/${report.capacity.registeredContextWindow} tokens, mean ${report.capacity.meanMs}ms`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,\n\t\t...report.judge.outcomes.map((outcome) => ` ${outcome}`),\n\t];\n\tif (report.totalCostUsd > 0) {\n\t\tlines.push(`- probe cost: $${report.totalCostUsd.toFixed(4)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
@@ -138,7 +138,7 @@ function extractJsonObject(text) {
138
138
  function fitnessEnvelope() {
139
139
  return {
140
140
  id: "model-fitness-probe",
141
- capabilities: ["research", "read_files", "memory_read"],
141
+ capabilities: ["research.execute", "filesystem.read", "memory.query"],
142
142
  maxEstimatedUsd: 1,
143
143
  createdAt: new Date().toISOString(),
144
144
  };
@@ -256,7 +256,7 @@ export async function runModelFitnessProbe(options) {
256
256
  id: `fitness-worker-${i}`,
257
257
  instructions: "Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.",
258
258
  route: { tier: "cheap", risk: "read-only", confidence: 1, reasonCode: "fitness_probe", reasons: [] },
259
- envelope: { id: `fitness-env-${i}`, capabilities: ["read_files"], maxEstimatedUsd: 1 },
259
+ envelope: { id: `fitness-env-${i}`, capabilities: ["filesystem.read"], maxEstimatedUsd: 1 },
260
260
  maxEstimatedUsd: 1,
261
261
  },
262
262
  maxUsd: 1,
@@ -267,9 +267,9 @@ export async function runModelFitnessProbe(options) {
267
267
  });
268
268
  worker.meanMs += now() - started;
269
269
  totalCostUsd += outcome.costUsd;
270
- if (outcome.result.status === "completed" && outcome.accepted)
270
+ if (outcome.claim.status === "completed" && outcome.accepted)
271
271
  worker.succeeded++;
272
- worker.outcomes.push(`${outcome.result.status}/${outcome.reasonCode}`);
272
+ worker.outcomes.push(`${outcome.claim.status}/${outcome.reasonCode}`);
273
273
  }
274
274
  worker.meanMs = Math.round(worker.meanMs / trials);
275
275
  worker.tokensPerSecond = takeSurfaceSpeed();