@bastani/atomic 0.9.21-alpha.1 → 0.9.21-alpha.2

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 (514) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/package.json +1 -1
  4. package/dist/builtin/subagents/CHANGELOG.md +11 -0
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/subagents/src/extension/index.bundle.mjs +292 -60
  7. package/dist/builtin/web-access/package.json +1 -1
  8. package/dist/builtin/workflows/CHANGELOG.md +11 -0
  9. package/dist/builtin/workflows/builtin/adversarial-verification.js +3 -3
  10. package/dist/builtin/workflows/builtin/{chunk-cw86srkf.js → chunk-632fxeb8.js} +1 -1
  11. package/dist/builtin/workflows/builtin/{chunk-w18kbz63.js → chunk-94f8zfz1.js} +1 -1
  12. package/dist/builtin/workflows/builtin/{chunk-kspvwc24.js → chunk-9cm2ckq2.js} +1 -1
  13. package/dist/builtin/workflows/builtin/{chunk-jaj27rqc.js → chunk-a1ar035d.js} +1 -1
  14. package/dist/builtin/workflows/builtin/{chunk-wh19f5ee.js → chunk-d3xhj946.js} +5 -4
  15. package/dist/builtin/workflows/builtin/{chunk-crw7q5g1.js → chunk-gyjck9z8.js} +1 -1
  16. package/dist/builtin/workflows/builtin/{chunk-maqv731g.js → chunk-hj8mh07f.js} +10 -6
  17. package/dist/builtin/workflows/builtin/{chunk-0nrgfbag.js → chunk-kb7s3gx2.js} +1 -1
  18. package/dist/builtin/workflows/builtin/{chunk-73c5tayt.js → chunk-kgn5wz1c.js} +19 -1
  19. package/dist/builtin/workflows/builtin/{chunk-2hak3b7g.js → chunk-nkj4qhj6.js} +1 -1
  20. package/dist/builtin/workflows/builtin/{chunk-bzdvx2xr.js → chunk-r97ndfvt.js} +1 -1
  21. package/dist/builtin/workflows/builtin/{chunk-vkmpdat4.js → chunk-wf876n16.js} +1 -1
  22. package/dist/builtin/workflows/builtin/classify-and-act.js +3 -3
  23. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -3
  24. package/dist/builtin/workflows/builtin/generate-and-filter.js +3 -3
  25. package/dist/builtin/workflows/builtin/goal.js +4 -4
  26. package/dist/builtin/workflows/builtin/index.js +12 -12
  27. package/dist/builtin/workflows/builtin/loop-until-done.js +3 -3
  28. package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
  29. package/dist/builtin/workflows/builtin/ralph.js +4 -4
  30. package/dist/builtin/workflows/builtin/steering-context.js +1 -1
  31. package/dist/builtin/workflows/builtin/tournament.js +3 -3
  32. package/dist/builtin/workflows/package.json +1 -1
  33. package/dist/builtin/workflows/src/extension/index.bundle.mjs +40 -11
  34. package/dist/builtin/workflows/src/index.js +9 -3
  35. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +6 -1
  36. package/dist/cli/auth-command.js +5 -0
  37. package/dist/cli/auth-command.js.map +1 -1
  38. package/dist/cli/credential-print.js +2 -0
  39. package/dist/cli/credential-print.js.map +1 -1
  40. package/dist/cli/experimental/command.js +5 -2
  41. package/dist/cli/experimental/command.js.map +1 -1
  42. package/dist/cli.js +1 -1
  43. package/dist/cli.js.map +1 -1
  44. package/dist/config.d.ts +4 -4
  45. package/dist/config.js +4 -4
  46. package/dist/config.js.map +1 -1
  47. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  48. package/dist/core/agent-session-extension-bindings.js +9 -4
  49. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  50. package/dist/core/agent-session-methods.d.ts +4 -4
  51. package/dist/core/agent-session-methods.d.ts.map +1 -1
  52. package/dist/core/agent-session-methods.js.map +1 -1
  53. package/dist/core/agent-session-prompt.d.ts +4 -4
  54. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  55. package/dist/core/agent-session-prompt.js +38 -15
  56. package/dist/core/agent-session-prompt.js.map +1 -1
  57. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  58. package/dist/core/agent-session-runtime.js +14 -9
  59. package/dist/core/agent-session-runtime.js.map +1 -1
  60. package/dist/core/agent-session-types.d.ts +4 -1
  61. package/dist/core/agent-session-types.d.ts.map +1 -1
  62. package/dist/core/agent-session-types.js.map +1 -1
  63. package/dist/core/agent-session.d.ts +1 -1
  64. package/dist/core/agent-session.d.ts.map +1 -1
  65. package/dist/core/agent-session.js +140 -95
  66. package/dist/core/agent-session.js.map +1 -1
  67. package/dist/core/auth-storage-backends.js +2 -3
  68. package/dist/core/auth-storage-backends.js.map +1 -1
  69. package/dist/core/auth-storage.js +4 -1
  70. package/dist/core/auth-storage.js.map +1 -1
  71. package/dist/core/builtin-resource-loader.js +9 -0
  72. package/dist/core/builtin-resource-loader.js.map +1 -1
  73. package/dist/core/cache-warmer.js +8 -1
  74. package/dist/core/cache-warmer.js.map +1 -1
  75. package/dist/core/compaction/range-planner.js +6 -0
  76. package/dist/core/compaction/range-planner.js.map +1 -1
  77. package/dist/core/execution-model-router.d.ts +13 -3
  78. package/dist/core/execution-model-router.d.ts.map +1 -1
  79. package/dist/core/execution-model-router.js +227 -131
  80. package/dist/core/execution-model-router.js.map +1 -1
  81. package/dist/core/export-html/template-js/entries-navigation.js +16 -6
  82. package/dist/core/export-html/template-js/initialization.js +34 -11
  83. package/dist/core/export-html/template.css +10 -0
  84. package/dist/core/export-html/template.js +50 -17
  85. package/dist/core/extensions/context-types.d.ts +2 -0
  86. package/dist/core/extensions/context-types.d.ts.map +1 -1
  87. package/dist/core/extensions/context-types.js.map +1 -1
  88. package/dist/core/extensions/host-input.js +8 -4
  89. package/dist/core/extensions/host-input.js.map +1 -1
  90. package/dist/core/extensions/reactive-widget.js +1 -0
  91. package/dist/core/extensions/reactive-widget.js.map +1 -1
  92. package/dist/core/extensions/runner-context.d.ts +1 -0
  93. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  94. package/dist/core/extensions/runner-context.js +4 -0
  95. package/dist/core/extensions/runner-context.js.map +1 -1
  96. package/dist/core/extensions/runner.d.ts +1 -0
  97. package/dist/core/extensions/runner.d.ts.map +1 -1
  98. package/dist/core/extensions/runner.js +48 -30
  99. package/dist/core/extensions/runner.js.map +1 -1
  100. package/dist/core/extensions/runtime-types.d.ts +1 -0
  101. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  102. package/dist/core/extensions/runtime-types.js.map +1 -1
  103. package/dist/core/extensions/workflow-activity-hub.js +9 -7
  104. package/dist/core/extensions/workflow-activity-hub.js.map +1 -1
  105. package/dist/core/footer-data-provider.js +24 -23
  106. package/dist/core/footer-data-provider.js.map +1 -1
  107. package/dist/core/keybindings.js +1 -0
  108. package/dist/core/keybindings.js.map +1 -1
  109. package/dist/core/mandatory-resource-loader.js +4 -1
  110. package/dist/core/mandatory-resource-loader.js.map +1 -1
  111. package/dist/core/model-config.js +2 -0
  112. package/dist/core/model-config.js.map +1 -1
  113. package/dist/core/model-registry.js +1 -0
  114. package/dist/core/model-registry.js.map +1 -1
  115. package/dist/core/{model-routing-task.d.ts → model-routing-bytes.d.ts} +1 -4
  116. package/dist/core/model-routing-bytes.d.ts.map +1 -0
  117. package/dist/core/model-routing-bytes.js +33 -0
  118. package/dist/core/model-routing-bytes.js.map +1 -0
  119. package/dist/core/model-routing-candidates.d.ts +42 -0
  120. package/dist/core/model-routing-candidates.d.ts.map +1 -0
  121. package/dist/core/model-routing-candidates.js +309 -0
  122. package/dist/core/model-routing-candidates.js.map +1 -0
  123. package/dist/core/model-routing-constraints.d.ts +4 -0
  124. package/dist/core/model-routing-constraints.d.ts.map +1 -1
  125. package/dist/core/model-routing-constraints.js +13 -1
  126. package/dist/core/model-routing-constraints.js.map +1 -1
  127. package/dist/core/model-routing-debug.d.ts +9 -0
  128. package/dist/core/model-routing-debug.d.ts.map +1 -0
  129. package/dist/core/model-routing-debug.js +14 -0
  130. package/dist/core/model-routing-debug.js.map +1 -0
  131. package/dist/core/model-routing-evals.d.ts +50 -0
  132. package/dist/core/model-routing-evals.d.ts.map +1 -0
  133. package/dist/core/model-routing-evals.js +190 -0
  134. package/dist/core/model-routing-evals.js.map +1 -0
  135. package/dist/core/model-routing-needs.d.ts +75 -0
  136. package/dist/core/model-routing-needs.d.ts.map +1 -0
  137. package/dist/core/model-routing-needs.js +176 -0
  138. package/dist/core/model-routing-needs.js.map +1 -0
  139. package/dist/core/model-runtime-streaming.js +3 -0
  140. package/dist/core/model-runtime-streaming.js.map +1 -1
  141. package/dist/core/model-runtime.js +26 -14
  142. package/dist/core/model-runtime.js.map +1 -1
  143. package/dist/core/models-store.js +2 -3
  144. package/dist/core/models-store.js.map +1 -1
  145. package/dist/core/output-guard.js +1 -0
  146. package/dist/core/output-guard.js.map +1 -1
  147. package/dist/core/package-manager-paths.d.ts +2 -1
  148. package/dist/core/package-manager-paths.d.ts.map +1 -1
  149. package/dist/core/package-manager-paths.js +4 -3
  150. package/dist/core/package-manager-paths.js.map +1 -1
  151. package/dist/core/package-manager.js +1 -0
  152. package/dist/core/package-manager.js.map +1 -1
  153. package/dist/core/resource-loader-assets.d.ts.map +1 -1
  154. package/dist/core/resource-loader-assets.js +9 -7
  155. package/dist/core/resource-loader-assets.js.map +1 -1
  156. package/dist/core/resource-loader-core.js +49 -0
  157. package/dist/core/resource-loader-core.js.map +1 -1
  158. package/dist/core/runtime-credentials.js +2 -1
  159. package/dist/core/runtime-credentials.js.map +1 -1
  160. package/dist/core/session-cwd.js +1 -0
  161. package/dist/core/session-cwd.js.map +1 -1
  162. package/dist/core/session-manager-archive.d.ts.map +1 -1
  163. package/dist/core/session-manager-archive.js +4 -2
  164. package/dist/core/session-manager-archive.js.map +1 -1
  165. package/dist/core/session-manager-core.js +11 -7
  166. package/dist/core/session-manager-core.js.map +1 -1
  167. package/dist/core/session-manager-storage.d.ts +10 -4
  168. package/dist/core/session-manager-storage.d.ts.map +1 -1
  169. package/dist/core/session-manager-storage.js +12 -6
  170. package/dist/core/session-manager-storage.js.map +1 -1
  171. package/dist/core/settings-manager-basic-accessors.d.ts +2 -1
  172. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  173. package/dist/core/settings-manager-basic-accessors.js +21 -0
  174. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  175. package/dist/core/settings-manager-core.js +13 -7
  176. package/dist/core/settings-manager-core.js.map +1 -1
  177. package/dist/core/settings-manager.d.ts +1 -1
  178. package/dist/core/settings-manager.d.ts.map +1 -1
  179. package/dist/core/settings-manager.js.map +1 -1
  180. package/dist/core/settings-storage.js +6 -0
  181. package/dist/core/settings-storage.js.map +1 -1
  182. package/dist/core/settings-types.d.ts +8 -0
  183. package/dist/core/settings-types.d.ts.map +1 -1
  184. package/dist/core/settings-types.js.map +1 -1
  185. package/dist/core/structured-output/index.d.ts.map +1 -1
  186. package/dist/core/structured-output/index.js +4 -1
  187. package/dist/core/structured-output/index.js.map +1 -1
  188. package/dist/core/structured-output/invalid-output.js +1 -0
  189. package/dist/core/structured-output/invalid-output.js.map +1 -1
  190. package/dist/core/tasks/agent-adapter.js +5 -3
  191. package/dist/core/tasks/agent-adapter.js.map +1 -1
  192. package/dist/core/tasks/child-command-owner.js +3 -7
  193. package/dist/core/tasks/child-command-owner.js.map +1 -1
  194. package/dist/core/tasks/completion.js +5 -1
  195. package/dist/core/tasks/completion.js.map +1 -1
  196. package/dist/core/tasks/owner-store.js +12 -8
  197. package/dist/core/tasks/owner-store.js.map +1 -1
  198. package/dist/core/tasks/supervisor.js +14 -35
  199. package/dist/core/tasks/supervisor.js.map +1 -1
  200. package/dist/core/tools/ask-user-question/state/build-questionnaire.js +13 -4
  201. package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
  202. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +11 -1
  203. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  204. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +1 -0
  205. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
  206. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js +1 -0
  207. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
  208. package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
  209. package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
  210. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js +5 -0
  211. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
  212. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js +2 -0
  213. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
  214. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js +13 -8
  215. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js.map +1 -1
  216. package/dist/core/tools/ask-user-question/view/components/submit-picker.js +1 -0
  217. package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
  218. package/dist/core/tools/ask-user-question/view/components/tab-bar.js +1 -0
  219. package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
  220. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +30 -24
  221. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  222. package/dist/core/tools/ask-user-question/view/dialog-builder.js +5 -0
  223. package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
  224. package/dist/core/tools/ask-user-question/view/props-adapter.js +8 -0
  225. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  226. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js +4 -4
  227. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
  228. package/dist/core/tools/bash.js +5 -8
  229. package/dist/core/tools/bash.js.map +1 -1
  230. package/dist/core/tools/edit-batch.js +4 -0
  231. package/dist/core/tools/edit-batch.js.map +1 -1
  232. package/dist/core/tools/edit.js +2 -0
  233. package/dist/core/tools/edit.js.map +1 -1
  234. package/dist/core/tools/file-mutation-coordinator.js +9 -0
  235. package/dist/core/tools/file-mutation-coordinator.js.map +1 -1
  236. package/dist/core/tools/find.js +1 -1
  237. package/dist/core/tools/find.js.map +1 -1
  238. package/dist/core/tools/hashline-engine/fs.js +1 -1
  239. package/dist/core/tools/hashline-engine/fs.js.map +1 -1
  240. package/dist/core/tools/hashline-engine/input.js +4 -0
  241. package/dist/core/tools/hashline-engine/input.js.map +1 -1
  242. package/dist/core/tools/hashline-engine/mismatch.js +6 -0
  243. package/dist/core/tools/hashline-engine/mismatch.js.map +1 -1
  244. package/dist/core/tools/hashline-engine/patcher.js +13 -0
  245. package/dist/core/tools/hashline-engine/patcher.js.map +1 -1
  246. package/dist/core/tools/hashline-engine/recovery.js +1 -0
  247. package/dist/core/tools/hashline-engine/recovery.js.map +1 -1
  248. package/dist/core/tools/output-accumulator.js +20 -13
  249. package/dist/core/tools/output-accumulator.js.map +1 -1
  250. package/dist/core/tools/persisted-output-file.js +9 -3
  251. package/dist/core/tools/persisted-output-file.js.map +1 -1
  252. package/dist/core/tools/resource-selectors.js +1 -0
  253. package/dist/core/tools/resource-selectors.js.map +1 -1
  254. package/dist/core/tools/write.js +1 -0
  255. package/dist/core/tools/write.js.map +1 -1
  256. package/dist/core/trust-manager.js +1 -0
  257. package/dist/core/trust-manager.js.map +1 -1
  258. package/dist/core/workflow-stage-admission.js +17 -10
  259. package/dist/core/workflow-stage-admission.js.map +1 -1
  260. package/dist/extensions/llama/client.js +2 -0
  261. package/dist/extensions/llama/client.js.map +1 -1
  262. package/dist/extensions/llama/huggingface-ui.js +17 -9
  263. package/dist/extensions/llama/huggingface-ui.js.map +1 -1
  264. package/dist/extensions/llama/huggingface.js +2 -0
  265. package/dist/extensions/llama/huggingface.js.map +1 -1
  266. package/dist/extensions/llama/ui.js +11 -3
  267. package/dist/extensions/llama/ui.js.map +1 -1
  268. package/dist/index.d.ts +4 -2
  269. package/dist/index.d.ts.map +1 -1
  270. package/dist/index.js +3 -1
  271. package/dist/index.js.map +1 -1
  272. package/dist/modes/interactive/components/armin.js +10 -6
  273. package/dist/modes/interactive/components/armin.js.map +1 -1
  274. package/dist/modes/interactive/components/assistant-message.js +10 -2
  275. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  276. package/dist/modes/interactive/components/atomic-working-status.js +10 -2
  277. package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
  278. package/dist/modes/interactive/components/bash-execution.js +9 -4
  279. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  280. package/dist/modes/interactive/components/bordered-loader.js +3 -0
  281. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  282. package/dist/modes/interactive/components/branch-summary-message.js +4 -1
  283. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  284. package/dist/modes/interactive/components/chat-message-renderer.js +2 -1
  285. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  286. package/dist/modes/interactive/components/chat-session-host-state.js +63 -31
  287. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  288. package/dist/modes/interactive/components/chat-session-host.js +8 -1
  289. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  290. package/dist/modes/interactive/components/chat-transcript.js +24 -14
  291. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  292. package/dist/modes/interactive/components/compaction-boundary-message.js +2 -1
  293. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  294. package/dist/modes/interactive/components/config-selector-list.js +15 -6
  295. package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
  296. package/dist/modes/interactive/components/config-selector.js +7 -1
  297. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  298. package/dist/modes/interactive/components/countdown-timer.js +2 -0
  299. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  300. package/dist/modes/interactive/components/custom-editor.js +21 -1
  301. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  302. package/dist/modes/interactive/components/custom-entry.js +4 -1
  303. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  304. package/dist/modes/interactive/components/custom-message.js +9 -1
  305. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  306. package/dist/modes/interactive/components/daxnuts.js +8 -6
  307. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  308. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  309. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  310. package/dist/modes/interactive/components/extension-editor.js +7 -1
  311. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  312. package/dist/modes/interactive/components/extension-input.js +8 -2
  313. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  314. package/dist/modes/interactive/components/extension-selector.js +9 -1
  315. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  316. package/dist/modes/interactive/components/first-time-setup.js +4 -2
  317. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  318. package/dist/modes/interactive/components/footer.js +5 -2
  319. package/dist/modes/interactive/components/footer.js.map +1 -1
  320. package/dist/modes/interactive/components/host-input-form.js +13 -2
  321. package/dist/modes/interactive/components/host-input-form.js.map +1 -1
  322. package/dist/modes/interactive/components/login-dialog.js +9 -3
  323. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  324. package/dist/modes/interactive/components/model-selector.js +24 -12
  325. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  326. package/dist/modes/interactive/components/oauth-selector.js +12 -3
  327. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  328. package/dist/modes/interactive/components/reserved-bottom-overlay.js +11 -2
  329. package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
  330. package/dist/modes/interactive/components/scoped-models-selector.js +13 -8
  331. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  332. package/dist/modes/interactive/components/scroll-widget.js +4 -0
  333. package/dist/modes/interactive/components/scroll-widget.js.map +1 -1
  334. package/dist/modes/interactive/components/session-selector-header.js +11 -7
  335. package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
  336. package/dist/modes/interactive/components/session-selector-list.js +25 -12
  337. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  338. package/dist/modes/interactive/components/session-selector.js +23 -15
  339. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  340. package/dist/modes/interactive/components/settings-selector-submenus.js +19 -1
  341. package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
  342. package/dist/modes/interactive/components/settings-selector.js +1 -0
  343. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  344. package/dist/modes/interactive/components/show-images-selector.js +1 -0
  345. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  346. package/dist/modes/interactive/components/skill-invocation-message.js +4 -1
  347. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  348. package/dist/modes/interactive/components/startup-identity.js +8 -3
  349. package/dist/modes/interactive/components/startup-identity.js.map +1 -1
  350. package/dist/modes/interactive/components/task-completion-message.js +2 -0
  351. package/dist/modes/interactive/components/task-completion-message.js.map +1 -1
  352. package/dist/modes/interactive/components/task-detail.js +2 -0
  353. package/dist/modes/interactive/components/task-detail.js.map +1 -1
  354. package/dist/modes/interactive/components/task-inspector.js +22 -12
  355. package/dist/modes/interactive/components/task-inspector.js.map +1 -1
  356. package/dist/modes/interactive/components/task-list.js +2 -0
  357. package/dist/modes/interactive/components/task-list.js.map +1 -1
  358. package/dist/modes/interactive/components/task-live-transcript.js +8 -3
  359. package/dist/modes/interactive/components/task-live-transcript.js.map +1 -1
  360. package/dist/modes/interactive/components/task-navigation.js +5 -2
  361. package/dist/modes/interactive/components/task-navigation.js.map +1 -1
  362. package/dist/modes/interactive/components/task-row.js +2 -0
  363. package/dist/modes/interactive/components/task-row.js.map +1 -1
  364. package/dist/modes/interactive/components/theme-selector.js +2 -0
  365. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  366. package/dist/modes/interactive/components/thinking-selector.js +7 -1
  367. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  368. package/dist/modes/interactive/components/tool-execution.js +25 -10
  369. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  370. package/dist/modes/interactive/components/transcript-follow-indicator.js +1 -0
  371. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
  372. package/dist/modes/interactive/components/tree-selector-component.js +7 -3
  373. package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
  374. package/dist/modes/interactive/components/tree-selector-help.js +1 -0
  375. package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
  376. package/dist/modes/interactive/components/tree-selector-label-input.js +6 -2
  377. package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
  378. package/dist/modes/interactive/components/tree-selector-list.js +4 -0
  379. package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
  380. package/dist/modes/interactive/components/trust-selector.js +6 -0
  381. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/user-message-selector.js +6 -3
  383. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  384. package/dist/modes/interactive/components/user-message.js +5 -0
  385. package/dist/modes/interactive/components/user-message.js.map +1 -1
  386. package/dist/modes/interactive/components/working-status.js +1 -0
  387. package/dist/modes/interactive/components/working-status.js.map +1 -1
  388. package/dist/modes/interactive/interactive-autocomplete.js +2 -0
  389. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  390. package/dist/modes/interactive/interactive-extension-runtime.js +1 -0
  391. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  392. package/dist/modes/interactive/interactive-mode-base.js +162 -120
  393. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  394. package/dist/modes/interactive/interactive-mode-helpers.js +3 -0
  395. package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -1
  396. package/dist/modes/interactive/interactive-mode-surface.d.ts +0 -6
  397. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  398. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  399. package/dist/modes/interactive/interactive-resource-disclosure.js +0 -4
  400. package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -1
  401. package/dist/modes/interactive/interactive-resource-rendering.js +0 -12
  402. package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -1
  403. package/dist/modes/interactive/interactive-startup-chat-container.js +1 -4
  404. package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
  405. package/dist/modes/interactive/model-catalog-refresh.js +1 -3
  406. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -1
  407. package/dist/modes/interactive/theme/color-utils.d.ts +5 -0
  408. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  409. package/dist/modes/interactive/theme/color-utils.js +11 -0
  410. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  411. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  412. package/dist/modes/interactive/theme/global-theme.js +4 -3
  413. package/dist/modes/interactive/theme/global-theme.js.map +1 -1
  414. package/dist/modes/interactive/theme/theme-class.js +7 -0
  415. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  416. package/dist/modes/interactive/theme/theme-controller.js +9 -2
  417. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  418. package/dist/modes/interactive-engine/activity-watchdog.js +8 -3
  419. package/dist/modes/interactive-engine/activity-watchdog.js.map +1 -1
  420. package/dist/modes/interactive-engine/engine-custom-ui.js +12 -8
  421. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  422. package/dist/modes/interactive-engine/engine-dialog-host.js +7 -3
  423. package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
  424. package/dist/modes/interactive-engine/engine-health.js +23 -13
  425. package/dist/modes/interactive-engine/engine-health.js.map +1 -1
  426. package/dist/modes/interactive-engine/engine-input-form.js +3 -2
  427. package/dist/modes/interactive-engine/engine-input-form.js.map +1 -1
  428. package/dist/modes/interactive-engine/engine-monitor.js +13 -1
  429. package/dist/modes/interactive-engine/engine-monitor.js.map +1 -1
  430. package/dist/modes/interactive-engine/engine-project-trust.js +2 -1
  431. package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -1
  432. package/dist/modes/interactive-engine/engine-render-service.js +7 -4
  433. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  434. package/dist/modes/interactive-engine/engine-session-picker.js +3 -2
  435. package/dist/modes/interactive-engine/engine-session-picker.js.map +1 -1
  436. package/dist/modes/interactive-engine/input-form-host.js +5 -1
  437. package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
  438. package/dist/modes/interactive-engine/isolated-runtime.js +37 -23
  439. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  440. package/dist/modes/interactive-engine/remote-command-catalog.js +4 -3
  441. package/dist/modes/interactive-engine/remote-command-catalog.js.map +1 -1
  442. package/dist/modes/interactive-engine/remote-component.js +24 -12
  443. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  444. package/dist/modes/interactive-engine/remote-frame-clamp.js +3 -3
  445. package/dist/modes/interactive-engine/remote-frame-clamp.js.map +1 -1
  446. package/dist/modes/interactive-engine/remote-model-catalog.js +5 -4
  447. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  448. package/dist/modes/interactive-engine/remote-queue-pause.js +3 -1
  449. package/dist/modes/interactive-engine/remote-queue-pause.js.map +1 -1
  450. package/dist/modes/interactive-engine/remote-renderer.js +24 -13
  451. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  452. package/dist/modes/interactive-engine/resource-readiness-error.js +1 -0
  453. package/dist/modes/interactive-engine/resource-readiness-error.js.map +1 -1
  454. package/dist/modes/interactive-engine/session-picker-host.js +5 -1
  455. package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
  456. package/dist/modes/interactive-engine/terminal-mode-controller.js +2 -1
  457. package/dist/modes/interactive-engine/terminal-mode-controller.js.map +1 -1
  458. package/dist/modes/rpc/queued-writer.js +13 -4
  459. package/dist/modes/rpc/queued-writer.js.map +1 -1
  460. package/dist/modes/rpc/rpc-bash-request-owners.js +2 -1
  461. package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
  462. package/dist/modes/rpc/rpc-client-api.d.ts +8 -4
  463. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  464. package/dist/modes/rpc/rpc-client-api.js +10 -3
  465. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  466. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  467. package/dist/modes/rpc/rpc-client.js +35 -22
  468. package/dist/modes/rpc/rpc-client.js.map +1 -1
  469. package/dist/modes/rpc/rpc-command-handler.js +6 -6
  470. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  471. package/dist/modes/rpc/rpc-event-buffer.js +3 -1
  472. package/dist/modes/rpc/rpc-event-buffer.js.map +1 -1
  473. package/dist/modes/rpc/rpc-generation-buffer.js +1 -3
  474. package/dist/modes/rpc/rpc-generation-buffer.js.map +1 -1
  475. package/dist/modes/rpc/rpc-keybindings-reload.js +4 -1
  476. package/dist/modes/rpc/rpc-keybindings-reload.js.map +1 -1
  477. package/dist/modes/rpc/rpc-output-buffer.js +3 -4
  478. package/dist/modes/rpc/rpc-output-buffer.js.map +1 -1
  479. package/dist/modes/rpc/rpc-pending-requests.js +1 -3
  480. package/dist/modes/rpc/rpc-pending-requests.js.map +1 -1
  481. package/dist/modes/rpc/rpc-provider-auth.js +3 -1
  482. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  483. package/dist/modes/rpc/rpc-resource-readiness.js +4 -5
  484. package/dist/modes/rpc/rpc-resource-readiness.js.map +1 -1
  485. package/dist/modes/rpc/rpc-session-binding.js +15 -0
  486. package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
  487. package/dist/modes/rpc/rpc-terminal-drain.js +3 -0
  488. package/dist/modes/rpc/rpc-terminal-drain.js.map +1 -1
  489. package/dist/modes/rpc/rpc-types.d.ts +10 -1
  490. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  491. package/dist/modes/rpc/rpc-types.js.map +1 -1
  492. package/docs/models/evals.md +883 -39
  493. package/docs/models/model-selection.md +7 -8
  494. package/docs/rpc/examples.md +1 -1
  495. package/docs/rpc/protocol.md +9 -3
  496. package/docs/sdk/structured-decisions.md +1 -1
  497. package/docs/sdk.md +3 -3
  498. package/docs/settings.md +24 -3
  499. package/docs/subagents/reference.md +22 -4
  500. package/docs/subagents.md +2 -0
  501. package/docs/usage.md +3 -3
  502. package/docs/workflows/api-reference.md +1 -1
  503. package/docs/workflows/authoring.md +1 -7
  504. package/docs/workflows/builtins.md +1 -1
  505. package/docs/workflows/reliable-design.md +1 -1
  506. package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
  507. package/examples/extensions/gondolin/package.json +1 -1
  508. package/examples/rpc-client.ts +1 -1
  509. package/examples/rpc-extension-ui.ts +1 -1
  510. package/npm-shrinkwrap.json +70 -33
  511. package/package.json +6 -7
  512. package/dist/core/model-routing-task.d.ts.map +0 -1
  513. package/dist/core/model-routing-task.js +0 -120
  514. package/dist/core/model-routing-task.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tAuthOperationOptions,\n\tAuthResult,\n\tClassifierApi,\n\tClassifierContext,\n\tClassifierModel,\n\tClassifierResult,\n\tContext,\n\tModel,\n\tModelsApiStreamOptions,\n\tModelsClassifierOptions,\n\tModelsRefreshOptions,\n\tModelsRefreshResult,\n\tModelsSimpleStreamOptions,\n\tProvider,\n\tProviderHeaders,\n} from \"@bastani/pi-ai\";\nimport type { ModelRuntime } from \"./model-runtime.js\";\nimport type { AuthStatus, ProviderConfigInput } from \"./provider-composer.ts\";\n\nexport type { ProviderConfigInput } from \"./provider-composer.ts\";\nexport type ResolvedRequestAuth =\n\t| {\n\t\t\tok: true;\n\t\t\tapiKey?: string;\n\t\t\theaders?: ProviderHeaders;\n\t\t\tbaseUrl?: string;\n\t\t\tenv?: Record<string, string>;\n\t }\n\t| { ok: false; error: string };\nexport { clearApiKeyCache } from \"./provider-composer.ts\";\n\n/**\n * Compatibility facade exposed to extensions.\n * Coding-agent internals use ModelRuntime directly.\n */\nexport class ModelRegistry {\n\tprivate readonly runtime: ModelRuntime;\n\n\tconstructor(runtime: ModelRuntime) {\n\t\tthis.runtime = runtime;\n\t}\n\n\t/**\n\t * Reload models.json asynchronously. Await before making synchronous registry reads.\n\t * Returns pi's refresh result so callers can react to per-provider failures\n\t * (`errors`) and cancellation (`aborted`); pi reports both without rejecting.\n\t */\n\tasync refresh(options?: ModelsRefreshOptions): Promise<ModelsRefreshResult> {\n\t\treturn this.runtime.refresh(options);\n\t}\n\n\tgetError(): string | undefined {\n\t\treturn this.runtime.getError();\n\t}\n\n\tgetAll(): Model<Api>[] {\n\t\treturn [...this.runtime.getModels()];\n\t}\n\n\tgetAvailable(): Model<Api>[] {\n\t\treturn [...this.runtime.getAvailableSnapshot()];\n\t}\n\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.runtime.getModel(provider, modelId);\n\t}\n\n\tgetClassifierModel(provider: string, modelId: string): ClassifierModel<ClassifierApi> | undefined {\n\t\treturn this.runtime.getModelOfType(\"classifier\", provider, modelId);\n\t}\n\n\thasConfiguredAuth(model: Model<Api>): boolean {\n\t\treturn this.runtime.hasConfiguredAuth(model.provider);\n\t}\n\n\t/** Boolean-only access to configured credential screening, without resolving request auth. */\n\tcontainsConfiguredCredential(serialized: string): Promise<boolean> {\n\t\treturn this.runtime.containsConfiguredCredential(serialized);\n\t}\n\n\tasync getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth> {\n\t\ttry {\n\t\t\tconst resolution = await this.runtime.getAuth(model);\n\t\t\tif (!resolution) {\n\t\t\t\tconst compatibility = this.runtime.getCompatibilityRequestConfig(model);\n\t\t\t\tif (compatibility.authHeader) {\n\t\t\t\t\treturn { ok: false, error: `No API key found for \"${model.provider}\"` };\n\t\t\t\t}\n\t\t\t\treturn { ok: true, headers: compatibility.headers };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tapiKey: resolution.auth.apiKey,\n\t\t\t\theaders: resolution.auth.headers,\n\t\t\t\t...(resolution.auth.baseUrl === undefined ? {} : { baseUrl: resolution.auth.baseUrl }),\n\t\t\t\tenv: resolution.env,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst cause = error instanceof Error ? error.cause : undefined;\n\t\t\tconst message =\n\t\t\t\tcause instanceof Error ? cause.message : error instanceof Error ? error.message : String(error);\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror:\n\t\t\t\t\tmessage === \"authHeader requires a resolved API key\"\n\t\t\t\t\t\t? `No API key found for \"${model.provider}\"`\n\t\t\t\t\t\t: message,\n\t\t\t};\n\t\t}\n\t}\n\n\tgetProviderAuthStatus(provider: string): AuthStatus {\n\t\treturn this.runtime.getProviderAuthStatus(provider);\n\t}\n\n\tgetProvider(provider: string): Provider | undefined {\n\t\treturn this.runtime.getProvider(provider);\n\t}\n\n\t/** Stream through the configured provider with request-time authentication. */\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream {\n\t\treturn this.runtime.stream(model, context, options);\n\t}\n\n\t/** Stream with provider-neutral options and request-time authentication. */\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream {\n\t\treturn this.runtime.streamSimple(model, context, options);\n\t}\n\n\t/** Complete through the active runtime so provider composition and request auth apply. */\n\tcomplete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage> {\n\t\treturn this.runtime.complete(model, context, options);\n\t}\n\n\tclassify(\n\t\tmodel: ClassifierModel<ClassifierApi>,\n\t\tcontext: ClassifierContext,\n\t\toptions?: ModelsClassifierOptions,\n\t): Promise<ClassifierResult> {\n\t\treturn this.runtime.classify(model, context, options);\n\t}\n\n\tgetProviderDisplayName(provider: string): string {\n\t\treturn this.runtime.getProvider(provider)?.name ?? provider;\n\t}\n\n\tgetProviderAuth(provider: string, options?: AuthOperationOptions): Promise<AuthResult | undefined> {\n\t\treturn this.runtime.getAuth(provider, options);\n\t}\n\n\tasync getApiKeyForProvider(provider: string): Promise<string | undefined> {\n\t\ttry {\n\t\t\treturn (await this.runtime.getAuth(provider))?.auth.apiKey;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tisUsingOAuth(model: Model<Api>): boolean {\n\t\treturn this.runtime.isUsingOAuth(model.provider);\n\t}\n\n\tregisterProvider(provider: Provider): void;\n\tregisterProvider(providerName: string, config: ProviderConfigInput): void;\n\tregisterProvider(providerOrName: Provider | string, config?: ProviderConfigInput): void {\n\t\tif (typeof providerOrName === \"string\") {\n\t\t\tif (!config) throw new Error(\"Provider config is required when registering by name\");\n\t\t\tthis.runtime.registerProvider(providerOrName, config);\n\t\t\treturn;\n\t\t}\n\t\tthis.runtime.registerNativeProvider(providerOrName);\n\t}\n\n\tunregisterProvider(providerName: string): void {\n\t\tthis.runtime.unregisterProvider(providerName);\n\t}\n\n\tgetRegisteredProviderConfig(providerName: string): ProviderConfigInput | undefined {\n\t\treturn this.runtime.getRegisteredProviderConfig(providerName);\n\t}\n\n\tgetRegisteredNativeProvider(providerName: string): Provider | undefined {\n\t\treturn this.runtime.getRegisteredNativeProvider(providerName);\n\t}\n\n\tgetRegisteredProviderIds(): readonly string[] {\n\t\treturn this.runtime.getRegisteredProviderIds();\n\t}\n}\n"]}
1
+ {"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tAuthOperationOptions,\n\tAuthResult,\n\tClassifierApi,\n\tClassifierContext,\n\tClassifierModel,\n\tClassifierResult,\n\tContext,\n\tModel,\n\tModelsApiStreamOptions,\n\tModelsClassifierOptions,\n\tModelsRefreshOptions,\n\tModelsRefreshResult,\n\tModelsSimpleStreamOptions,\n\tProvider,\n\tProviderHeaders,\n} from \"@bastani/pi-ai\";\nimport type { ModelRuntime } from \"./model-runtime.js\";\nimport type { AuthStatus, ProviderConfigInput } from \"./provider-composer.ts\";\n\nexport type { ProviderConfigInput } from \"./provider-composer.ts\";\nexport type ResolvedRequestAuth =\n\t| {\n\t\t\tok: true;\n\t\t\tapiKey?: string;\n\t\t\theaders?: ProviderHeaders;\n\t\t\tbaseUrl?: string;\n\t\t\tenv?: Record<string, string>;\n\t }\n\t| { ok: false; error: string };\nexport { clearApiKeyCache } from \"./provider-composer.ts\";\n\n/**\n * Compatibility facade exposed to extensions.\n * Coding-agent internals use ModelRuntime directly.\n */\nexport class ModelRegistry {\n\tprivate readonly runtime: ModelRuntime;\n\n\tconstructor(runtime: ModelRuntime) {\n\t\tthis.runtime = runtime;\n\t}\n\n\t/**\n\t * Reload models.json asynchronously. Await before making synchronous registry reads.\n\t * Returns pi's refresh result so callers can react to per-provider failures\n\t * (`errors`) and cancellation (`aborted`); pi reports both without rejecting.\n\t */\n\tasync refresh(options?: ModelsRefreshOptions): Promise<ModelsRefreshResult> {\n\t\treturn this.runtime.refresh(options);\n\t}\n\n\tgetError(): string | undefined {\n\t\treturn this.runtime.getError();\n\t}\n\n\tgetAll(): Model<Api>[] {\n\t\treturn [...this.runtime.getModels()];\n\t}\n\n\tgetAvailable(): Model<Api>[] {\n\t\treturn [...this.runtime.getAvailableSnapshot()];\n\t}\n\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.runtime.getModel(provider, modelId);\n\t}\n\n\tgetClassifierModel(provider: string, modelId: string): ClassifierModel<ClassifierApi> | undefined {\n\t\treturn this.runtime.getModelOfType(\"classifier\", provider, modelId);\n\t}\n\n\thasConfiguredAuth(model: Model<Api>): boolean {\n\t\treturn this.runtime.hasConfiguredAuth(model.provider);\n\t}\n\n\t/** Boolean-only access to configured credential screening, without resolving request auth. */\n\tcontainsConfiguredCredential(serialized: string): Promise<boolean> {\n\t\treturn this.runtime.containsConfiguredCredential(serialized);\n\t}\n\n\tasync getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth> {\n\t\ttry {\n\t\t\tconst resolution = await this.runtime.getAuth(model);\n\t\t\tif (!resolution) {\n\t\t\t\tconst compatibility = this.runtime.getCompatibilityRequestConfig(model);\n\t\t\t\tif (compatibility.authHeader) {\n\t\t\t\t\treturn { ok: false, error: `No API key found for \"${model.provider}\"` };\n\t\t\t\t}\n\t\t\t\treturn { ok: true, headers: compatibility.headers };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tapiKey: resolution.auth.apiKey,\n\t\t\t\theaders: resolution.auth.headers,\n\t\t\t\t...(resolution.auth.baseUrl === undefined ? {} : { baseUrl: resolution.auth.baseUrl }),\n\t\t\t\tenv: resolution.env,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst cause = error instanceof Error ? error.cause : undefined;\n\t\t\tconst message =\n\t\t\t\tcause instanceof Error ? cause.message : error instanceof Error ? error.message : String(error);\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror:\n\t\t\t\t\tmessage === \"authHeader requires a resolved API key\"\n\t\t\t\t\t\t? `No API key found for \"${model.provider}\"`\n\t\t\t\t\t\t: message,\n\t\t\t};\n\t\t}\n\t}\n\n\tgetProviderAuthStatus(provider: string): AuthStatus {\n\t\treturn this.runtime.getProviderAuthStatus(provider);\n\t}\n\n\tgetProvider(provider: string): Provider | undefined {\n\t\treturn this.runtime.getProvider(provider);\n\t}\n\n\t/** Stream through the configured provider with request-time authentication. */\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream {\n\t\treturn this.runtime.stream(model, context, options);\n\t}\n\n\t/** Stream with provider-neutral options and request-time authentication. */\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream {\n\t\treturn this.runtime.streamSimple(model, context, options);\n\t}\n\n\t/** Complete through the active runtime so provider composition and request auth apply. */\n\tcomplete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage> {\n\t\treturn this.runtime.complete(model, context, options);\n\t}\n\n\tclassify(\n\t\tmodel: ClassifierModel<ClassifierApi>,\n\t\tcontext: ClassifierContext,\n\t\toptions?: ModelsClassifierOptions,\n\t): Promise<ClassifierResult> {\n\t\treturn this.runtime.classify(model, context, options);\n\t}\n\n\tgetProviderDisplayName(provider: string): string {\n\t\treturn this.runtime.getProvider(provider)?.name ?? provider;\n\t}\n\n\tgetProviderAuth(provider: string, options?: AuthOperationOptions): Promise<AuthResult | undefined> {\n\t\treturn this.runtime.getAuth(provider, options);\n\t}\n\n\tasync getApiKeyForProvider(provider: string): Promise<string | undefined> {\n\t\ttry {\n\t\t\treturn (await this.runtime.getAuth(provider))?.auth.apiKey;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tisUsingOAuth(model: Model<Api>): boolean {\n\t\treturn this.runtime.isUsingOAuth(model.provider);\n\t}\n\n\tregisterProvider(provider: Provider): void;\n\tregisterProvider(providerName: string, config: ProviderConfigInput): void;\n\tregisterProvider(providerOrName: Provider | string, config?: ProviderConfigInput): void {\n\t\tif (typeof providerOrName === \"string\") {\n\t\t\tif (!config) throw new Error(\"Provider config is required when registering by name\");\n\t\t\tthis.runtime.registerProvider(providerOrName, config);\n\t\t\treturn;\n\t\t}\n\t\tthis.runtime.registerNativeProvider(providerOrName);\n\t}\n\n\tunregisterProvider(providerName: string): void {\n\t\tthis.runtime.unregisterProvider(providerName);\n\t}\n\n\tgetRegisteredProviderConfig(providerName: string): ProviderConfigInput | undefined {\n\t\treturn this.runtime.getRegisteredProviderConfig(providerName);\n\t}\n\n\tgetRegisteredNativeProvider(providerName: string): Provider | undefined {\n\t\treturn this.runtime.getRegisteredNativeProvider(providerName);\n\t}\n\n\tgetRegisteredProviderIds(): readonly string[] {\n\t\treturn this.runtime.getRegisteredProviderIds();\n\t}\n}\n"]}
@@ -1,9 +1,6 @@
1
1
  export declare const ROUTING_REQUEST_BYTES = 60000;
2
- export declare const MODEL_ROUTING_TASK_BYTES = 9000;
3
2
  export declare const TRUNCATED_MARKER = "\n[... truncated ...]\n";
4
3
  export declare function jsonBytes(value: string): number;
5
4
  /** Keep the longest prefix that fits, marking the cut. Returns "" when not even the marker fits. */
6
5
  export declare function truncateToBytes(text: string, maxBytes: number): string;
7
- /** Bound only the model selector's copy. Execution and hard constraints stay intact. */
8
- export declare function modelRoutingTask(task: string, maxBytes?: number): string;
9
- //# sourceMappingURL=model-routing-task.d.ts.map
6
+ //# sourceMappingURL=model-routing-bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-routing-bytes.d.ts","sourceRoot":"","sources":["../../src/core/model-routing-bytes.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAE1D,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AASD,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWtE"}
@@ -0,0 +1,33 @@
1
+ // Jev is the smallest routing classifier: 32k tokens for state plus the longest
2
+ // question. Measured against Jev 1.13, dense markdown runs about 1.9 JSON bytes per
3
+ // token and escaped candidate JSON about 2.4, so 60_000 JSON bytes stays under the
4
+ // limit for every input. Larger classifiers and chat fallbacks accept the same copy.
5
+ export const ROUTING_REQUEST_BYTES = 60_000;
6
+ export const TRUNCATED_MARKER = "\n[... truncated ...]\n";
7
+ export function jsonBytes(value) {
8
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
9
+ }
10
+ // Never split a UTF-16 surrogate pair at a cut.
11
+ function boundary(text, index) {
12
+ const before = text.charCodeAt(index - 1);
13
+ const after = text.charCodeAt(index);
14
+ return before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff ? index - 1 : index;
15
+ }
16
+ /** Keep the longest prefix that fits, marking the cut. Returns "" when not even the marker fits. */
17
+ export function truncateToBytes(text, maxBytes) {
18
+ if (jsonBytes(text) <= maxBytes)
19
+ return text;
20
+ if (jsonBytes(TRUNCATED_MARKER) > maxBytes)
21
+ return "";
22
+ let low = 0;
23
+ let high = text.length;
24
+ while (low < high) {
25
+ const middle = Math.ceil((low + high) / 2);
26
+ if (jsonBytes(`${text.slice(0, boundary(text, middle))}${TRUNCATED_MARKER}`) <= maxBytes)
27
+ low = middle;
28
+ else
29
+ high = middle - 1;
30
+ }
31
+ return `${text.slice(0, boundary(text, low))}${TRUNCATED_MARKER}`;
32
+ }
33
+ //# sourceMappingURL=model-routing-bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-routing-bytes.js","sourceRoot":"","sources":["../../src/core/model-routing-bytes.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,oFAAoF;AACpF,mFAAmF;AACnF,qFAAqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAE1D,MAAM,UAAU,SAAS,CAAC,KAAa;IACtC,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAED,gDAAgD;AAChD,SAAS,QAAQ,CAAC,IAAY,EAAE,KAAa;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACvG,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC7D,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,SAAS,CAAC,gBAAgB,CAAC,GAAG,QAAQ;QAAE,OAAO,EAAE,CAAC;IACtD,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;IACvB,OAAO,GAAG,GAAG,IAAI,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,IAAI,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,GAAG,gBAAgB,EAAE,CAAC,IAAI,QAAQ;YAAE,GAAG,GAAG,MAAM,CAAC;;YAClG,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,gBAAgB,EAAE,CAAC;AACnE,CAAC","sourcesContent":["// Jev is the smallest routing classifier: 32k tokens for state plus the longest\n// question. Measured against Jev 1.13, dense markdown runs about 1.9 JSON bytes per\n// token and escaped candidate JSON about 2.4, so 60_000 JSON bytes stays under the\n// limit for every input. Larger classifiers and chat fallbacks accept the same copy.\nexport const ROUTING_REQUEST_BYTES = 60_000;\nexport const TRUNCATED_MARKER = \"\\n[... truncated ...]\\n\";\n\nexport function jsonBytes(value: string): number {\n\treturn Buffer.byteLength(JSON.stringify(value), \"utf8\");\n}\n\n// Never split a UTF-16 surrogate pair at a cut.\nfunction boundary(text: string, index: number): number {\n\tconst before = text.charCodeAt(index - 1);\n\tconst after = text.charCodeAt(index);\n\treturn before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff ? index - 1 : index;\n}\n\n/** Keep the longest prefix that fits, marking the cut. Returns \"\" when not even the marker fits. */\nexport function truncateToBytes(text: string, maxBytes: number): string {\n\tif (jsonBytes(text) <= maxBytes) return text;\n\tif (jsonBytes(TRUNCATED_MARKER) > maxBytes) return \"\";\n\tlet low = 0;\n\tlet high = text.length;\n\twhile (low < high) {\n\t\tconst middle = Math.ceil((low + high) / 2);\n\t\tif (jsonBytes(`${text.slice(0, boundary(text, middle))}${TRUNCATED_MARKER}`) <= maxBytes) low = middle;\n\t\telse high = middle - 1;\n\t}\n\treturn `${text.slice(0, boundary(text, low))}${TRUNCATED_MARKER}`;\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import { type EvalsCatalog } from "./model-routing-evals.js";
2
+ import { type ResolvedTaskNeeds } from "./model-routing-needs.js";
3
+ /** What ranking needs to know about one eligible model. */
4
+ export interface CandidateModel {
5
+ /** `provider/id`, as used in router selections. */
6
+ readonly model: string;
7
+ readonly name: string;
8
+ readonly cost: {
9
+ readonly input: number;
10
+ readonly output: number;
11
+ };
12
+ readonly input: readonly string[];
13
+ /** `provider/id` of the base model when this entry is its derived fast route (`fastRoute` metadata). */
14
+ readonly fastRouteOf?: string;
15
+ }
16
+ export interface RankedCandidate extends CandidateModel {
17
+ /** Identity shared by one model's providers and its derived fast route, which collapse onto it. */
18
+ readonly baseKey: string;
19
+ readonly score: number;
20
+ readonly values: ReadonlyMap<string, number>;
21
+ /** How each quoted value was measured, for example its effort, harness or reporter. */
22
+ readonly conditions: ReadonlyMap<string, string>;
23
+ readonly released?: string;
24
+ readonly workStanding?: number;
25
+ readonly overallStanding?: number;
26
+ }
27
+ /**
28
+ * Rank every eligible model for the task in code. Quality is the model's
29
+ * standing on the benchmarks for this kind of work (overall intelligence when it
30
+ * has none), weighed against price by how demanding the task is, with a small
31
+ * preference for newer releases.
32
+ */
33
+ export declare function rankCandidates(catalog: EvalsCatalog, candidates: readonly CandidateModel[], needs: ResolvedTaskNeeds): RankedCandidate[];
34
+ /** The best `size` candidates with at most one per base model. */
35
+ export declare function distinctTop(ranked: readonly RankedCandidate[], size: number): RankedCandidate[];
36
+ /**
37
+ * One shortlisted option described with its own evidence, so the router compares
38
+ * options directly: release date, price tier, image input, and results for this
39
+ * kind of work and overall, with standings relative to every eligible model.
40
+ */
41
+ export declare function describeOption(option: RankedCandidate, needs: ResolvedTaskNeeds, eligible: readonly RankedCandidate[]): string;
42
+ //# sourceMappingURL=model-routing-candidates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-routing-candidates.d.ts","sourceRoot":"","sources":["../../src/core/model-routing-candidates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,YAAY,EAAuB,MAAM,0BAA0B,CAAC;AACzG,OAAO,EAAE,KAAK,iBAAiB,EAA6B,MAAM,0BAA0B,CAAC;AAE7F,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC9B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,wGAAwG;IACxG,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAsED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACtD,mGAAmG;IACnG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,uFAAuF;IACvF,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CAClC;AAuGD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,SAAS,cAAc,EAAE,EACrC,KAAK,EAAE,iBAAiB,GACtB,eAAe,EAAE,CAmEnB;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAU/F;AAYD;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,iBAAiB,EACxB,QAAQ,EAAE,SAAS,eAAe,EAAE,GAClC,MAAM,CAmDR"}
@@ -0,0 +1,309 @@
1
+ import { candidateEvidenceRows, modelEvidenceTokens } from "./model-routing-evals.js";
2
+ import { taskDemand } from "./model-routing-needs.js";
3
+ const percent = (key, label) => ({ key, label, unit: "%" });
4
+ const points = (key, label) => ({ key, label, unit: "" });
5
+ const OVERALL = points("aa:idx", "AA Intelligence Index");
6
+ /** evals.md columns that measure each kind of work, in the order results are quoted. */
7
+ const WORK_METRICS = {
8
+ computer_use: [
9
+ percent("pub:OSW2", "OSWorld 2.0"),
10
+ percent("pub:SSP", "ScreenSpot-Pro"),
11
+ percent("pub:ALE", "Agents' Last Exam"),
12
+ percent("aa:MMMU", "MMMU-Pro"),
13
+ ],
14
+ coding: [
15
+ percent("aa:TB4", "Terminal-Bench 4.0"),
16
+ percent("dswe:Pass@1", "DeepSWE"),
17
+ percent("fc:Main", "FrontierCode"),
18
+ percent("aa:TB21", "Terminal-Bench 2.1"),
19
+ ],
20
+ code_review: [
21
+ percent("fc:Main", "FrontierCode"),
22
+ percent("aa:TB4", "Terminal-Bench 4.0"),
23
+ percent("pub:XGym", "ExploitGym"),
24
+ percent("pub:SECPro", "SEC-Bench Pro"),
25
+ ],
26
+ codebase_lookup: [
27
+ percent("aa:TB4", "Terminal-Bench 4.0"),
28
+ percent("aa:tau2", "τ²-Bench"),
29
+ percent("aa:IF", "IFBench"),
30
+ ],
31
+ research: [
32
+ percent("aa:HLE", "Humanity's Last Exam"),
33
+ percent("pub:BComp", "BrowseComp"),
34
+ percent("aa:GPQA", "GPQA Diamond"),
35
+ percent("aa:LCR", "AA-LCR"),
36
+ ],
37
+ business_workflow: [
38
+ percent("aa:Auto", "AutomationBench-AA"),
39
+ percent("pub:ABench", "AutomationBench"),
40
+ percent("aa:tau2", "τ²-Bench"),
41
+ percent("aa:Ent", "EnterpriseOps-Gym"),
42
+ ],
43
+ math_science: [
44
+ percent("pub:FMT4", "FrontierMath Tier 4"),
45
+ percent("pub:TBSci", "Terminal-Bench-Science"),
46
+ percent("aa:Crit", "CritPt"),
47
+ percent("aa:Sci", "SciCode"),
48
+ ],
49
+ writing: [
50
+ percent("aa:IF", "IFBench"),
51
+ points("aa:Gn", "GDPval"),
52
+ points("aa:Brief", "AA-Briefcase"),
53
+ percent("aa:LCR", "AA-LCR"),
54
+ ],
55
+ };
56
+ /** When speed matters, a fast route edges out its standard route for the model's single slot. */
57
+ const FAST_ROUTE_BONUS = 0.02;
58
+ /** A standing is stated only when enough eligible models share the measurement. */
59
+ const MIN_RANKED_MODELS = 4;
60
+ function sectionKind(intro) {
61
+ const heading = intro.find((line) => line.startsWith("## ")) ?? "";
62
+ if (/DeepSWE/u.test(heading))
63
+ return "dswe";
64
+ if (/FrontierCode/u.test(heading))
65
+ return "fc";
66
+ if (/Published/u.test(heading))
67
+ return "pub";
68
+ return "aa";
69
+ }
70
+ const cells = (line) => line
71
+ .split("|")
72
+ .slice(1, -1)
73
+ .map((cell) => cell.trim());
74
+ const nameWords = (text) => new Set(text.match(/\p{Lu}[\p{L}]{2,}/gu) ?? []);
75
+ /**
76
+ * The parts of a published result's setting that apply to this row: a clause
77
+ * naming other models (for example "Fable values are Mythos" on a GPT row) is a
78
+ * footnote for them and is dropped.
79
+ */
80
+ function ownSetting(setting, rowModel, modelWords) {
81
+ const own = nameWords(rowModel);
82
+ return setting
83
+ .split(";")
84
+ .map((clause) => clause.trim())
85
+ .filter((clause) => {
86
+ const named = [...nameWords(clause)].filter((word) => modelWords.has(word));
87
+ return named.length === 0 || named.some((word) => own.has(word));
88
+ })
89
+ .join(", ");
90
+ }
91
+ /** Parenthetical measurement setting in an Artificial Analysis model name, for example "Max Effort". */
92
+ function nameCondition(name) {
93
+ const setting = /\(([^)]+)\)\s*$/u.exec(name ?? "")?.[1];
94
+ return setting && /^(?:minimal|low|medium|high|xhigh|max)$/u.test(setting) ? `${setting} effort` : setting;
95
+ }
96
+ /**
97
+ * Best value per metric across every evals row describing the model, with the
98
+ * conditions it was measured under, plus the model's newest release date.
99
+ */
100
+ function measure(catalog, model) {
101
+ const kinds = catalog.sections.map((section) => sectionKind(section.intro));
102
+ const headers = catalog.sections.map((section) => cells(section.intro.find((line) => line.startsWith("| slug |")) ?? ""));
103
+ const values = new Map();
104
+ const conditions = new Map();
105
+ const modelColumn = headers.map((header) => header.indexOf("Model"));
106
+ const modelWords = catalog.sections.map((_, section) => {
107
+ const words = new Set();
108
+ for (const row of catalog.rows)
109
+ if (row.section === section)
110
+ for (const word of nameWords(cells(row.line)[modelColumn[section]] ?? ""))
111
+ words.add(word);
112
+ return words;
113
+ });
114
+ let released;
115
+ const record = (key, raw, condition) => {
116
+ const value = Number.parseFloat(raw ?? "");
117
+ if (!Number.isFinite(value) || value <= (values.get(key) ?? Number.NEGATIVE_INFINITY))
118
+ return;
119
+ values.set(key, value);
120
+ if (condition)
121
+ conditions.set(key, condition);
122
+ else
123
+ conditions.delete(key);
124
+ };
125
+ for (const row of candidateEvidenceRows(catalog, model)) {
126
+ const kind = kinds[row.section];
127
+ const header = headers[row.section];
128
+ const rowCells = cells(row.line);
129
+ const column = (name) => (header.includes(name) ? rowCells[header.indexOf(name)] : undefined);
130
+ if (kind === "pub") {
131
+ const reporter = column("Source");
132
+ const setting = ownSetting(column("Setting") ?? "", column("Model") ?? "", modelWords[row.section]);
133
+ const condition = [setting, reporter ? `reported by ${reporter}` : undefined].filter(Boolean).join(", ");
134
+ // Each reporter's results form their own cohort: a vendor harness and an
135
+ // official leaderboard are not ranked against each other.
136
+ record(`pub:${column("Benchmark")}@${reporter ?? ""}`, column("Score"), condition);
137
+ }
138
+ else {
139
+ const effort = column("Effort");
140
+ const condition = effort ? `${effort} effort` : nameCondition(column("Model"));
141
+ for (const [index, name] of header.entries())
142
+ if (index > 1 && name !== "Effort" && name !== "Release date")
143
+ record(`${kind}:${name}`, rowCells[index], condition);
144
+ }
145
+ if (row.releaseDate && (!released || row.releaseDate > released))
146
+ released = row.releaseDate;
147
+ }
148
+ return { values, conditions, ...(released ? { released } : {}) };
149
+ }
150
+ /** Value keys measuring `metric`: the column itself, or one per reporter for published results. */
151
+ const cohortKeys = (values, metric) => [...values.keys()].filter((key) => key === metric.key || key.startsWith(`${metric.key}@`));
152
+ const baseKey = (candidate) => modelEvidenceTokens(candidate.fastRouteOf ?? candidate.model).join("-");
153
+ const blended = (candidate) => (3 * candidate.cost.input + candidate.cost.output) / 4;
154
+ /**
155
+ * Rank every eligible model for the task in code. Quality is the model's
156
+ * standing on the benchmarks for this kind of work (overall intelligence when it
157
+ * has none), weighed against price by how demanding the task is, with a small
158
+ * preference for newer releases.
159
+ */
160
+ export function rankCandidates(catalog, candidates, needs) {
161
+ const measured = candidates.map((candidate) => ({
162
+ candidate,
163
+ base: baseKey(candidate),
164
+ ...measure(catalog, candidate.model),
165
+ }));
166
+ // One observation per base model: provider copies and fast routes of one model
167
+ // neither move other models' standings nor count toward the minimum.
168
+ const rankOf = (key, value) => {
169
+ const byBase = new Map();
170
+ for (const entry of measured) {
171
+ const observed = entry.values.get(key);
172
+ if (observed !== undefined)
173
+ byBase.set(entry.base, Math.max(byBase.get(entry.base) ?? observed, observed));
174
+ }
175
+ if (byBase.size < MIN_RANKED_MODELS)
176
+ return undefined;
177
+ return [...byBase.values()].filter((other) => other < value).length / (byBase.size - 1);
178
+ };
179
+ const standingOf = (values, metrics) => {
180
+ const ranks = metrics
181
+ .flatMap((metric) => cohortKeys(values, metric))
182
+ .map((key) => rankOf(key, values.get(key)))
183
+ .filter((rank) => rank !== undefined);
184
+ return ranks.length ? ranks.reduce((a, b) => a + b, 0) / ranks.length : undefined;
185
+ };
186
+ const logPrices = measured
187
+ .map((entry) => blended(entry.candidate))
188
+ .filter((price) => price > 0)
189
+ .map(Math.log);
190
+ const [low, high] = [Math.min(...logPrices), Math.max(...logPrices)];
191
+ const newest = measured
192
+ .map((entry) => entry.released ?? "")
193
+ .sort()
194
+ .at(-1);
195
+ const demand = taskDemand(needs);
196
+ const qualityWeight = 0.25 + 0.65 * demand;
197
+ const priceWeight = 0.65 - 0.65 * demand;
198
+ return measured
199
+ .map(({ candidate, base, values, conditions, released }) => {
200
+ const workStanding = standingOf(values, WORK_METRICS[needs.work]);
201
+ const overallStanding = standingOf(values, [OVERALL]);
202
+ const quality = workStanding ?? (overallStanding !== undefined ? 0.8 * overallStanding : 0.2);
203
+ const price = blended(candidate);
204
+ const cheapness = price > 0 && high > low ? 1 - (Math.log(price) - low) / (high - low) : 1;
205
+ const ageDays = released && newest ? (Date.parse(newest) - Date.parse(released)) / 86_400_000 : 365;
206
+ const recency = 1 - Math.min(1, ageDays / 365);
207
+ return {
208
+ ...candidate,
209
+ baseKey: base,
210
+ score: qualityWeight * quality +
211
+ priceWeight * cheapness +
212
+ 0.1 * recency +
213
+ (needs.latencySensitive && candidate.fastRouteOf ? FAST_ROUTE_BONUS : 0),
214
+ values,
215
+ conditions,
216
+ ...(released ? { released } : {}),
217
+ ...(workStanding !== undefined ? { workStanding } : {}),
218
+ ...(overallStanding !== undefined ? { overallStanding } : {}),
219
+ };
220
+ })
221
+ .sort((a, b) => b.score - a.score ||
222
+ Number(a.fastRouteOf !== undefined) - Number(b.fastRouteOf !== undefined) ||
223
+ a.model.localeCompare(b.model));
224
+ }
225
+ /** The best `size` candidates with at most one per base model. */
226
+ export function distinctTop(ranked, size) {
227
+ const seen = new Set();
228
+ const top = [];
229
+ for (const candidate of ranked) {
230
+ if (seen.has(candidate.baseKey))
231
+ continue;
232
+ seen.add(candidate.baseKey);
233
+ top.push(candidate);
234
+ if (top.length === size)
235
+ break;
236
+ }
237
+ return top;
238
+ }
239
+ function standingLabel(fraction) {
240
+ if (fraction >= 0.9)
241
+ return "top 10%";
242
+ if (fraction >= 0.75)
243
+ return "top quarter";
244
+ if (fraction >= 0.5)
245
+ return "above median";
246
+ if (fraction >= 0.25)
247
+ return "below median";
248
+ return "bottom quarter";
249
+ }
250
+ const money = (value) => `$${Number(value.toPrecision(3))}`;
251
+ /**
252
+ * One shortlisted option described with its own evidence, so the router compares
253
+ * options directly: release date, price tier, image input, and results for this
254
+ * kind of work and overall, with standings relative to every eligible model.
255
+ */
256
+ export function describeOption(option, needs, eligible) {
257
+ const prices = eligible.map(blended).sort((a, b) => a - b);
258
+ const position = prices.filter((other) => other < blended(option)).length / Math.max(1, prices.length - 1);
259
+ const tier = position < 1 / 3 ? "low" : position < 2 / 3 ? "mid" : "high";
260
+ const newest = eligible
261
+ .map((candidate) => candidate.released ?? "")
262
+ .sort()
263
+ .at(-1);
264
+ const quote = (metrics, standing) => {
265
+ const present = metrics
266
+ .map((metric) => {
267
+ const keys = cohortKeys(option.values, metric);
268
+ const best = keys.sort((a, b) => option.values.get(b) - option.values.get(a))[0];
269
+ return best === undefined ? undefined : { metric, key: best };
270
+ })
271
+ .filter((entry) => entry !== undefined)
272
+ .slice(0, 2);
273
+ if (present.length === 0)
274
+ return "no published results";
275
+ const results = present
276
+ .map(({ metric, key }) => {
277
+ const condition = option.conditions.get(key);
278
+ return `${metric.label} ${option.values.get(key)}${metric.unit}${condition ? ` measured with ${condition}` : ""}`;
279
+ })
280
+ .join("; ");
281
+ return `${standing === undefined ? "measured" : standingLabel(standing)} (${results})`;
282
+ };
283
+ let released = "unknown";
284
+ if (option.released) {
285
+ const months = newest ? Math.round((Date.parse(newest) - Date.parse(option.released)) / (30.44 * 86_400_000)) : 0;
286
+ released =
287
+ months <= 1
288
+ ? `${option.released}, among the newest`
289
+ : `${option.released}, ${months} months older than the newest`;
290
+ }
291
+ const fastBase = option.fastRouteOf
292
+ ? eligible.find((candidate) => candidate.model === option.fastRouteOf)
293
+ : undefined;
294
+ return JSON.stringify({
295
+ model: option.name,
296
+ id: option.model,
297
+ released,
298
+ price: `${tier}: ${money(option.cost.input)} / ${money(option.cost.output)} per million tokens`,
299
+ reads_images: option.input.includes("image"),
300
+ [needs.work]: quote(WORK_METRICS[needs.work], option.workStanding),
301
+ overall: quote([OVERALL], option.overallStanding),
302
+ ...(option.fastRouteOf
303
+ ? {
304
+ route: `faster route of ${fastBase?.name ?? option.fastRouteOf} with the same results; billed above the listed prices`,
305
+ }
306
+ : {}),
307
+ });
308
+ }
309
+ //# sourceMappingURL=model-routing-candidates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-routing-candidates.js","sourceRoot":"","sources":["../../src/core/model-routing-candidates.ts"],"names":[],"mappings":"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","sourcesContent":["import { candidateEvidenceRows, type EvalsCatalog, modelEvidenceTokens } from \"./model-routing-evals.js\";\nimport { type ResolvedTaskNeeds, taskDemand, type WorkKind } from \"./model-routing-needs.js\";\n\n/** What ranking needs to know about one eligible model. */\nexport interface CandidateModel {\n\t/** `provider/id`, as used in router selections. */\n\treadonly model: string;\n\treadonly name: string;\n\treadonly cost: { readonly input: number; readonly output: number };\n\treadonly input: readonly string[];\n\t/** `provider/id` of the base model when this entry is its derived fast route (`fastRoute` metadata). */\n\treadonly fastRouteOf?: string;\n}\n\ninterface Metric {\n\treadonly key: string;\n\treadonly label: string;\n\treadonly unit: \"%\" | \"\";\n}\n\nconst percent = (key: string, label: string): Metric => ({ key, label, unit: \"%\" });\nconst points = (key: string, label: string): Metric => ({ key, label, unit: \"\" });\n\nconst OVERALL: Metric = points(\"aa:idx\", \"AA Intelligence Index\");\n\n/** evals.md columns that measure each kind of work, in the order results are quoted. */\nconst WORK_METRICS: Record<WorkKind, readonly Metric[]> = {\n\tcomputer_use: [\n\t\tpercent(\"pub:OSW2\", \"OSWorld 2.0\"),\n\t\tpercent(\"pub:SSP\", \"ScreenSpot-Pro\"),\n\t\tpercent(\"pub:ALE\", \"Agents' Last Exam\"),\n\t\tpercent(\"aa:MMMU\", \"MMMU-Pro\"),\n\t],\n\tcoding: [\n\t\tpercent(\"aa:TB4\", \"Terminal-Bench 4.0\"),\n\t\tpercent(\"dswe:Pass@1\", \"DeepSWE\"),\n\t\tpercent(\"fc:Main\", \"FrontierCode\"),\n\t\tpercent(\"aa:TB21\", \"Terminal-Bench 2.1\"),\n\t],\n\tcode_review: [\n\t\tpercent(\"fc:Main\", \"FrontierCode\"),\n\t\tpercent(\"aa:TB4\", \"Terminal-Bench 4.0\"),\n\t\tpercent(\"pub:XGym\", \"ExploitGym\"),\n\t\tpercent(\"pub:SECPro\", \"SEC-Bench Pro\"),\n\t],\n\tcodebase_lookup: [\n\t\tpercent(\"aa:TB4\", \"Terminal-Bench 4.0\"),\n\t\tpercent(\"aa:tau2\", \"τ²-Bench\"),\n\t\tpercent(\"aa:IF\", \"IFBench\"),\n\t],\n\tresearch: [\n\t\tpercent(\"aa:HLE\", \"Humanity's Last Exam\"),\n\t\tpercent(\"pub:BComp\", \"BrowseComp\"),\n\t\tpercent(\"aa:GPQA\", \"GPQA Diamond\"),\n\t\tpercent(\"aa:LCR\", \"AA-LCR\"),\n\t],\n\tbusiness_workflow: [\n\t\tpercent(\"aa:Auto\", \"AutomationBench-AA\"),\n\t\tpercent(\"pub:ABench\", \"AutomationBench\"),\n\t\tpercent(\"aa:tau2\", \"τ²-Bench\"),\n\t\tpercent(\"aa:Ent\", \"EnterpriseOps-Gym\"),\n\t],\n\tmath_science: [\n\t\tpercent(\"pub:FMT4\", \"FrontierMath Tier 4\"),\n\t\tpercent(\"pub:TBSci\", \"Terminal-Bench-Science\"),\n\t\tpercent(\"aa:Crit\", \"CritPt\"),\n\t\tpercent(\"aa:Sci\", \"SciCode\"),\n\t],\n\twriting: [\n\t\tpercent(\"aa:IF\", \"IFBench\"),\n\t\tpoints(\"aa:Gn\", \"GDPval\"),\n\t\tpoints(\"aa:Brief\", \"AA-Briefcase\"),\n\t\tpercent(\"aa:LCR\", \"AA-LCR\"),\n\t],\n};\n\n/** When speed matters, a fast route edges out its standard route for the model's single slot. */\nconst FAST_ROUTE_BONUS = 0.02;\n\n/** A standing is stated only when enough eligible models share the measurement. */\nconst MIN_RANKED_MODELS = 4;\n\nexport interface RankedCandidate extends CandidateModel {\n\t/** Identity shared by one model's providers and its derived fast route, which collapse onto it. */\n\treadonly baseKey: string;\n\treadonly score: number;\n\treadonly values: ReadonlyMap<string, number>;\n\t/** How each quoted value was measured, for example its effort, harness or reporter. */\n\treadonly conditions: ReadonlyMap<string, string>;\n\treadonly released?: string;\n\treadonly workStanding?: number;\n\treadonly overallStanding?: number;\n}\n\nfunction sectionKind(intro: readonly string[]): \"aa\" | \"dswe\" | \"fc\" | \"pub\" {\n\tconst heading = intro.find((line) => line.startsWith(\"## \")) ?? \"\";\n\tif (/DeepSWE/u.test(heading)) return \"dswe\";\n\tif (/FrontierCode/u.test(heading)) return \"fc\";\n\tif (/Published/u.test(heading)) return \"pub\";\n\treturn \"aa\";\n}\n\nconst cells = (line: string) =>\n\tline\n\t\t.split(\"|\")\n\t\t.slice(1, -1)\n\t\t.map((cell) => cell.trim());\n\nconst nameWords = (text: string) => new Set(text.match(/\\p{Lu}[\\p{L}]{2,}/gu) ?? []);\n\n/**\n * The parts of a published result's setting that apply to this row: a clause\n * naming other models (for example \"Fable values are Mythos\" on a GPT row) is a\n * footnote for them and is dropped.\n */\nfunction ownSetting(setting: string, rowModel: string, modelWords: ReadonlySet<string>): string {\n\tconst own = nameWords(rowModel);\n\treturn setting\n\t\t.split(\";\")\n\t\t.map((clause) => clause.trim())\n\t\t.filter((clause) => {\n\t\t\tconst named = [...nameWords(clause)].filter((word) => modelWords.has(word));\n\t\t\treturn named.length === 0 || named.some((word) => own.has(word));\n\t\t})\n\t\t.join(\", \");\n}\n\n/** Parenthetical measurement setting in an Artificial Analysis model name, for example \"Max Effort\". */\nfunction nameCondition(name: string | undefined): string | undefined {\n\tconst setting = /\\(([^)]+)\\)\\s*$/u.exec(name ?? \"\")?.[1];\n\treturn setting && /^(?:minimal|low|medium|high|xhigh|max)$/u.test(setting) ? `${setting} effort` : setting;\n}\n\n/**\n * Best value per metric across every evals row describing the model, with the\n * conditions it was measured under, plus the model's newest release date.\n */\nfunction measure(\n\tcatalog: EvalsCatalog,\n\tmodel: string,\n): { values: Map<string, number>; conditions: Map<string, string>; released?: string } {\n\tconst kinds = catalog.sections.map((section) => sectionKind(section.intro));\n\tconst headers = catalog.sections.map((section) =>\n\t\tcells(section.intro.find((line) => line.startsWith(\"| slug |\")) ?? \"\"),\n\t);\n\tconst values = new Map<string, number>();\n\tconst conditions = new Map<string, string>();\n\tconst modelColumn = headers.map((header) => header.indexOf(\"Model\"));\n\tconst modelWords = catalog.sections.map((_, section) => {\n\t\tconst words = new Set<string>();\n\t\tfor (const row of catalog.rows)\n\t\t\tif (row.section === section)\n\t\t\t\tfor (const word of nameWords(cells(row.line)[modelColumn[section]!] ?? \"\")) words.add(word);\n\t\treturn words;\n\t});\n\tlet released: string | undefined;\n\tconst record = (key: string, raw: string | undefined, condition: string | undefined) => {\n\t\tconst value = Number.parseFloat(raw ?? \"\");\n\t\tif (!Number.isFinite(value) || value <= (values.get(key) ?? Number.NEGATIVE_INFINITY)) return;\n\t\tvalues.set(key, value);\n\t\tif (condition) conditions.set(key, condition);\n\t\telse conditions.delete(key);\n\t};\n\tfor (const row of candidateEvidenceRows(catalog, model)) {\n\t\tconst kind = kinds[row.section]!;\n\t\tconst header = headers[row.section]!;\n\t\tconst rowCells = cells(row.line);\n\t\tconst column = (name: string) => (header.includes(name) ? rowCells[header.indexOf(name)] : undefined);\n\t\tif (kind === \"pub\") {\n\t\t\tconst reporter = column(\"Source\");\n\t\t\tconst setting = ownSetting(column(\"Setting\") ?? \"\", column(\"Model\") ?? \"\", modelWords[row.section]!);\n\t\t\tconst condition = [setting, reporter ? `reported by ${reporter}` : undefined].filter(Boolean).join(\", \");\n\t\t\t// Each reporter's results form their own cohort: a vendor harness and an\n\t\t\t// official leaderboard are not ranked against each other.\n\t\t\trecord(`pub:${column(\"Benchmark\")}@${reporter ?? \"\"}`, column(\"Score\"), condition);\n\t\t} else {\n\t\t\tconst effort = column(\"Effort\");\n\t\t\tconst condition = effort ? `${effort} effort` : nameCondition(column(\"Model\"));\n\t\t\tfor (const [index, name] of header.entries())\n\t\t\t\tif (index > 1 && name !== \"Effort\" && name !== \"Release date\")\n\t\t\t\t\trecord(`${kind}:${name}`, rowCells[index], condition);\n\t\t}\n\t\tif (row.releaseDate && (!released || row.releaseDate > released)) released = row.releaseDate;\n\t}\n\treturn { values, conditions, ...(released ? { released } : {}) };\n}\n\n/** Value keys measuring `metric`: the column itself, or one per reporter for published results. */\nconst cohortKeys = (values: ReadonlyMap<string, number>, metric: Metric) =>\n\t[...values.keys()].filter((key) => key === metric.key || key.startsWith(`${metric.key}@`));\n\nconst baseKey = (candidate: CandidateModel) => modelEvidenceTokens(candidate.fastRouteOf ?? candidate.model).join(\"-\");\n\nconst blended = (candidate: CandidateModel) => (3 * candidate.cost.input + candidate.cost.output) / 4;\n\n/**\n * Rank every eligible model for the task in code. Quality is the model's\n * standing on the benchmarks for this kind of work (overall intelligence when it\n * has none), weighed against price by how demanding the task is, with a small\n * preference for newer releases.\n */\nexport function rankCandidates(\n\tcatalog: EvalsCatalog,\n\tcandidates: readonly CandidateModel[],\n\tneeds: ResolvedTaskNeeds,\n): RankedCandidate[] {\n\tconst measured = candidates.map((candidate) => ({\n\t\tcandidate,\n\t\tbase: baseKey(candidate),\n\t\t...measure(catalog, candidate.model),\n\t}));\n\t// One observation per base model: provider copies and fast routes of one model\n\t// neither move other models' standings nor count toward the minimum.\n\tconst rankOf = (key: string, value: number): number | undefined => {\n\t\tconst byBase = new Map<string, number>();\n\t\tfor (const entry of measured) {\n\t\t\tconst observed = entry.values.get(key);\n\t\t\tif (observed !== undefined) byBase.set(entry.base, Math.max(byBase.get(entry.base) ?? observed, observed));\n\t\t}\n\t\tif (byBase.size < MIN_RANKED_MODELS) return undefined;\n\t\treturn [...byBase.values()].filter((other) => other < value).length / (byBase.size - 1);\n\t};\n\tconst standingOf = (values: ReadonlyMap<string, number>, metrics: readonly Metric[]) => {\n\t\tconst ranks = metrics\n\t\t\t.flatMap((metric) => cohortKeys(values, metric))\n\t\t\t.map((key) => rankOf(key, values.get(key)!))\n\t\t\t.filter((rank): rank is number => rank !== undefined);\n\t\treturn ranks.length ? ranks.reduce((a, b) => a + b, 0) / ranks.length : undefined;\n\t};\n\tconst logPrices = measured\n\t\t.map((entry) => blended(entry.candidate))\n\t\t.filter((price) => price > 0)\n\t\t.map(Math.log);\n\tconst [low, high] = [Math.min(...logPrices), Math.max(...logPrices)];\n\tconst newest = measured\n\t\t.map((entry) => entry.released ?? \"\")\n\t\t.sort()\n\t\t.at(-1);\n\tconst demand = taskDemand(needs);\n\tconst qualityWeight = 0.25 + 0.65 * demand;\n\tconst priceWeight = 0.65 - 0.65 * demand;\n\n\treturn measured\n\t\t.map(({ candidate, base, values, conditions, released }) => {\n\t\t\tconst workStanding = standingOf(values, WORK_METRICS[needs.work]);\n\t\t\tconst overallStanding = standingOf(values, [OVERALL]);\n\t\t\tconst quality = workStanding ?? (overallStanding !== undefined ? 0.8 * overallStanding : 0.2);\n\t\t\tconst price = blended(candidate);\n\t\t\tconst cheapness = price > 0 && high > low ? 1 - (Math.log(price) - low) / (high - low) : 1;\n\t\t\tconst ageDays = released && newest ? (Date.parse(newest) - Date.parse(released)) / 86_400_000 : 365;\n\t\t\tconst recency = 1 - Math.min(1, ageDays / 365);\n\t\t\treturn {\n\t\t\t\t...candidate,\n\t\t\t\tbaseKey: base,\n\t\t\t\tscore:\n\t\t\t\t\tqualityWeight * quality +\n\t\t\t\t\tpriceWeight * cheapness +\n\t\t\t\t\t0.1 * recency +\n\t\t\t\t\t(needs.latencySensitive && candidate.fastRouteOf ? FAST_ROUTE_BONUS : 0),\n\t\t\t\tvalues,\n\t\t\t\tconditions,\n\t\t\t\t...(released ? { released } : {}),\n\t\t\t\t...(workStanding !== undefined ? { workStanding } : {}),\n\t\t\t\t...(overallStanding !== undefined ? { overallStanding } : {}),\n\t\t\t};\n\t\t})\n\t\t.sort(\n\t\t\t(a, b) =>\n\t\t\t\tb.score - a.score ||\n\t\t\t\tNumber(a.fastRouteOf !== undefined) - Number(b.fastRouteOf !== undefined) ||\n\t\t\t\ta.model.localeCompare(b.model),\n\t\t);\n}\n\n/** The best `size` candidates with at most one per base model. */\nexport function distinctTop(ranked: readonly RankedCandidate[], size: number): RankedCandidate[] {\n\tconst seen = new Set<string>();\n\tconst top: RankedCandidate[] = [];\n\tfor (const candidate of ranked) {\n\t\tif (seen.has(candidate.baseKey)) continue;\n\t\tseen.add(candidate.baseKey);\n\t\ttop.push(candidate);\n\t\tif (top.length === size) break;\n\t}\n\treturn top;\n}\n\nfunction standingLabel(fraction: number): string {\n\tif (fraction >= 0.9) return \"top 10%\";\n\tif (fraction >= 0.75) return \"top quarter\";\n\tif (fraction >= 0.5) return \"above median\";\n\tif (fraction >= 0.25) return \"below median\";\n\treturn \"bottom quarter\";\n}\n\nconst money = (value: number) => `$${Number(value.toPrecision(3))}`;\n\n/**\n * One shortlisted option described with its own evidence, so the router compares\n * options directly: release date, price tier, image input, and results for this\n * kind of work and overall, with standings relative to every eligible model.\n */\nexport function describeOption(\n\toption: RankedCandidate,\n\tneeds: ResolvedTaskNeeds,\n\teligible: readonly RankedCandidate[],\n): string {\n\tconst prices = eligible.map(blended).sort((a, b) => a - b);\n\tconst position = prices.filter((other) => other < blended(option)).length / Math.max(1, prices.length - 1);\n\tconst tier = position < 1 / 3 ? \"low\" : position < 2 / 3 ? \"mid\" : \"high\";\n\tconst newest = eligible\n\t\t.map((candidate) => candidate.released ?? \"\")\n\t\t.sort()\n\t\t.at(-1);\n\tconst quote = (metrics: readonly Metric[], standing: number | undefined) => {\n\t\tconst present = metrics\n\t\t\t.map((metric) => {\n\t\t\t\tconst keys = cohortKeys(option.values, metric);\n\t\t\t\tconst best = keys.sort((a, b) => option.values.get(b)! - option.values.get(a)!)[0];\n\t\t\t\treturn best === undefined ? undefined : { metric, key: best };\n\t\t\t})\n\t\t\t.filter((entry) => entry !== undefined)\n\t\t\t.slice(0, 2);\n\t\tif (present.length === 0) return \"no published results\";\n\t\tconst results = present\n\t\t\t.map(({ metric, key }) => {\n\t\t\t\tconst condition = option.conditions.get(key);\n\t\t\t\treturn `${metric.label} ${option.values.get(key)}${metric.unit}${condition ? ` measured with ${condition}` : \"\"}`;\n\t\t\t})\n\t\t\t.join(\"; \");\n\t\treturn `${standing === undefined ? \"measured\" : standingLabel(standing)} (${results})`;\n\t};\n\tlet released = \"unknown\";\n\tif (option.released) {\n\t\tconst months = newest ? Math.round((Date.parse(newest) - Date.parse(option.released)) / (30.44 * 86_400_000)) : 0;\n\t\treleased =\n\t\t\tmonths <= 1\n\t\t\t\t? `${option.released}, among the newest`\n\t\t\t\t: `${option.released}, ${months} months older than the newest`;\n\t}\n\tconst fastBase = option.fastRouteOf\n\t\t? eligible.find((candidate) => candidate.model === option.fastRouteOf)\n\t\t: undefined;\n\treturn JSON.stringify({\n\t\tmodel: option.name,\n\t\tid: option.model,\n\t\treleased,\n\t\tprice: `${tier}: ${money(option.cost.input)} / ${money(option.cost.output)} per million tokens`,\n\t\treads_images: option.input.includes(\"image\"),\n\t\t[needs.work]: quote(WORK_METRICS[needs.work], option.workStanding),\n\t\toverall: quote([OVERALL], option.overallStanding),\n\t\t...(option.fastRouteOf\n\t\t\t? {\n\t\t\t\t\troute: `faster route of ${fastBase?.name ?? option.fastRouteOf} with the same results; billed above the listed prices`,\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n}\n"]}
@@ -2,6 +2,8 @@ import type { Api, Model } from "@bastani/pi-ai";
2
2
  import { type Static, Type } from "typebox";
3
3
  export declare const ModelConstraintsSchema: Type.TObject<{
4
4
  allowedModels: Type.TOptional<Type.TArray<Type.TString>>;
5
+ allowedProviders: Type.TOptional<Type.TArray<Type.TString>>;
6
+ excludedProviders: Type.TOptional<Type.TArray<Type.TString>>;
5
7
  maxInputCost: Type.TOptional<Type.TNumber>;
6
8
  maxOutputCost: Type.TOptional<Type.TNumber>;
7
9
  minContextWindow: Type.TOptional<Type.TNumber>;
@@ -19,6 +21,8 @@ export type ModelRouterOutput = {
19
21
  readonly effort: string | null;
20
22
  }[];
21
23
  };
24
+ /** Whether a constraint sets its own provider list. */
25
+ export declare function setsProviders(constraints: ModelConstraints | undefined): boolean;
22
26
  /** Every applicable declaration must hold; a caller never widens a definition restriction. */
23
27
  export declare function eligiblePair(model: Model<Api>, pair: ModelRouterOutput, constraints: readonly ModelConstraints[]): boolean;
24
28
  //# sourceMappingURL=model-routing-constraints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-routing-constraints.d.ts","sourceRoot":"","sources":["../../src/core/model-routing-constraints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,eAAO,MAAM,sBAAsB;;;;;;;EAyClC,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAErE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAWlF;AACD,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CAC3F,CAAC;AACF,8FAA8F;AAC9F,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE,iBAAiB,EACvB,WAAW,EAAE,SAAS,gBAAgB,EAAE,GACtC,OAAO,CAYT"}
1
+ {"version":3,"file":"model-routing-constraints.d.ts","sourceRoot":"","sources":["../../src/core/model-routing-constraints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,eAAO,MAAM,sBAAsB;;;;;;;;;EAsDlC,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAErE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAWlF;AACD,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CAC3F,CAAC;AACF,uDAAuD;AACvD,wBAAgB,aAAa,CAAC,WAAW,EAAE,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAEhF;AAED,8FAA8F;AAC9F,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE,iBAAiB,EACvB,WAAW,EAAE,SAAS,gBAAgB,EAAE,GACtC,OAAO,CAcT"}
@@ -2,7 +2,13 @@ import { Type } from "typebox";
2
2
  import { Compile } from "typebox/compile";
3
3
  export const ModelConstraintsSchema = Type.Object({
4
4
  allowedModels: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
5
- description: "Exact provider/model IDs; omitted uses the full available catalog.",
5
+ description: "Exact provider/model IDs; omitted uses the full available catalog. With model 'auto', these are the candidates the router chooses between (as many as fit one routing request, roughly 100), so list the models that suit the task. Prefer the user's subscription models (for example ChatGPT/Codex, GitHub Copilot, a Claude subscription, or a coding or token plan) over pay-per-token API models, unless the user asked for API models or has no subscription models.",
6
+ })),
7
+ allowedProviders: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
8
+ description: 'Provider IDs whose models may be used, for example ["openai-codex", "github-copilot"]. Setting this or excludedProviders replaces the user\'s modelRouting provider settings for this call, so set them only when the user asks to use or avoid specific providers.',
9
+ })),
10
+ excludedProviders: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
11
+ description: 'Provider IDs whose models are never used, for example ["openrouter"]. Setting this or allowedProviders replaces the user\'s modelRouting provider settings for this call, so set them only when the user asks.',
6
12
  })),
7
13
  maxInputCost: Type.Optional(Type.Number({
8
14
  minimum: 0,
@@ -32,9 +38,15 @@ export function parseModelConstraints(value) {
32
38
  }
33
39
  return value;
34
40
  }
41
+ /** Whether a constraint sets its own provider list. */
42
+ export function setsProviders(constraints) {
43
+ return constraints?.allowedProviders !== undefined || constraints?.excludedProviders !== undefined;
44
+ }
35
45
  /** Every applicable declaration must hold; a caller never widens a definition restriction. */
36
46
  export function eligiblePair(model, pair, constraints) {
37
47
  return constraints.every((c) => (c.allowedModels === undefined || c.allowedModels.includes(pair.model)) &&
48
+ (c.allowedProviders === undefined || c.allowedProviders.includes(model.provider)) &&
49
+ !c.excludedProviders?.includes(model.provider) &&
38
50
  (c.allowedEfforts === undefined || c.allowedEfforts.some((e) => e === pair.effort)) &&
39
51
  (c.maxInputCost === undefined ||
40
52
  [model.cost, ...(model.cost.tiers ?? [])].every((rate) => rate.input <= c.maxInputCost)) &&