@desplega.ai/agent-swarm 1.158.0 → 1.160.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
  3. package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
  4. package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
  5. package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
  6. package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
  7. package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
  8. package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
  9. package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
  10. package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
  11. package/dist/boot-seeds-gsetbs5y.js +28 -0
  12. package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
  13. package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
  14. package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
  15. package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
  16. package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
  17. package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
  18. package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
  19. package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
  20. package/dist/cli-0x01kwrd.js +491 -0
  21. package/dist/cli-0xqde53b.js +176 -0
  22. package/dist/cli-10nhj6xq.js +8355 -0
  23. package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
  24. package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
  25. package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
  26. package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
  27. package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
  28. package/dist/cli-3qhyh31j.js +166 -0
  29. package/dist/cli-447dt1h3.js +3828 -0
  30. package/dist/cli-4derpgyk.js +115 -0
  31. package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
  32. package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
  33. package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
  34. package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
  35. package/dist/cli-741yb0xx.js +1027 -0
  36. package/dist/cli-74h9hscv.js +69 -0
  37. package/dist/cli-7cxw8b60.js +14910 -0
  38. package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
  39. package/dist/cli-7kyk9jr3.js +22 -0
  40. package/dist/cli-89s4ngw3.js +183 -0
  41. package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
  42. package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
  43. package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
  44. package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
  45. package/dist/cli-br0qdrnp.js +2150 -0
  46. package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
  47. package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
  48. package/dist/cli-cpvsaqsw.js +333 -0
  49. package/dist/cli-d5czme6m.js +17805 -0
  50. package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
  51. package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
  52. package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
  53. package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
  54. package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
  55. package/dist/cli-gt4hxb8p.js +99 -0
  56. package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
  57. package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
  58. package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
  59. package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
  60. package/dist/cli-kmcpfwn2.js +333856 -0
  61. package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
  62. package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
  63. package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
  64. package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
  65. package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
  66. package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
  67. package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
  68. package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
  69. package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
  70. package/dist/cli-rb9m6rpe.js +4980 -0
  71. package/dist/cli-rykfmgwg.js +102 -0
  72. package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
  73. package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
  74. package/dist/cli-tfky2838.js +756 -0
  75. package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
  76. package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
  77. package/dist/cli-trc24wk2.js +143 -0
  78. package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
  79. package/dist/cli-v7fn5gms.js +1425 -0
  80. package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
  81. package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
  82. package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
  83. package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
  84. package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
  85. package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
  86. package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
  87. package/dist/cli-zpep9q5e.js +491 -0
  88. package/dist/cli.js +41 -32
  89. package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
  90. package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
  91. package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
  92. package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
  93. package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
  94. package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
  95. package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
  96. package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
  97. package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
  98. package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
  99. package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
  100. package/dist/execute-6e7qeyk4.js +1017 -0
  101. package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
  102. package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
  103. package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
  104. package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
  105. package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
  106. package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
  107. package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
  108. package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
  109. package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
  110. package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
  111. package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
  112. package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
  113. package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
  114. package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
  115. package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
  116. package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
  117. package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
  118. package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
  119. package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
  120. package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
  121. package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
  122. package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
  123. package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
  124. package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
  125. package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
  126. package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
  127. package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
  128. package/dist/pricing-refresh-wx0tp7cb.js +39 -0
  129. package/dist/quickjs-r1pq2107.wasm +0 -0
  130. package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
  131. package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
  132. package/dist/runtime-zyssgse0.js +24 -0
  133. package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
  134. package/dist/typesafe-system-one-2ef30pec.js +27 -0
  135. package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
  136. package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
  137. package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
  138. package/openapi.json +1314 -91
  139. package/package.json +12 -11
  140. package/src/be/db/agents.ts +20 -0
  141. package/src/be/db/api-keys.ts +70 -0
  142. package/src/be/db/tasks/human-free.ts +442 -0
  143. package/src/be/db/tasks/read.ts +56 -1
  144. package/src/be/db/tasks/write.ts +107 -11
  145. package/src/be/db.ts +274 -188
  146. package/src/be/harness-model-support.ts +182 -0
  147. package/src/be/human-free-drain.ts +67 -0
  148. package/src/be/memory/providers/sqlite-store.ts +51 -15
  149. package/src/be/migrations/182_task_human_free_flag.sql +63 -0
  150. package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
  151. package/src/be/migrations/184_model_catalog.sql +120 -0
  152. package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
  153. package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
  154. package/src/be/model-catalog-store.ts +644 -0
  155. package/src/be/model-tier-keys.ts +46 -0
  156. package/src/be/model-tier-resolution.ts +534 -0
  157. package/src/be/model-validation.ts +188 -0
  158. package/src/be/models-catalog.ts +61 -7
  159. package/src/be/modelsdev-cache.json +82 -0
  160. package/src/be/modelsdev-cache.ts +2 -0
  161. package/src/be/pricing-refresh.ts +154 -12
  162. package/src/be/scripts/typecheck.ts +15 -0
  163. package/src/be/seed/runner.ts +18 -12
  164. package/src/be/seed/types.ts +1 -0
  165. package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
  166. package/src/be/swarm-config-guard.ts +8 -0
  167. package/src/cli.tsx +10 -0
  168. package/src/commands/claude-managed-setup.ts +3 -1
  169. package/src/commands/codex-login.ts +67 -0
  170. package/src/commands/credential-outcome-report.ts +191 -0
  171. package/src/commands/rate-limit-outcome.ts +34 -4
  172. package/src/commands/runner.ts +357 -186
  173. package/src/commands/seat-mismatch-report.ts +46 -0
  174. package/src/extensions/apply-task-create.ts +27 -1
  175. package/src/extensions/contract-types.generated.ts +1 -1
  176. package/src/heartbeat/heartbeat.ts +79 -17
  177. package/src/heartbeat/templates.ts +2 -2
  178. package/src/http/agents.ts +62 -1
  179. package/src/http/api-keys.ts +140 -2
  180. package/src/http/codex-oauth-keep-warm.ts +3 -5
  181. package/src/http/index.ts +8 -0
  182. package/src/http/memory.ts +12 -5
  183. package/src/http/models-catalog.ts +357 -8
  184. package/src/http/poll.ts +54 -3
  185. package/src/http/schedules.ts +51 -6
  186. package/src/http/script-runs.ts +12 -0
  187. package/src/http/session-data.ts +2 -5
  188. package/src/http/stats.ts +6 -8
  189. package/src/http/status.ts +15 -1
  190. package/src/http/tasks.ts +90 -7
  191. package/src/http/usage-cache.ts +56 -15
  192. package/src/http/workflows.ts +46 -8
  193. package/src/mcp-client/http-client.ts +5 -0
  194. package/src/memory/recall-query.ts +74 -0
  195. package/src/prompts/base-prompt.ts +15 -4
  196. package/src/prompts/session-templates.ts +23 -1
  197. package/src/providers/acp-adapter.ts +1 -0
  198. package/src/providers/claude-adapter.ts +14 -5
  199. package/src/providers/claude-managed-adapter.ts +1 -0
  200. package/src/providers/claude-managed-models.ts +47 -161
  201. package/src/providers/claude-sdk-session.ts +3 -1
  202. package/src/providers/codex-adapter.ts +14 -14
  203. package/src/providers/codex-models.ts +65 -198
  204. package/src/providers/devin-adapter.ts +1 -0
  205. package/src/providers/dsh-adapter.ts +2 -1
  206. package/src/providers/harness-version.ts +83 -7
  207. package/src/providers/opencode-adapter.ts +53 -1
  208. package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
  209. package/src/providers/pi-codemode-runtime.ts +17 -0
  210. package/src/providers/pi-mono-adapter.ts +361 -83
  211. package/src/providers/pi-mono-extension.ts +16 -1
  212. package/src/providers/reasoning-effort.ts +44 -140
  213. package/src/providers/types.ts +8 -0
  214. package/src/rbac/legacy-policy.ts +43 -0
  215. package/src/rbac/permissions.ts +15 -0
  216. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  217. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  218. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  219. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  220. package/src/server.ts +6 -0
  221. package/src/slack/assistant.ts +13 -0
  222. package/src/slack/message-text.ts +56 -2
  223. package/src/slack/render-v2.ts +87 -37
  224. package/src/slack/session-status.ts +541 -0
  225. package/src/slack/thread-buffer.ts +10 -2
  226. package/src/tasks/sibling-awareness.ts +3 -2
  227. package/src/telemetry.ts +5 -4
  228. package/src/templates.d.ts +6 -0
  229. package/src/tests/agents-list-model-display.test.ts +4 -6
  230. package/src/tests/api-key-auth-failure-route.test.ts +142 -0
  231. package/src/tests/api-key-tracking.test.ts +368 -1
  232. package/src/tests/base-prompt.test.ts +43 -2
  233. package/src/tests/claude-adapter.test.ts +68 -0
  234. package/src/tests/claude-managed-adapter.test.ts +12 -18
  235. package/src/tests/codex-adapter.test.ts +2 -1
  236. package/src/tests/codex-auth-failure.test.ts +52 -0
  237. package/src/tests/codex-gpt6-release.test.ts +66 -5
  238. package/src/tests/codex-login.test.ts +116 -0
  239. package/src/tests/context-window.test.ts +7 -5
  240. package/src/tests/credential-exhaustion-policy.test.ts +118 -3
  241. package/src/tests/credential-outcome-report.test.ts +171 -0
  242. package/src/tests/credential-status-api.test.ts +103 -2
  243. package/src/tests/db-extraction-contract.test.ts +1 -0
  244. package/src/tests/db-task-read-contract.test.ts +10 -1
  245. package/src/tests/db-task-write-contract.test.ts +535 -2
  246. package/src/tests/docs-index-footprint.test.js +3 -3
  247. package/src/tests/dokploy-deploy.test.ts +315 -0
  248. package/src/tests/dsh-adapter.test.ts +1 -1
  249. package/src/tests/explicit-model-validation.test.ts +583 -0
  250. package/src/tests/extensions-pre-task.test.ts +73 -0
  251. package/src/tests/fetch-resolved-env.test.ts +46 -0
  252. package/src/tests/hang-watchdog-worker.ts +47 -0
  253. package/src/tests/hang-watchdog.test.ts +45 -0
  254. package/src/tests/hang-watchdog.ts +30 -0
  255. package/src/tests/harness-model-guard.test.ts +123 -0
  256. package/src/tests/harness-model-support.test.ts +374 -0
  257. package/src/tests/harness-version.test.ts +70 -3
  258. package/src/tests/heartbeat-checklist-config.test.ts +71 -0
  259. package/src/tests/heartbeat-checklist.test.ts +4 -2
  260. package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
  261. package/src/tests/http-task-write-ownership.test.ts +172 -0
  262. package/src/tests/human-free-flag.test.ts +279 -0
  263. package/src/tests/human-free-oracle.ts +57 -0
  264. package/src/tests/human-free-reclassify.test.ts +669 -0
  265. package/src/tests/memory-fts-populate.test.ts +139 -0
  266. package/src/tests/memory-http-recall-gating.test.ts +125 -1
  267. package/src/tests/migration-046-budgets.test.ts +3 -3
  268. package/src/tests/model-catalog-migration.test.ts +134 -0
  269. package/src/tests/model-catalog-table.test.ts +249 -0
  270. package/src/tests/model-catalog-write-access.test.ts +387 -0
  271. package/src/tests/model-rate-limit-windows.test.ts +19 -0
  272. package/src/tests/model-tier-resolution.test.ts +611 -0
  273. package/src/tests/models-catalog.test.ts +1 -1
  274. package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
  275. package/src/tests/opencode-adapter.test.ts +157 -2
  276. package/src/tests/package-publish.test.ts +137 -36
  277. package/src/tests/pi-codemode.test.ts +246 -0
  278. package/src/tests/pi-mono-adapter.test.ts +3 -0
  279. package/src/tests/pi-native-mcp.test.ts +193 -0
  280. package/src/tests/pi-tool-exposure.test.ts +374 -0
  281. package/src/tests/preload.ts +3 -0
  282. package/src/tests/pricing-routes.test.ts +2 -2
  283. package/src/tests/prompt-template-session.test.ts +5 -3
  284. package/src/tests/rate-limit-event.test.ts +65 -0
  285. package/src/tests/rate-limit-outcome.test.ts +90 -0
  286. package/src/tests/rbac-engine.test.ts +77 -3
  287. package/src/tests/reasoning-effort.test.ts +109 -0
  288. package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
  289. package/src/tests/runner-key-completion-outcome.test.ts +112 -0
  290. package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
  291. package/src/tests/runner-registration-retry.test.ts +149 -0
  292. package/src/tests/runtime-model-catalog.test.ts +86 -0
  293. package/src/tests/script-connections.test.ts +9 -0
  294. package/src/tests/seat-mismatch-report.test.ts +85 -0
  295. package/src/tests/seed-scripts.test.ts +138 -0
  296. package/src/tests/seed.test.ts +25 -0
  297. package/src/tests/session-costs.test.ts +14 -11
  298. package/src/tests/slack-message-text.test.ts +101 -0
  299. package/src/tests/slack-render-v2.test.ts +96 -0
  300. package/src/tests/slack-session-status.test.ts +626 -0
  301. package/src/tests/slack-thread-buffer-context.test.ts +93 -0
  302. package/src/tests/status.test.ts +29 -0
  303. package/src/tests/steering-promotion.test.ts +51 -0
  304. package/src/tests/store-progress-ownership.test.ts +136 -0
  305. package/src/tests/subscription-plans.test.ts +28 -0
  306. package/src/tests/task-cascade-fail.test.ts +148 -2
  307. package/src/tests/task-citations.test.ts +3 -2
  308. package/src/tests/tool-annotations.test.ts +1 -1
  309. package/src/tests/usage-cache.test.ts +166 -0
  310. package/src/tests/workflow-agent-task.test.ts +30 -0
  311. package/src/tests/workflow-executors.test.ts +5 -2
  312. package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
  313. package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
  314. package/src/tests/workflow-system-one-decision.test.ts +2063 -0
  315. package/src/tests/workflow-triggers-v2.test.ts +320 -0
  316. package/src/tools/model-catalog/index.ts +137 -0
  317. package/src/tools/schedules/create-schedule.ts +17 -2
  318. package/src/tools/schedules/patch-schedule.ts +31 -1
  319. package/src/tools/schedules/update-schedule.ts +31 -1
  320. package/src/tools/send-task.ts +18 -1
  321. package/src/tools/store-progress.ts +49 -4
  322. package/src/tools/task-action.ts +14 -1
  323. package/src/tools/tool-config.ts +3 -1
  324. package/src/tools/workflows/create-workflow.ts +17 -4
  325. package/src/tools/workflows/patch-workflow-node.ts +17 -7
  326. package/src/tools/workflows/patch-workflow.ts +9 -2
  327. package/src/tools/workflows/update-workflow.ts +17 -4
  328. package/src/types.ts +41 -1
  329. package/src/utils/codex-auth-failure.ts +34 -0
  330. package/src/utils/context-window.ts +47 -53
  331. package/src/utils/credentials.ts +72 -30
  332. package/src/utils/error-tracker.ts +80 -0
  333. package/src/utils/harness-cli-version.ts +115 -0
  334. package/src/utils/harness-model-error.ts +33 -0
  335. package/src/utils/model-rate-limit-windows.ts +12 -0
  336. package/src/utils/runtime-model-catalog.ts +152 -0
  337. package/src/utils/spawn-model-guard.ts +43 -0
  338. package/src/utils/subscription-plans.ts +22 -0
  339. package/src/workflows/approval-resolution.ts +39 -0
  340. package/src/workflows/definition.ts +7 -0
  341. package/src/workflows/engine.ts +69 -1
  342. package/src/workflows/executors/agent-task.ts +16 -6
  343. package/src/workflows/executors/base.ts +53 -0
  344. package/src/workflows/executors/human-in-the-loop.ts +8 -8
  345. package/src/workflows/executors/index.ts +1 -0
  346. package/src/workflows/executors/registry.ts +2 -0
  347. package/src/workflows/executors/system-one-decision.ts +1232 -0
  348. package/src/workflows/executors/system-one-providers.ts +301 -0
  349. package/src/workflows/executors/workflow-llm.ts +13 -1
  350. package/src/workflows/model-validation.ts +45 -0
  351. package/src/workflows/patch-definition.ts +5 -0
  352. package/src/workflows/readiness.ts +86 -0
  353. package/src/workflows/recovery.ts +12 -12
  354. package/src/workflows/resume.ts +23 -9
  355. package/src/workflows/triggers.ts +85 -0
  356. package/templates/schedules/daily-blocker-digest/content.md +4 -5
  357. package/templates/skills/agent-browser/SKILL.md +6 -5
  358. package/templates/skills/agent-browser/content.md +6 -5
  359. package/templates/skills/heartbeat-runbook/config.json +1 -1
  360. package/templates/skills/heartbeat-runbook/content.md +2 -2
  361. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  362. package/templates/skills/swarm-scripts/content.md +1 -1
  363. package/templates/skills/workflow-iterate/content.md +82 -1
  364. package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
  365. package/templates/workflows/pr-review-status-sweep/content.md +2 -0
  366. package/dist/boot-seeds-s3q01xj3.js +0 -26
  367. package/dist/claude-sdk-session-t442qz6f.js +0 -39108
  368. package/dist/cli-0xjkj1j7.js +0 -61
  369. package/dist/cli-20cj37vt.js +0 -335561
  370. package/dist/cli-2djtr51b.js +0 -48
  371. package/dist/cli-65hjmev5.js +0 -1141
  372. package/dist/cli-aw1jwp1r.js +0 -14075
  373. package/dist/cli-h967nb6r.js +0 -6603
  374. package/dist/cli-vapyk8sw.js +0 -20
  375. package/dist/cli-ws6rqycm.js +0 -247
  376. package/dist/pricing-refresh-v1cbr9te.js +0 -27
  377. package/src/providers/modelsdev-reasoning.json +0 -6453
  378. package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
@@ -7,31 +7,32 @@ import {
7
7
  } from "./cli-dgnj0zcc.js";
8
8
  import {
9
9
  SIMILARITY_THRESHOLD,
10
+ isUnknownModelError,
10
11
  memoryRelevance,
11
12
  writeSkillsToFilesystem
12
- } from "./cli-q67y4wzm.js";
13
+ } from "./cli-phsaj4xq.js";
13
14
  import {
14
15
  Anthropic
15
16
  } from "./cli-j490egb5.js";
17
+ import {
18
+ checkHeartbeatChecklist,
19
+ runHeartbeatSweep,
20
+ stopHeartbeat
21
+ } from "./cli-a8dvhzrt.js";
16
22
  import {
17
23
  isClaudeBridgeEffective,
18
24
  resolveClaudeTransport
19
25
  } from "./cli-eree7rnv.js";
20
26
  import {
21
27
  MAX_RATE_LIMIT_RESET_MS
22
- } from "./cli-npssxgaz.js";
28
+ } from "./cli-2pdaysab.js";
23
29
  import {
24
30
  reasoningCapability
25
- } from "./cli-h967nb6r.js";
31
+ } from "./cli-4derpgyk.js";
26
32
  import {
27
33
  ensureAgentFsCredentialsForAgent,
28
34
  inviteEmailToSharedOrg
29
- } from "./cli-xhaeg2nc.js";
30
- import {
31
- checkHeartbeatChecklist,
32
- runHeartbeatSweep,
33
- stopHeartbeat
34
- } from "./cli-rqz8qbw7.js";
35
+ } from "./cli-7e398j1h.js";
35
36
  import {
36
37
  AGENT_MAX_TASKS_CONFIG_KEY,
37
38
  ALL_CAPABILITIES,
@@ -58,6 +59,7 @@ import {
58
59
  TriggerSchemaError,
59
60
  WebhookError,
60
61
  activateVersion,
62
+ agentRanModel,
61
63
  agentWithCapacity,
62
64
  allowedCredentialRedirect,
63
65
  applyRating,
@@ -80,7 +82,6 @@ import {
80
82
  checkOutputSchemaShape,
81
83
  clearJiraMetadata,
82
84
  closeRooms,
83
- createApprovalFollowUpTask,
84
85
  createEvent,
85
86
  createEventsBatch,
86
87
  createResumeFollowUp,
@@ -103,10 +104,13 @@ import {
103
104
  executeRawLlm,
104
105
  executeReadOnlyQuery,
105
106
  expandCandidatesWithGraph,
107
+ explicitModelError,
108
+ explicitModelErrorForAgent,
106
109
  extractAndVerifyCookie,
107
110
  findUserById,
108
111
  fingerprintApiKey,
109
112
  flushAuditBuffer,
113
+ getAgentHarnessCliVersion,
110
114
  getAutomationSetupStates,
111
115
  getEnabledCapabilities,
112
116
  getEventCountsFiltered,
@@ -154,6 +158,7 @@ import {
154
158
  handlePullRequestReview,
155
159
  handleWebhookTrigger,
156
160
  handleWorkflowRun,
161
+ harnessModelErrorFor,
157
162
  hasCapability,
158
163
  httpServerSemconvAttributes,
159
164
  hydrateOAuthAppFromPreset,
@@ -185,6 +190,7 @@ import {
185
190
  listExtensionRuns,
186
191
  listExtensionVersions,
187
192
  listExtensions,
193
+ listHarnessModelSupport,
188
194
  listOAuthPresetIds,
189
195
  listOAuthPresets,
190
196
  listRuntimeInstancesForAgent,
@@ -201,13 +207,18 @@ import {
201
207
  mintToken,
202
208
  parseBody,
203
209
  parseCookieHeader,
210
+ parseModelTierOverridesHeader,
204
211
  parseQueryParams,
205
212
  parseSkillContent,
206
213
  patchWorkflowDefinition,
214
+ poolTaskRunsOnHarness,
207
215
  preflightAutomation,
216
+ previewModelTiers,
208
217
  readScriptSdkJsonResponse,
209
218
  reconcileAgentMaxTasksPolicy,
210
219
  reconcileAgentStatusFromRuntimes,
220
+ recordClaimModelResolution,
221
+ recordHarnessModelSupport,
211
222
  recordIdentityEvent,
212
223
  recordMemoryAccesses,
213
224
  recordRetrievals,
@@ -244,11 +255,14 @@ import {
244
255
  runtimeInstanceHeader,
245
256
  runtimeStaleThresholdMinutes,
246
257
  safeRequestUrlForLog,
258
+ sanitizeModelTierOverrides,
247
259
  scheduleIntegrationsReload,
248
260
  scopedResourceScopeIdSchema,
249
261
  sendKapsoReaction,
250
262
  sendTaskHandler,
251
263
  sendTaskOutputSchema,
264
+ setAgentHarnessCliVersion,
265
+ setAgentModelTierOverrides,
252
266
  setCorsHeaders,
253
267
  setExtensionLoopbackBaseUrl,
254
268
  setRuntimeCredentialReady,
@@ -266,6 +280,7 @@ import {
266
280
  stopAuditGc,
267
281
  stopAuditWriter,
268
282
  stopExtensionRuntime,
283
+ stripSiblingBlock,
269
284
  sweepRooms,
270
285
  taskActionHandler,
271
286
  taskActionInputSchema,
@@ -287,32 +302,26 @@ import {
287
302
  verifyHmacSignature,
288
303
  verifyWebhookSignature,
289
304
  warnIfCorsAllowsAnyOrigin,
290
- wireHttpSpanLifecycle
291
- } from "./cli-ftfvggzx.js";
305
+ wireHttpSpanLifecycle,
306
+ workflowModelErrors,
307
+ workflowSaveWarnings
308
+ } from "./cli-9hsgwz4w.js";
292
309
  import"./cli-0z2v4nhw.js";
293
310
  import {
294
311
  REFERENCES_SOURCE_MAX_LENGTH,
295
312
  sanitizeReferencesSource
296
- } from "./cli-tt9k8r35.js";
297
- import {
298
- CLIENT_ID,
299
- MAX_CODEX_OAUTH_SLOT,
300
- _fetchHolder,
301
- codexOAuthKeyForSlot,
302
- deriveCodexKeySuffix,
303
- exchangeAuthorizationCode as exchangeAuthorizationCode2,
304
- getAccountId,
305
- getValidCodexOAuth,
306
- loadAllCodexOAuthSlots
307
- } from "./cli-vhjwh6cz.js";
313
+ } from "./cli-cpvsaqsw.js";
308
314
  import {
309
315
  isMultiRuntimeEnabled
310
316
  } from "./cli-re8z5p8p.js";
311
- import"./cli-3dpj7atn.js";
312
- import"./cli-aw1jwp1r.js";
317
+ import {
318
+ FilesError,
319
+ getFileStorageProvider,
320
+ normalizeFilesError
321
+ } from "./cli-jsp14b6c.js";
313
322
  import {
314
323
  getUserGrant
315
- } from "./cli-aky8tctm.js";
324
+ } from "./cli-tzx2ke1v.js";
316
325
  import {
317
326
  LEGACY_RULES,
318
327
  can,
@@ -320,13 +329,16 @@ import {
320
329
  decideToolAdmission,
321
330
  isRbacEnabled,
322
331
  setAuditSink
323
- } from "./cli-g8djp6qe.js";
332
+ } from "./cli-tmqt7dpj.js";
324
333
  import {
325
- getModelsCatalog
326
- } from "./cli-ws6rqycm.js";
334
+ deleteModelCatalogOverlay,
335
+ loadModelsCatalog,
336
+ requestModelCatalogRefresh,
337
+ upsertModelCatalogOverlay
338
+ } from "./cli-tfky2838.js";
327
339
  import {
328
340
  normalizeModelKey
329
- } from "./cli-wscdvcqz.js";
341
+ } from "./cli-vctdqs5h.js";
330
342
  import {
331
343
  ConnectionAuthInputSchema,
332
344
  MAX_SCRIPT_WALL_CLOCK_MS,
@@ -347,6 +359,7 @@ import {
347
359
  connectionAuthInputFromFlat,
348
360
  connectionAuthSummary,
349
361
  consumeMcpOAuthPending,
362
+ createApprovalFollowUpTask,
350
363
  createScriptApi,
351
364
  definitionNodeIds,
352
365
  deleteMcpOAuthToken,
@@ -418,7 +431,7 @@ import {
418
431
  upsertScriptByName,
419
432
  upsertScriptConnection,
420
433
  validateDefinition
421
- } from "./cli-fgqxwrpv.js";
434
+ } from "./cli-tpq83z89.js";
422
435
  import"./cli-epan13p1.js";
423
436
  import {
424
437
  detachedProcessGroup,
@@ -430,9 +443,25 @@ import {
430
443
  import {
431
444
  getApiKey
432
445
  } from "./cli-f14fvzag.js";
446
+ import"./cli-12tszpk9.js";
447
+ import {
448
+ CLIENT_ID,
449
+ MAX_CODEX_OAUTH_SLOT,
450
+ _fetchHolder,
451
+ codexOAuthKeyForSlot,
452
+ deriveCodexKeySuffix,
453
+ exchangeAuthorizationCode as exchangeAuthorizationCode2,
454
+ getAccountId,
455
+ getValidCodexOAuth,
456
+ loadAllCodexOAuthSlots
457
+ } from "./cli-ygwm91nt.js";
458
+ import"./cli-3dpj7atn.js";
459
+ import"./cli-10nhj6xq.js";
460
+ import"./cli-rb9m6rpe.js";
461
+ import"./cli-rykfmgwg.js";
433
462
  import {
434
463
  searchScripts
435
- } from "./cli-987hg0aa.js";
464
+ } from "./cli-0jwe9034.js";
436
465
  import {
437
466
  acquireOAuthRefreshLock,
438
467
  buildAuthorizationUrl,
@@ -456,29 +485,23 @@ import {
456
485
  updateAuthorizationIdentity,
457
486
  updateOAuthAppById,
458
487
  upsertAuthorization
459
- } from "./cli-53sz8gkz.js";
460
- import {
461
- FilesError,
462
- getFileStorageProvider,
463
- normalizeFilesError
464
- } from "./cli-jsp14b6c.js";
488
+ } from "./cli-6cs6wzxt.js";
489
+ import"./cli-fad8m16k.js";
465
490
  import {
466
491
  CANDIDATE_SET_MULTIPLIER,
467
492
  EMBEDDING_DIMENSIONS,
493
+ OpenAI,
468
494
  getEmbeddingProvider,
469
495
  getMemoryStore,
470
496
  init_constants as init_constants2,
497
+ init_openai,
471
498
  init_reranker,
472
499
  rerank
473
- } from "./cli-65hjmev5.js";
474
- import"./cli-xberxa1r.js";
500
+ } from "./cli-jz4w45qt.js";
501
+ import"./cli-25fcq4b4.js";
475
502
  import"./cli-bsakbbkm.js";
476
- import"./cli-fad8m16k.js";
503
+ import"./cli-trc24wk2.js";
477
504
  import"./cli-51tf7ac3.js";
478
- import {
479
- OpenAI,
480
- init_openai
481
- } from "./cli-aehm1rbq.js";
482
505
  import {
483
506
  TaskCitationSchema,
484
507
  ensure,
@@ -498,12 +521,13 @@ import {
498
521
  withRemoteContext,
499
522
  withSpan,
500
523
  withSpanContext
501
- } from "./cli-j57qkrpq.js";
524
+ } from "./cli-azhgzetg.js";
502
525
  import"./cli-q51yprfq.js";
503
526
  import"./cli-3er6gcsn.js";
504
527
  import"./cli-2658f6at.js";
505
528
  import"./cli-yatxqynm.js";
506
529
  import {
530
+ CODEX_AUTH_WATCH_NAMESPACE,
507
531
  CredentialBindingSchema,
508
532
  DB_RETENTION_TUNING_BOUNDS,
509
533
  EXTENSION_AGENT_ROLE,
@@ -529,6 +553,7 @@ import {
529
553
  cleanupStaleSessions,
530
554
  clearKeyRateLimit,
531
555
  closeDb,
556
+ codexAuthBenchMarkerKey,
532
557
  completeTask,
533
558
  computeContentHash,
534
559
  countActiveScriptRuns,
@@ -576,6 +601,7 @@ import {
576
601
  deleteTaskAttachment,
577
602
  deleteUser,
578
603
  deleteWorkflow,
604
+ drainHumanFreeReclassifyQueue,
579
605
  emitBuiltInIntegrationConnectedOnce,
580
606
  emitIntegrationConnected,
581
607
  emitMcpServerConnectedTelemetry,
@@ -589,6 +615,7 @@ import {
589
615
  getAgentHarnessProviders,
590
616
  getAgentMcpServers,
591
617
  getAgentSkills,
618
+ getAgentStatusCounts,
592
619
  getAgentWithTasks,
593
620
  getAllAgents,
594
621
  getAllAgentsWithTasks,
@@ -677,7 +704,6 @@ import {
677
704
  getTaskSteeringFieldsForTasks,
678
705
  getTasksCount,
679
706
  getUnassignedTaskIdsForAgent,
680
- getUsageDataVersion,
681
707
  getUserById,
682
708
  getWorkflow,
683
709
  getWorkflowRun,
@@ -692,6 +718,7 @@ import {
692
718
  incrementPageViewCount,
693
719
  initTelemetry,
694
720
  init_asset_key_audit,
721
+ init_codex_auth_failure,
695
722
  init_context_key,
696
723
  init_credential_broker,
697
724
  init_crypto,
@@ -699,6 +726,7 @@ import {
699
726
  init_db,
700
727
  init_default_drift,
701
728
  init_heartbeat_expiry,
729
+ init_human_free,
702
730
  init_request_auth_context,
703
731
  init_steering,
704
732
  init_swarm_config_guard,
@@ -714,6 +742,7 @@ import {
714
742
  isInternalConfigKey,
715
743
  isReservedConfigKey,
716
744
  isSteeringEnabled as isSteeringEnabled2,
745
+ isTelemetryEnabled,
717
746
  listAgentsWithCredStatusByProvider,
718
747
  listAllMetrics,
719
748
  listAllPages,
@@ -748,7 +777,9 @@ import {
748
777
  promoteDraftTask,
749
778
  recordBudgetRefusalNotification,
750
779
  recordInlineScriptRun,
780
+ recordKeyAuthFailure,
751
781
  recordKeyRateLimitWindows,
782
+ recordKeySeatMismatch,
752
783
  recordKeyUsage,
753
784
  requestSteering,
754
785
  reservedKeyError,
@@ -764,7 +795,9 @@ import {
764
795
  setApiKeyName,
765
796
  setApiKeyPlan,
766
797
  setFavorite,
798
+ setHumanFreeQueueListener,
767
799
  setRequestAuth,
800
+ settleSupersededTaskDependents,
768
801
  startTask,
769
802
  supersedeTask,
770
803
  sweepExpiredKv,
@@ -808,7 +841,8 @@ import {
808
841
  upsertSwarmConfig,
809
842
  validateConfigValue,
810
843
  withFavoriteFlags
811
- } from "./cli-47m6dkd3.js";
844
+ } from "./cli-qydf22qq.js";
845
+ import"./cli-3qhyh31j.js";
812
846
  import {
813
847
  ActiveSessionSchema,
814
848
  AgentAcpStatusSchema,
@@ -858,6 +892,7 @@ import {
858
892
  KvKeySchema,
859
893
  KvNamespaceSchema,
860
894
  KvValueTypeSchema,
895
+ MODEL_TIERS,
861
896
  McpAuthMethodSchema,
862
897
  McpServerSchema,
863
898
  McpServerWithInstallInfoSchema,
@@ -934,12 +969,16 @@ import {
934
969
  isSafeBundlePath,
935
970
  isTerminalTaskStatus,
936
971
  splitLegacyModelAlias
937
- } from "./cli-4198qc9v.js";
972
+ } from "./cli-ktmyrtpn.js";
938
973
  import {
939
974
  IDENTITY_FIELD_BUDGETS,
940
975
  IdentityFieldBudgetError,
941
976
  init_identity_field_budget
942
- } from "./cli-3gmcwfyx.js";
977
+ } from "./cli-r1mxd1xh.js";
978
+ import {
979
+ getSlackConfiguration,
980
+ init_config
981
+ } from "./cli-n7h1kqpf.js";
943
982
  import {
944
983
  getAllTemplateDefinitions,
945
984
  getTemplateDefinition,
@@ -950,8 +989,7 @@ import {
950
989
  interpolate,
951
990
  isSteeringEnabled,
952
991
  resolveTemplate
953
- } from "./cli-ggm92wcn.js";
954
- import"./cli-19jenss3.js";
992
+ } from "./cli-ptr8h7kp.js";
955
993
  import {
956
994
  MAX_PROFILE_FILE_LENGTH,
957
995
  getAppUrl,
@@ -960,26 +998,27 @@ import {
960
998
  getPublicMcpBaseUrl,
961
999
  init_constants
962
1000
  } from "./cli-dv6cdjs2.js";
963
- import {
964
- getSlackConfiguration,
965
- init_config
966
- } from "./cli-n7h1kqpf.js";
967
- import {
968
- MODEL_SCOPED_WINDOWS,
969
- activeModelBlocks,
970
- init_model_rate_limit_windows
971
- } from "./cli-de1396j2.js";
972
1001
  import {
973
1002
  SUBSCRIPTION_PLANS,
974
1003
  SUBSCRIPTION_PLANS_CHECKED_AT,
975
1004
  init_subscription_plans,
976
1005
  isSubscriptionPlanId
977
- } from "./cli-cqt19wg6.js";
1006
+ } from "./cli-1a2j50m0.js";
1007
+ import"./cli-0wgxmwf6.js";
1008
+ import {
1009
+ MODEL_SCOPED_WINDOWS,
1010
+ activeModelBlocks,
1011
+ init_model_rate_limit_windows
1012
+ } from "./cli-ywybs5as.js";
978
1013
  import {
979
1014
  init_env_flag,
980
1015
  isEnvFlagEnabled,
981
1016
  parseEnvFlag
982
1017
  } from "./cli-ej6gbxfb.js";
1018
+ import {
1019
+ init_src,
1020
+ isAlias
1021
+ } from "./cli-kmcpfwn2.js";
983
1022
  import {
984
1023
  exports_zod,
985
1024
  init_zod
@@ -996,7 +1035,7 @@ import {
996
1035
  import {
997
1036
  init_package,
998
1037
  package_default
999
- } from "./cli-c07r9a2m.js";
1038
+ } from "./cli-0q3avq3s.js";
1000
1039
  import {
1001
1040
  init_secret_scrubber,
1002
1041
  registerVolatileSecret,
@@ -1005,20 +1044,20 @@ import {
1005
1044
  } from "./cli-r2ap2czm.js";
1006
1045
  import {
1007
1046
  bedrockProviderModule
1008
- } from "./cli-h38x0qhg.js";
1047
+ } from "./cli-et8m9xsv.js";
1009
1048
  import"./cli-yn0a417a.js";
1010
1049
  import"./cli-cgj4hc12.js";
1011
1050
  import"./cli-txgcknmy.js";
1012
1051
  import"./cli-6map995v.js";
1013
- import"./cli-k0g1sjzm.js";
1052
+ import"./cli-ybgv4kw2.js";
1014
1053
  import"./cli-y2apkfe2.js";
1015
- import"./cli-vapyk8sw.js";
1054
+ import"./cli-7kyk9jr3.js";
1016
1055
  import {
1017
1056
  setBedrockProviderModule
1018
- } from "./cli-5b6b62tz.js";
1057
+ } from "./cli-13hw4z91.js";
1019
1058
  import"./cli-btbzvq95.js";
1020
1059
  import"./cli-1m2e086m.js";
1021
- import"./cli-mcnhgnn1.js";
1060
+ import"./cli-ykk5jaax.js";
1022
1061
  import"./cli-bzr0ftht.js";
1023
1062
  import"./cli-bd957dgb.js";
1024
1063
  import {
@@ -1509,6 +1548,62 @@ async function stopDbRetention() {
1509
1548
  await retentionTickPromise;
1510
1549
  }
1511
1550
 
1551
+ // src/be/human-free-drain.ts
1552
+ init_human_free();
1553
+ var YIELD_MS2 = 25;
1554
+ var IDLE_INTERVAL_MS = 60000;
1555
+ var running = false;
1556
+ var idleTimer = null;
1557
+ var passTimer = null;
1558
+ function scheduleIdle() {
1559
+ if (!running)
1560
+ return;
1561
+ if (idleTimer)
1562
+ clearTimeout(idleTimer);
1563
+ idleTimer = setTimeout(() => schedulePass(0), IDLE_INTERVAL_MS);
1564
+ idleTimer.unref?.();
1565
+ }
1566
+ function schedulePass(delayMs) {
1567
+ if (!running || passTimer)
1568
+ return;
1569
+ passTimer = setTimeout(() => {
1570
+ passTimer = null;
1571
+ runPass();
1572
+ }, delayMs);
1573
+ passTimer.unref?.();
1574
+ }
1575
+ async function runPass() {
1576
+ if (!running)
1577
+ return;
1578
+ try {
1579
+ const { batches, remaining } = await drainHumanFreeReclassifyQueue({ maxBatches: 1 });
1580
+ if (batches > 0 && remaining > 0) {
1581
+ schedulePass(YIELD_MS2);
1582
+ return;
1583
+ }
1584
+ } catch (err) {
1585
+ console.error("[human-free-drain] batch failed, retrying later:", err instanceof Error ? err.message : String(err));
1586
+ }
1587
+ scheduleIdle();
1588
+ }
1589
+ function startHumanFreeDrain() {
1590
+ if (running)
1591
+ return;
1592
+ running = true;
1593
+ setHumanFreeQueueListener(() => schedulePass(0));
1594
+ schedulePass(0);
1595
+ }
1596
+ function stopHumanFreeDrain() {
1597
+ running = false;
1598
+ setHumanFreeQueueListener(undefined);
1599
+ if (idleTimer)
1600
+ clearTimeout(idleTimer);
1601
+ if (passTimer)
1602
+ clearTimeout(passTimer);
1603
+ idleTimer = null;
1604
+ passTimer = null;
1605
+ }
1606
+
1512
1607
  // src/be/scripts/retention.ts
1513
1608
  init_db();
1514
1609
  var SCRATCH_RETENTION_DAYS = 14;
@@ -3326,6 +3421,7 @@ async function handleActiveSessions(req, res, pathSegments, queryParams, myAgent
3326
3421
  }
3327
3422
 
3328
3423
  // src/http/agents.ts
3424
+ init_src();
3329
3425
  init_zod();
3330
3426
  init_db();
3331
3427
  init_telemetry();
@@ -3378,7 +3474,9 @@ var registerAgent = route({
3378
3474
  maxTasks: exports_external.number().int().optional(),
3379
3475
  provider: ProviderNameSchema.optional(),
3380
3476
  harness_provider: ProviderNameSchema.optional(),
3381
- runtimeInstanceId: exports_external.string().min(1).optional()
3477
+ runtimeInstanceId: exports_external.string().min(1).optional(),
3478
+ modelTierOverrides: exports_external.record(exports_external.string(), exports_external.record(exports_external.string(), exports_external.string())).optional(),
3479
+ harnessCliVersion: exports_external.string().max(64).optional()
3382
3480
  }),
3383
3481
  responses: {
3384
3482
  200: {
@@ -3458,7 +3556,7 @@ var updateAgentRuntimeRoute = route({
3458
3556
  path: "/api/agents/{id}/runtime",
3459
3557
  pattern: ["api", "agents", null, "runtime"],
3460
3558
  summary: "Update an agent's runtime harness and default model",
3461
- description: "Updates `agents.harness_provider` and agent-scoped runtime config. The settings apply to future provider sessions. For `model`, `reasoning_effort`, and `claude.transport`: omit the field to leave it unchanged, send `null` to clear the corresponding override, or send a value to set it.",
3559
+ description: "Updates `agents.harness_provider` and agent-scoped runtime config. The settings apply to future provider sessions. For `model`, `reasoning_effort`, and `claude.transport`: omit the field to leave it unchanged, send `null` to clear the corresponding override, or send a value to set it. A `model` the model catalog does not list is a 400 unless `allow_custom_model` is true. A `latest:` alias is not accepted here (aliases resolve for a task's model and for `MODEL_TIER_*` values); `reasoning_effort` must be one the harness and model support.",
3462
3560
  tags: ["Agents"],
3463
3561
  params: exports_external.object({ id: exports_external.string() }),
3464
3562
  query: exports_external.object({ repoId: exports_external.string().optional() }),
@@ -3771,6 +3869,13 @@ async function handleAgentRegister(req, res, pathSegments, myAgentId) {
3771
3869
  }
3772
3870
  if (parsed.body.harness_provider && parsed.body.harness_provider !== existingAgent.harnessProvider) {
3773
3871
  await setAgentHarnessProvider(existingAgent.id, parsed.body.harness_provider);
3872
+ const harness = parsed.body.harness_provider;
3873
+ const override = (await getSwarmConfigs({ scope: "agent", scopeId: agentId, key: "MODEL_OVERRIDE" }))[0]?.value;
3874
+ if (override && await harnessModelErrorFor(override, harness)) {
3875
+ getDbClient().afterCommit(() => {
3876
+ console.warn(`[agents] MODEL_OVERRIDE ${override} of agent ${agentId} does not run on its new ${harness} harness (was ${existingAgent.harnessProvider ?? "unset"}); update or clear it`);
3877
+ });
3878
+ }
3774
3879
  }
3775
3880
  await resetEmptyPollCount(existingAgent.id);
3776
3881
  if (multiRuntime && parsed.body.runtimeInstanceId) {
@@ -3809,6 +3914,12 @@ async function handleAgentRegister(req, res, pathSegments, myAgentId) {
3809
3914
  }
3810
3915
  return { agent, created: true };
3811
3916
  });
3917
+ if (parsed.body.harnessCliVersion !== undefined) {
3918
+ await setAgentHarnessCliVersion(agentId, parsed.body.harnessCliVersion.trim() || null);
3919
+ }
3920
+ if (parsed.body.modelTierOverrides) {
3921
+ await setAgentModelTierOverrides(agentId, sanitizeModelTierOverrides(parsed.body.modelTierOverrides));
3922
+ }
3812
3923
  telemetry.agent("registered", {
3813
3924
  role: parsed.body.role,
3814
3925
  capabilities: parsed.body.capabilities ?? [],
@@ -4114,6 +4225,21 @@ async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId)
4114
4225
  return true;
4115
4226
  }
4116
4227
  }
4228
+ if (typeof model === "string" && isAlias(model)) {
4229
+ jsonError(res, `A latest: alias cannot be an agent's default model ("${model}"). Set the alias on a task, or as a MODEL_TIER_<PROVIDER>_<TIER> value.`, 400);
4230
+ return true;
4231
+ }
4232
+ if (typeof model === "string") {
4233
+ const modelError = await explicitModelError({
4234
+ model,
4235
+ allowCustomModel: allow_custom_model,
4236
+ harnessProvider: harness_provider
4237
+ });
4238
+ if (modelError) {
4239
+ jsonError(res, modelError, 400);
4240
+ return true;
4241
+ }
4242
+ }
4117
4243
  let agent;
4118
4244
  try {
4119
4245
  agent = await getDbClient().transaction(async () => {
@@ -4373,22 +4499,50 @@ init_subscription_plans();
4373
4499
 
4374
4500
  // src/http/usage-cache.ts
4375
4501
  var USAGE_CACHE_TTL_MS = 30000;
4502
+ var USAGE_CACHE_MAX_STALE_MS = 120000;
4376
4503
  var MAX_ENTRIES = 100;
4377
4504
  var entries = new Map;
4378
- async function cachedUsageReport(key, load) {
4379
- const now = Date.now();
4505
+ var loading = new Map;
4506
+ var generation = 0;
4507
+ function load(key, loader) {
4508
+ const running2 = loading.get(key);
4509
+ if (running2)
4510
+ return running2;
4511
+ const startedIn = generation;
4512
+ const promise = Promise.resolve().then(loader).then((value) => {
4513
+ if (startedIn === generation) {
4514
+ entries.delete(key);
4515
+ if (entries.size >= MAX_ENTRIES)
4516
+ entries.delete(entries.keys().next().value);
4517
+ entries.set(key, { fetchedAt: Date.now(), value });
4518
+ }
4519
+ return value;
4520
+ }).finally(() => {
4521
+ if (loading.get(key) === promise)
4522
+ loading.delete(key);
4523
+ });
4524
+ loading.set(key, promise);
4525
+ return promise;
4526
+ }
4527
+ async function cachedUsageReport(key, loader) {
4380
4528
  const hit = entries.get(key);
4381
- if (hit && hit.expiresAt > now)
4382
- return hit.value;
4383
- const value = await load();
4384
- entries.delete(key);
4385
- if (entries.size >= MAX_ENTRIES)
4386
- entries.delete(entries.keys().next().value);
4387
- entries.set(key, { expiresAt: now + USAGE_CACHE_TTL_MS, value });
4388
- return value;
4529
+ if (hit) {
4530
+ const age = Date.now() - hit.fetchedAt;
4531
+ if (age < USAGE_CACHE_TTL_MS)
4532
+ return hit.value;
4533
+ if (age < USAGE_CACHE_MAX_STALE_MS) {
4534
+ load(key, loader).catch((error) => {
4535
+ console.error(`[usage-cache] background refresh failed for ${key.split(":")[0]}:`, error);
4536
+ });
4537
+ return hit.value;
4538
+ }
4539
+ }
4540
+ return load(key, loader);
4389
4541
  }
4390
4542
  function clearUsageCache() {
4543
+ generation++;
4391
4544
  entries.clear();
4545
+ loading.clear();
4392
4546
  }
4393
4547
 
4394
4548
  // src/http/api-keys.ts
@@ -4439,6 +4593,38 @@ var reportRateLimit = route({
4439
4593
  },
4440
4594
  auth: { apiKey: true }
4441
4595
  });
4596
+ var reportAuthFailure = route({
4597
+ method: "post",
4598
+ path: "/api/keys/report-auth-failure",
4599
+ pattern: ["api", "keys", "report-auth-failure"],
4600
+ summary: "Record an auth failure for a pooled key; bench it after 2 in a row",
4601
+ tags: ["API Keys"],
4602
+ body: exports_external.object({
4603
+ keyType: exports_external.string(),
4604
+ keySuffix: exports_external.string().min(1).max(10),
4605
+ keyIndex: exports_external.number().int().min(0),
4606
+ taskId: exports_external.string().uuid().optional(),
4607
+ scope: exports_external.string().optional(),
4608
+ scopeId: exports_external.string().optional()
4609
+ }),
4610
+ responses: {
4611
+ 200: {
4612
+ description: "Failure recorded",
4613
+ schema: exports_external.object({
4614
+ success: exports_external.literal(true),
4615
+ consecutiveAuthFailures: exports_external.number().int(),
4616
+ benched: exports_external.boolean(),
4617
+ rateLimitedUntil: exports_external.string().nullable()
4618
+ })
4619
+ },
4620
+ 400: { description: "Validation error" },
4621
+ 401: { description: "Unauthorized" }
4622
+ },
4623
+ auth: { apiKey: true },
4624
+ rbac: {
4625
+ ungated: "worker credential telemetry, same posture as POST /api/keys/report-rate-limit"
4626
+ }
4627
+ });
4442
4628
  var rateLimitWindowSchema = exports_external.object({
4443
4629
  status: exports_external.string(),
4444
4630
  utilization: exports_external.number().optional(),
@@ -4480,6 +4666,30 @@ var reportRateLimitWindows = route({
4480
4666
  },
4481
4667
  auth: { apiKey: true }
4482
4668
  });
4669
+ var reportSeatMismatch = route({
4670
+ method: "post",
4671
+ path: "/api/keys/report-seat-mismatch",
4672
+ pattern: ["api", "keys", "report-seat-mismatch"],
4673
+ summary: "Record that an API key's subscription seat cannot run a model family",
4674
+ tags: ["API Keys"],
4675
+ body: exports_external.object({
4676
+ keyType: exports_external.string(),
4677
+ keySuffix: exports_external.string().min(1).max(10),
4678
+ keyIndex: exports_external.number().int().min(0),
4679
+ model: exports_external.enum(["fable", "opus", "sonnet", "haiku"]),
4680
+ scope: exports_external.string().optional(),
4681
+ scopeId: exports_external.string().optional()
4682
+ }),
4683
+ responses: {
4684
+ 200: { description: "Seat mismatch recorded", schema: successMessageSchema },
4685
+ 400: { description: "Validation error" },
4686
+ 401: { description: "Unauthorized" }
4687
+ },
4688
+ auth: { apiKey: true },
4689
+ rbac: {
4690
+ ungated: "worker credential telemetry, same posture as POST /api/keys/report-rate-limit"
4691
+ }
4692
+ });
4483
4693
  var getAvailable = route({
4484
4694
  method: "get",
4485
4695
  path: "/api/keys/available",
@@ -4501,7 +4711,9 @@ var getAvailable = route({
4501
4711
  availableIndices: exports_external.array(exports_external.number().int()),
4502
4712
  totalKeys: exports_external.number().int(),
4503
4713
  modelBlockedIndices: exports_external.array(exports_external.number().int()).optional(),
4504
- earliestModelResetAt: exports_external.string().nullable().optional()
4714
+ earliestModelResetAt: exports_external.string().nullable().optional(),
4715
+ seatBlockedIndices: exports_external.array(exports_external.number().int()).optional(),
4716
+ authFailureFence: exports_external.number().int()
4505
4717
  })
4506
4718
  },
4507
4719
  400: { description: "Validation error" },
@@ -4527,6 +4739,10 @@ var ApiKeyStatusSchema = exports_external.object({
4527
4739
  rateLimitWindows: exports_external.record(exports_external.string(), rateLimitWindowSchema),
4528
4740
  plan: exports_external.string().nullable(),
4529
4741
  planSource: exports_external.enum(["manual", "detected", "estimated"]).nullable(),
4742
+ lastSeatMismatchAt: exports_external.string().nullable(),
4743
+ lastSeatMismatchModel: exports_external.string().nullable(),
4744
+ consecutiveAuthFailures: exports_external.number().int(),
4745
+ lastAuthFailureAt: exports_external.string().nullable(),
4530
4746
  modelLimits: exports_external.array(exports_external.object({
4531
4747
  model: exports_external.string(),
4532
4748
  window: exports_external.string(),
@@ -4648,7 +4864,10 @@ var clearRateLimitRoute = route({
4648
4864
  keyType: exports_external.string(),
4649
4865
  keySuffix: exports_external.string().min(1).max(10),
4650
4866
  scope: exports_external.string().optional(),
4651
- scopeId: exports_external.string().optional()
4867
+ scopeId: exports_external.string().optional(),
4868
+ clearAuthBench: exports_external.boolean().optional(),
4869
+ keyIndex: exports_external.number().int().min(0).optional(),
4870
+ authFence: exports_external.number().int().min(0).optional()
4652
4871
  }),
4653
4872
  responses: {
4654
4873
  200: {
@@ -4746,6 +4965,21 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
4746
4965
  }
4747
4966
  return true;
4748
4967
  }
4968
+ if (reportAuthFailure.match(req.method, pathSegments)) {
4969
+ const parsed = await reportAuthFailure.parse(req, res, pathSegments, queryParams);
4970
+ if (!parsed)
4971
+ return true;
4972
+ const { keyType, keySuffix, keyIndex, scope, scopeId } = parsed.body;
4973
+ try {
4974
+ const result = await recordKeyAuthFailure(keyType, keySuffix, keyIndex, scope, scopeId ?? null);
4975
+ if (result.benched)
4976
+ clearUsageCache();
4977
+ reportAuthFailure.respond(res, 200, { success: true, ...result });
4978
+ } catch (err) {
4979
+ jsonError(res, err instanceof Error ? err.message : "Failed to record auth failure", 500);
4980
+ }
4981
+ return true;
4982
+ }
4749
4983
  if (reportRateLimitWindows.match(req.method, pathSegments)) {
4750
4984
  const parsed = await reportRateLimitWindows.parse(req, res, pathSegments, queryParams);
4751
4985
  if (!parsed)
@@ -4764,6 +4998,24 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
4764
4998
  }
4765
4999
  return true;
4766
5000
  }
5001
+ if (reportSeatMismatch.match(req.method, pathSegments)) {
5002
+ const parsed = await reportSeatMismatch.parse(req, res, pathSegments, queryParams);
5003
+ if (!parsed)
5004
+ return true;
5005
+ const { keyType, keySuffix, keyIndex, model, scope, scopeId } = parsed.body;
5006
+ try {
5007
+ const { planChanged } = await recordKeySeatMismatch(keyType, keySuffix, keyIndex, model, scope, scopeId ?? null);
5008
+ if (planChanged)
5009
+ clearUsageCache();
5010
+ reportSeatMismatch.respond(res, 200, {
5011
+ success: true,
5012
+ message: `Seat mismatch recorded for ...${keySuffix} (${model})`
5013
+ });
5014
+ } catch (err) {
5015
+ jsonError(res, err instanceof Error ? err.message : "Failed to record seat mismatch", 500);
5016
+ }
5017
+ return true;
5018
+ }
4767
5019
  if (getAvailable.match(req.method, pathSegments)) {
4768
5020
  const parsed = await getAvailable.parse(req, res, pathSegments, queryParams);
4769
5021
  if (!parsed)
@@ -4775,9 +5027,11 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
4775
5027
  success: true,
4776
5028
  availableIndices: result.availableIndices,
4777
5029
  totalKeys,
5030
+ authFailureFence: result.authFailureFence,
4778
5031
  ...model !== undefined ? {
4779
5032
  modelBlockedIndices: result.modelBlockedIndices,
4780
- earliestModelResetAt: result.earliestModelResetAt
5033
+ earliestModelResetAt: result.earliestModelResetAt,
5034
+ seatBlockedIndices: result.seatBlockedIndices
4781
5035
  } : {}
4782
5036
  });
4783
5037
  } catch (err) {
@@ -4871,9 +5125,13 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
4871
5125
  const parsed = await clearRateLimitRoute.parse(req, res, pathSegments, queryParams);
4872
5126
  if (!parsed)
4873
5127
  return true;
4874
- const { keyType, keySuffix, scope, scopeId } = parsed.body;
5128
+ const { keyType, keySuffix, scope, scopeId, clearAuthBench, keyIndex, authFence } = parsed.body;
4875
5129
  try {
4876
- const cleared = await clearKeyRateLimit(keyType, keySuffix, scope, scopeId ?? null);
5130
+ const cleared = await clearKeyRateLimit(keyType, keySuffix, scope, scopeId ?? null, {
5131
+ clearAuthBench: clearAuthBench === true,
5132
+ keyIndex,
5133
+ authFence
5134
+ });
4877
5135
  clearRateLimitRoute.respond(res, 200, {
4878
5136
  success: true,
4879
5137
  cleared,
@@ -7054,8 +7312,8 @@ async function handleCodexOAuthDevice(req, res, pathSegments, queryParams) {
7054
7312
  // src/http/codex-oauth-keep-warm.ts
7055
7313
  init_zod();
7056
7314
  init_db();
7315
+ init_codex_auth_failure();
7057
7316
  var KEEP_WARM_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
7058
- var AUTH_WATCH_NAMESPACE = "codex-auth-watch";
7059
7317
  var slotOutcomeSchema = exports_external.discriminatedUnion("outcome", [
7060
7318
  exports_external.object({ slot: exports_external.number(), keySuffix: exports_external.string(), outcome: exports_external.literal("warm") }),
7061
7319
  exports_external.object({ slot: exports_external.number(), keySuffix: exports_external.string(), outcome: exports_external.literal("refreshed") }),
@@ -7073,7 +7331,7 @@ var keepWarmRoute = route({
7073
7331
  path: "/api/oauth/keep-warm/codex",
7074
7332
  pattern: ["api", "oauth", "keep-warm", "codex"],
7075
7333
  summary: "Locked keep-warm refresh sweep across all Codex OAuth pool slots",
7076
- description: "Enumerates codex_oauth_* slots and refreshes any older than ~7 days through the same locked getValidCodexOAuth path used at task time. Skips slots already benched by codex-auth-expiry-watch.",
7334
+ description: "Enumerates codex_oauth_* slots and refreshes any older than ~7 days through the same locked getValidCodexOAuth path used at task time. Skips slots with a codex-auth-watch bench marker (auth-failure bench or codex-auth-expiry-watch).",
7077
7335
  tags: ["OAuth"],
7078
7336
  responses: {
7079
7337
  200: {
@@ -7094,7 +7352,7 @@ async function handleCodexOAuthKeepWarm(req, res, pathSegments) {
7094
7352
  const results = [];
7095
7353
  for (const { slot, creds } of slots) {
7096
7354
  const keySuffix = deriveCodexKeySuffix(creds.access, creds.accountId);
7097
- if (await getKv(AUTH_WATCH_NAMESPACE, `bench:${keySuffix}`)) {
7355
+ if (await getKv(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(keySuffix))) {
7098
7356
  results.push({ slot, keySuffix, outcome: "skipped-benched" });
7099
7357
  continue;
7100
7358
  }
@@ -7671,6 +7929,9 @@ declare module "swarm-extension" {
7671
7929
  model?: string | undefined;
7672
7930
  modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;
7673
7931
  effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;
7932
+ resolvedModel?: string | undefined;
7933
+ modelSource?: string | undefined;
7934
+ modelAlias?: string | undefined;
7674
7935
  scheduleId?: string | undefined;
7675
7936
  workflowRunId?: string | null | undefined;
7676
7937
  workflowRunStepId?: string | null | undefined;
@@ -13753,6 +14014,79 @@ async function getUsefulnessStats(options = {}) {
13753
14014
  };
13754
14015
  }
13755
14016
 
14017
+ // src/memory/recall-query.ts
14018
+ var COMPLETED_INSTRUCTIONS = `
14019
+
14020
+ IMPORTANT: Do NOT re-delegate or re-answer the original request. The worker has already handled it. Your job is ONLY to:
14021
+ 1. Review the output above
14022
+ 2. Do not relay the worker's raw output to Slack; the engine owns the thread tree and outcome card
14023
+ 3. Complete this follow-up task
14024
+
14025
+ Use`;
14026
+ var FAILED_INSTRUCTIONS = `
14027
+
14028
+ Decide whether to reassign, retry, or handle the failure. Use`;
14029
+ var DETAILS_PREFIX = ' `get-task-details` with taskId "';
14030
+ var DETAILS_SUFFIX = '" for full details.';
14031
+ function buildRecallQuery(description) {
14032
+ let query = stripSiblingBlock(truncateUtf8(description, 65536));
14033
+ const header2 = query.match(/^Worker task (completed|failed) — (?:review|action) needed\.\n\nAgent: [^\n]*\nOriginal task created by agent [^\n]*\nTask: "/);
14034
+ if (header2) {
14035
+ const taskStart = header2[0].length;
14036
+ const outputMarker = header2[1] === "completed" ? `"
14037
+
14038
+ Output:
14039
+ ` : `"
14040
+
14041
+ Failure reason: `;
14042
+ const taskEnd = query.indexOf(outputMarker, taskStart);
14043
+ const outputStart = taskEnd + outputMarker.length;
14044
+ const instructions = header2[1] === "completed" ? COMPLETED_INSTRUCTIONS : FAILED_INSTRUCTIONS;
14045
+ const outputEnd = query.indexOf(instructions + DETAILS_PREFIX, outputStart);
14046
+ const idStart = outputEnd + instructions.length + DETAILS_PREFIX.length;
14047
+ const idEnd = query.indexOf('"', idStart);
14048
+ if (taskEnd !== -1 && outputEnd !== -1 && idEnd !== -1 && !query.slice(idStart, idEnd).includes(`
14049
+ `) && query.startsWith(DETAILS_SUFFIX, idEnd)) {
14050
+ const creatorInstructions = query.indexOf(`
14051
+ Additional instructions from the task creator:
14052
+ `, outputStart);
14053
+ const contentEnd = creatorInstructions !== -1 && creatorInstructions < outputEnd ? creatorInstructions : outputEnd;
14054
+ const threadContext = [];
14055
+ let cursor = idEnd + DETAILS_SUFFIX.length;
14056
+ while (cursor < query.length) {
14057
+ const start = query.indexOf("<thread_context>", cursor);
14058
+ if (start === -1)
14059
+ break;
14060
+ const end = query.indexOf("</thread_context>", start);
14061
+ if (end === -1)
14062
+ break;
14063
+ cursor = end + "</thread_context>".length;
14064
+ threadContext.push(query.slice(start, cursor));
14065
+ }
14066
+ query = [
14067
+ query.slice(taskStart, taskEnd),
14068
+ query.slice(outputStart, contentEnd),
14069
+ ...threadContext
14070
+ ].join(`
14071
+
14072
+ `);
14073
+ }
14074
+ }
14075
+ query = query.trim();
14076
+ return truncateUtf8(query, 8191);
14077
+ }
14078
+ function truncateUtf8(query, maxBytes) {
14079
+ let bytes = 0;
14080
+ let end = 0;
14081
+ for (const character of query) {
14082
+ bytes += Buffer.byteLength(character, "utf8");
14083
+ if (bytes > maxBytes)
14084
+ break;
14085
+ end += character.length;
14086
+ }
14087
+ return query.slice(0, end);
14088
+ }
14089
+
13756
14090
  // src/http/memory.ts
13757
14091
  init_types();
13758
14092
  init_request_auth_context();
@@ -14249,7 +14583,14 @@ async function handleMemory(req, res, pathSegments, callerAgentId) {
14249
14583
  const parsed = await searchMemory.parse(req, res, pathSegments, new URLSearchParams);
14250
14584
  if (!parsed)
14251
14585
  return true;
14252
- const { query, intent, limit, scope, source } = parsed.body;
14586
+ const { query: originalQuery, intent, limit, scope, source } = parsed.body;
14587
+ const consumptionHeader = req.headers["x-memory-consumption"];
14588
+ const consumptionMode = Array.isArray(consumptionHeader) ? consumptionHeader[0] : consumptionHeader;
14589
+ const query = consumptionMode === "prompt" ? buildRecallQuery(originalQuery) : originalQuery;
14590
+ if (consumptionMode === "prompt" && !query) {
14591
+ searchMemory.respond(res, 200, { results: [] });
14592
+ return true;
14593
+ }
14253
14594
  try {
14254
14595
  const provider = getEmbeddingProvider();
14255
14596
  const store = getMemoryStore();
@@ -14268,8 +14609,6 @@ async function handleMemory(req, res, pathSegments, callerAgentId) {
14268
14609
  isLead: false
14269
14610
  });
14270
14611
  const resultLimit = Math.min(limit, 20);
14271
- const consumptionHeader = req.headers["x-memory-consumption"];
14272
- const consumptionMode = Array.isArray(consumptionHeader) ? consumptionHeader[0] : consumptionHeader;
14273
14612
  const ranked = consumptionMode === "prompt" ? rerank(expanded, { limit: expanded.length }).map((r) => ({ r, eligible: memoryRelevance(r) > SIMILARITY_THRESHOLD })).sort((a, b) => Number(b.eligible) - Number(a.eligible)).slice(0, resultLimit).map(({ r }) => r) : rerank(expanded, { limit: resultLimit });
14274
14613
  const sourceTaskIdHeader = req.headers["x-source-task-id"];
14275
14614
  const sourceTaskId = Array.isArray(sourceTaskIdHeader) ? sourceTaskIdHeader[0] : sourceTaskIdHeader;
@@ -15173,11 +15512,21 @@ async function handleMetrics(req, res, pathSegments, queryParams, myAgentId) {
15173
15512
 
15174
15513
  // src/http/models-catalog.ts
15175
15514
  init_zod();
15515
+ init_db();
15516
+ init_types();
15517
+ init_request_auth_context();
15176
15518
  var CatalogModelSchema = exports_external.object({
15177
15519
  id: exports_external.string(),
15178
15520
  name: exports_external.string().optional(),
15179
- cost: exports_external.object({ input: exports_external.number().optional(), output: exports_external.number().optional() }).optional(),
15521
+ cost: exports_external.object({
15522
+ input: exports_external.number().optional(),
15523
+ output: exports_external.number().optional(),
15524
+ cache_read: exports_external.number().optional(),
15525
+ cache_write: exports_external.number().optional()
15526
+ }).optional(),
15180
15527
  limit: exports_external.object({ context: exports_external.number().optional() }).optional(),
15528
+ release_date: exports_external.string().optional(),
15529
+ status: exports_external.string().optional(),
15181
15530
  reasoning: exports_external.boolean().optional(),
15182
15531
  reasoning_options: exports_external.array(exports_external.object({ type: exports_external.string(), values: exports_external.array(exports_external.string()).optional() })).optional()
15183
15532
  });
@@ -15186,6 +15535,55 @@ var CatalogProviderSchema = exports_external.object({
15186
15535
  name: exports_external.string().optional(),
15187
15536
  models: exports_external.record(exports_external.string(), CatalogModelSchema)
15188
15537
  });
15538
+ var ReasoningOptionSchema = exports_external.object({
15539
+ type: exports_external.string(),
15540
+ values: exports_external.array(exports_external.string()).optional()
15541
+ });
15542
+ var OverlayPricingSchema = exports_external.object({
15543
+ input: exports_external.number().nonnegative().optional(),
15544
+ output: exports_external.number().nonnegative().optional(),
15545
+ cache_read: exports_external.number().nonnegative().optional(),
15546
+ cache_write: exports_external.number().nonnegative().optional()
15547
+ });
15548
+ var ModelCatalogRefreshResultSchema = exports_external.object({
15549
+ status: exports_external.enum(["updated", "not-modified", "skipped-fresh", "skipped-cooldown", "error"]),
15550
+ models: exports_external.number(),
15551
+ added: exports_external.array(exports_external.string()),
15552
+ checkedAt: exports_external.number().nullable(),
15553
+ retryAfterMs: exports_external.number().optional(),
15554
+ error: exports_external.string().optional()
15555
+ });
15556
+ var ModelCatalogOverlayBodySchema = exports_external.object({
15557
+ provider: exports_external.string().min(1),
15558
+ modelId: exports_external.string().min(1),
15559
+ name: exports_external.string().optional(),
15560
+ family: exports_external.string().optional(),
15561
+ releaseDate: exports_external.string().optional(),
15562
+ contextWindow: exports_external.number().int().positive().optional(),
15563
+ maxOutput: exports_external.number().int().positive().optional(),
15564
+ reasoning: exports_external.boolean().optional(),
15565
+ reasoningOptions: exports_external.array(ReasoningOptionSchema).optional(),
15566
+ pricing: OverlayPricingSchema.optional(),
15567
+ status: exports_external.string().optional(),
15568
+ reason: exports_external.string().min(1),
15569
+ verifiedBy: exports_external.string().optional(),
15570
+ expiresWhenUpstreamMatches: exports_external.boolean().optional()
15571
+ });
15572
+ var OverlayEntrySchema = ModelCatalogOverlayBodySchema.extend({
15573
+ name: exports_external.string().nullish(),
15574
+ family: exports_external.string().nullish(),
15575
+ releaseDate: exports_external.string().nullish(),
15576
+ contextWindow: exports_external.number().nullish(),
15577
+ maxOutput: exports_external.number().nullish(),
15578
+ reasoning: exports_external.boolean().nullish(),
15579
+ reasoningOptions: exports_external.array(ReasoningOptionSchema).nullish(),
15580
+ pricing: OverlayPricingSchema.nullish(),
15581
+ status: exports_external.string().nullish(),
15582
+ verifiedBy: exports_external.string().nullish(),
15583
+ expiresWhenUpstreamMatches: exports_external.boolean(),
15584
+ createdAt: exports_external.number(),
15585
+ updatedAt: exports_external.number()
15586
+ });
15189
15587
  var getCatalog = route({
15190
15588
  method: "get",
15191
15589
  path: "/api/models-catalog",
@@ -15204,12 +15602,218 @@ var getCatalog = route({
15204
15602
  }
15205
15603
  }
15206
15604
  });
15605
+ var ModelTierPreviewSchema = exports_external.object({
15606
+ provider: ProviderNameSchema,
15607
+ tier: exports_external.enum(MODEL_TIERS),
15608
+ key: exports_external.string(),
15609
+ defaultValue: exports_external.string(),
15610
+ configured: exports_external.string().nullable(),
15611
+ source: exports_external.enum(["tier-config", "tier-default"]),
15612
+ resolvedModel: exports_external.string().nullable(),
15613
+ alias: exports_external.string().nullable()
15614
+ });
15615
+ var getTiers = route({
15616
+ method: "get",
15617
+ path: "/api/models-catalog/tiers",
15618
+ pattern: ["api", "models-catalog", "tiers"],
15619
+ summary: "Preview what each model tier resolves to per harness provider",
15620
+ description: "One row per provider and tier: the built-in default, the `MODEL_TIER_<PROVIDER>_<TIER>` value stored in swarm config (if any), which layer wins, and the concrete model it resolves to against the current catalog (`latest:` aliases resolved with the same soak and auto-upgrade rules as claim time, without recording a resolution). Ignores per-worker `MODEL_TIER_*` overrides and per-task models.",
15621
+ tags: ["Pricing"],
15622
+ responses: {
15623
+ 200: {
15624
+ description: "Tier previews",
15625
+ schema: exports_external.object({ tiers: exports_external.array(ModelTierPreviewSchema) })
15626
+ }
15627
+ }
15628
+ });
15629
+ var refreshCatalog = route({
15630
+ method: "post",
15631
+ path: "/api/models-catalog/refresh",
15632
+ pattern: ["api", "models-catalog", "refresh"],
15633
+ summary: "Refresh the model catalog from models.dev",
15634
+ description: "Unforced calls skip the network when the last models.dev check is younger than 4h (`skipped-fresh`). `force: true` always fetches, still conditional on the stored ETag (`not-modified` on 304), but a forced call within a minute of the previous one returns `skipped-cooldown` with `retryAfterMs`. Concurrent refreshes share one fetch. Lead agent or operator only. `added` lists provider/modelId keys new since the previous fetch.",
15635
+ tags: ["Pricing"],
15636
+ rbac: { permission: "models.catalog.write" },
15637
+ body: exports_external.object({ force: exports_external.boolean().optional() }),
15638
+ responses: {
15639
+ 200: { description: "Refresh outcome", schema: ModelCatalogRefreshResultSchema },
15640
+ 403: { description: "Forbidden" }
15641
+ }
15642
+ });
15643
+ var upsertOverlay = route({
15644
+ method: "put",
15645
+ path: "/api/models-catalog/overlay",
15646
+ pattern: ["api", "models-catalog", "overlay"],
15647
+ summary: "Upsert one model-catalog overlay row",
15648
+ description: "Overlay facts win per non-null field over the models.dev row; overlay-only models are served too. Overlay prices fill pricing-table gaps (never override an active price). With `expiresWhenUpstreamMatches` (default true) the row is deleted once upstream matches every non-null fact.",
15649
+ tags: ["Pricing"],
15650
+ rbac: { permission: "models.catalog.write" },
15651
+ body: ModelCatalogOverlayBodySchema,
15652
+ responses: {
15653
+ 200: { description: "Overlay row upserted", schema: OverlayEntrySchema },
15654
+ 403: { description: "Forbidden" }
15655
+ }
15656
+ });
15657
+ var deleteOverlay = route({
15658
+ method: "delete",
15659
+ path: "/api/models-catalog/overlay",
15660
+ pattern: ["api", "models-catalog", "overlay"],
15661
+ summary: "Delete one model-catalog overlay row",
15662
+ tags: ["Pricing"],
15663
+ rbac: { permission: "models.catalog.write" },
15664
+ body: exports_external.object({ provider: exports_external.string().min(1), modelId: exports_external.string().min(1) }),
15665
+ responses: {
15666
+ 200: { description: "Overlay row deleted", schema: exports_external.object({ deleted: exports_external.boolean() }) },
15667
+ 403: { description: "Forbidden" }
15668
+ }
15669
+ });
15670
+ var HarnessSupportRowSchema = exports_external.object({
15671
+ harness: exports_external.string(),
15672
+ cliVersion: exports_external.string(),
15673
+ modelId: exports_external.string(),
15674
+ status: exports_external.enum(["ok", "unsupported", "unknown"]),
15675
+ checkedAt: exports_external.number(),
15676
+ error: exports_external.string().nullable()
15677
+ });
15678
+ var listHarnessSupport = route({
15679
+ method: "get",
15680
+ path: "/api/models-catalog/harness-support",
15681
+ pattern: ["api", "models-catalog", "harness-support"],
15682
+ summary: "List harness CLI model support rows",
15683
+ description: "Whether a catalog model runs on a given `claude` / `codex` CLI version, as recorded by workers after a model's first run. No row means unknown (allowed at claim).",
15684
+ tags: ["Pricing"],
15685
+ query: exports_external.object({ harness: exports_external.string().optional(), cliVersion: exports_external.string().optional() }),
15686
+ responses: {
15687
+ 200: {
15688
+ description: "Support rows, newest first",
15689
+ schema: exports_external.object({ rows: exports_external.array(HarnessSupportRowSchema) })
15690
+ }
15691
+ }
15692
+ });
15693
+ var recordHarnessSupport = route({
15694
+ method: "put",
15695
+ path: "/api/models-catalog/harness-support",
15696
+ pattern: ["api", "models-catalog", "harness-support"],
15697
+ summary: "Record whether a harness CLI version accepts a model",
15698
+ description: "Written by workers: `ok` after a model's first successful run, `unsupported` when the CLI rejects the model id. Claim-time resolution falls back (alias/tier) or fails fast (explicit model) on `unsupported`.",
15699
+ tags: ["Pricing"],
15700
+ rbac: { permission: "models.harness-support.write" },
15701
+ body: exports_external.object({
15702
+ harness: exports_external.string().min(1).max(32),
15703
+ cliVersion: exports_external.string().min(1).max(64),
15704
+ modelId: exports_external.string().min(1).max(200),
15705
+ status: exports_external.enum(["ok", "unsupported", "unknown"]),
15706
+ error: exports_external.string().max(4000).optional()
15707
+ }),
15708
+ responses: {
15709
+ 200: { description: "Support row upserted", schema: HarnessSupportRowSchema },
15710
+ 403: { description: "Forbidden" }
15711
+ }
15712
+ });
15713
+ async function ensureCatalogWriter(req, res, verb = "models.catalog.write") {
15714
+ const auth = getRequestAuth(req);
15715
+ const header2 = req.headers["x-agent-id"];
15716
+ const agentId = auth?.kind === "agent" ? auth.agentId : Array.isArray(header2) ? header2[0] : header2;
15717
+ let principal;
15718
+ if (auth?.kind === "user") {
15719
+ principal = { kind: "user", userId: auth.userId };
15720
+ } else if (agentId) {
15721
+ const agent = await getAgentById(agentId);
15722
+ principal = { kind: "agent", agentId, isLead: agent?.isLead ?? false };
15723
+ } else if (auth?.kind === "operator") {
15724
+ principal = { kind: "operator" };
15725
+ } else {
15726
+ principal = { kind: "agent", agentId: "", isLead: false };
15727
+ }
15728
+ const decision = can({
15729
+ principal,
15730
+ verb,
15731
+ resource: { kind: "none" },
15732
+ source: "http"
15733
+ });
15734
+ if (!decision.allow) {
15735
+ jsonError(res, verb === "models.catalog.write" ? "Writing the model catalog requires the lead agent or an operator" : "Recording harness model support requires a registered agent or an operator", 403);
15736
+ return null;
15737
+ }
15738
+ return {
15739
+ userId: auth?.kind === "user" ? auth.userId : null,
15740
+ agentId: principal.kind === "agent" && principal.agentId ? principal.agentId : null
15741
+ };
15742
+ }
15743
+ async function callerOwnsSupportRow(agentId, body) {
15744
+ const agent = await getAgentById(agentId);
15745
+ if (!agent || agent.harnessProvider !== body.harness)
15746
+ return false;
15747
+ return await getAgentHarnessCliVersion(agentId) === body.cliVersion;
15748
+ }
15207
15749
  async function handleModelsCatalog(req, res, pathSegments, queryParams) {
15208
15750
  if (getCatalog.match(req.method, pathSegments)) {
15209
15751
  const parsed = await getCatalog.parse(req, res, pathSegments, queryParams);
15210
15752
  if (!parsed)
15211
15753
  return true;
15212
- json(res, getModelsCatalog());
15754
+ getCatalog.respond(res, 200, await loadModelsCatalog());
15755
+ return true;
15756
+ }
15757
+ if (getTiers.match(req.method, pathSegments)) {
15758
+ const parsed = await getTiers.parse(req, res, pathSegments, queryParams);
15759
+ if (!parsed)
15760
+ return true;
15761
+ getTiers.respond(res, 200, { tiers: await previewModelTiers() });
15762
+ return true;
15763
+ }
15764
+ if (refreshCatalog.match(req.method, pathSegments)) {
15765
+ const parsed = await refreshCatalog.parse(req, res, pathSegments, queryParams);
15766
+ if (!parsed)
15767
+ return true;
15768
+ if (!await ensureCatalogWriter(req, res))
15769
+ return true;
15770
+ refreshCatalog.respond(res, 200, await requestModelCatalogRefresh({ force: parsed.body.force }));
15771
+ return true;
15772
+ }
15773
+ if (upsertOverlay.match(req.method, pathSegments)) {
15774
+ const parsed = await upsertOverlay.parse(req, res, pathSegments, queryParams);
15775
+ if (!parsed)
15776
+ return true;
15777
+ const writer = await ensureCatalogWriter(req, res);
15778
+ if (!writer)
15779
+ return true;
15780
+ const entry = await upsertModelCatalogOverlay(parsed.body, { userId: writer.userId });
15781
+ upsertOverlay.respond(res, 200, entry);
15782
+ return true;
15783
+ }
15784
+ if (deleteOverlay.match(req.method, pathSegments)) {
15785
+ const parsed = await deleteOverlay.parse(req, res, pathSegments, queryParams);
15786
+ if (!parsed)
15787
+ return true;
15788
+ if (!await ensureCatalogWriter(req, res))
15789
+ return true;
15790
+ const deleted = await deleteModelCatalogOverlay(parsed.body.provider, parsed.body.modelId);
15791
+ deleteOverlay.respond(res, 200, { deleted });
15792
+ return true;
15793
+ }
15794
+ if (listHarnessSupport.match(req.method, pathSegments)) {
15795
+ const parsed = await listHarnessSupport.parse(req, res, pathSegments, queryParams);
15796
+ if (!parsed)
15797
+ return true;
15798
+ listHarnessSupport.respond(res, 200, { rows: await listHarnessModelSupport(parsed.query) });
15799
+ return true;
15800
+ }
15801
+ if (recordHarnessSupport.match(req.method, pathSegments)) {
15802
+ const parsed = await recordHarnessSupport.parse(req, res, pathSegments, queryParams);
15803
+ if (!parsed)
15804
+ return true;
15805
+ const writer = await ensureCatalogWriter(req, res, "models.harness-support.write");
15806
+ if (!writer)
15807
+ return true;
15808
+ if (writer.agentId && !await callerOwnsSupportRow(writer.agentId, parsed.body)) {
15809
+ jsonError(res, "Harness support can only be recorded for the calling agent's own harness and registered CLI version", 403);
15810
+ return true;
15811
+ }
15812
+ if (writer.agentId && parsed.body.status === "unsupported" && !(isUnknownModelError(parsed.body.error, parsed.body.modelId) && await agentRanModel(writer.agentId, parsed.body.modelId))) {
15813
+ jsonError(res, "An unsupported report needs a model the calling agent ran and the CLI's model-rejection error", 403);
15814
+ return true;
15815
+ }
15816
+ recordHarnessSupport.respond(res, 200, await recordHarnessModelSupport(parsed.body));
15213
15817
  return true;
15214
15818
  }
15215
15819
  return false;
@@ -15761,6 +16365,7 @@ init_types();
15761
16365
  init_zod();
15762
16366
  init_db();
15763
16367
  init_config();
16368
+ init_telemetry();
15764
16369
  init_types();
15765
16370
  var SetupMilestoneStateSchema = exports_external.enum(["unverified", "configured", "verified"]);
15766
16371
  var SetupMilestoneIdSchema = exports_external.enum([
@@ -15804,6 +16409,9 @@ var StatusActivitySchema = exports_external.object({
15804
16409
  leads_online: exports_external.number().int().nonnegative(),
15805
16410
  recent_tasks_count: exports_external.number().int().nonnegative()
15806
16411
  });
16412
+ var StatusTelemetrySchema = exports_external.object({
16413
+ enabled: exports_external.boolean()
16414
+ });
15807
16415
  var StatusAgentFsSchema = exports_external.object({
15808
16416
  configured: exports_external.boolean(),
15809
16417
  base_url: exports_external.string().nullable(),
@@ -15836,7 +16444,8 @@ var StatusResponseSchema = exports_external.object({
15836
16444
  activity: StatusActivitySchema,
15837
16445
  agent_fs: StatusAgentFsSchema,
15838
16446
  automations: exports_external.array(AutomationStatusSchema),
15839
- health: StatusHealthSchema
16447
+ health: StatusHealthSchema,
16448
+ telemetry: StatusTelemetrySchema.optional()
15840
16449
  });
15841
16450
  var TestConnectionRequestSchema = exports_external.object({
15842
16451
  provider: ProviderNameSchema
@@ -16191,7 +16800,8 @@ async function buildStatusPayload() {
16191
16800
  ...getAgentFsStatusProvider()
16192
16801
  },
16193
16802
  automations,
16194
- health: computeHealth(setup)
16803
+ health: computeHealth(setup),
16804
+ telemetry: { enabled: isTelemetryEnabled() }
16195
16805
  };
16196
16806
  }
16197
16807
  function getAgentFsStatusProvider() {
@@ -16213,7 +16823,7 @@ var getStatus = route({
16213
16823
  path: "/status",
16214
16824
  pattern: ["status"],
16215
16825
  summary: "Identity + setup readiness + live activity for the swarm dashboard",
16216
- description: "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; setup milestones each emit `unverified | configured | verified`; automations report `running | needs_setup` from the same runtime preflight used at dispatch; activity counts agents alive in the last 5 min and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set.",
16826
+ description: "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; setup milestones each emit `unverified | configured | verified`; automations report `running | needs_setup` from the same runtime preflight used at dispatch; activity counts agents alive in the last 5 min and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set; telemetry reports the effective ANONYMIZED_TELEMETRY opt-out state.",
16217
16827
  tags: ["Status"],
16218
16828
  responses: {
16219
16829
  200: { description: "Status payload", schema: StatusResponseSchema },
@@ -17868,7 +18478,9 @@ var pollTriggers = route({
17868
18478
  summary: "Poll for triggers (tasks, mentions)",
17869
18479
  tags: ["Poll"],
17870
18480
  auth: { apiKey: true, agentId: true },
17871
- headers: runtimeInstanceHeader("poll for work"),
18481
+ headers: runtimeInstanceHeader("poll for work").extend({
18482
+ "X-Model-Tier-Overrides": exports_external.string().optional().describe("URL-encoded JSON {provider: {tier: model}} of the worker's MODEL_TIER_* env overrides. " + "Stored on the agent row and applied at claim time (modelSource=worker-env).")
18483
+ }),
17872
18484
  responses: {
17873
18485
  200: { description: "Trigger data or null", schema: pollResponseSchema },
17874
18486
  400: { description: "Missing X-Agent-ID" },
@@ -17905,6 +18517,14 @@ async function attachmentsForTrigger(taskId) {
17905
18517
  sizeBytes: a.sizeBytes
17906
18518
  }));
17907
18519
  }
18520
+ async function claimModelFields(task, agent) {
18521
+ try {
18522
+ return await recordClaimModelResolution(task, agent);
18523
+ } catch (error) {
18524
+ console.warn(`[/api/poll] model resolution failed for task ${task.id}:`, error);
18525
+ return {};
18526
+ }
18527
+ }
17908
18528
  var commitCursorsRoute = route({
17909
18529
  method: "post",
17910
18530
  path: "/api/channel-activity/commit-cursors",
@@ -17928,6 +18548,7 @@ var commitCursorsRoute = route({
17928
18548
  });
17929
18549
  async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
17930
18550
  const runtimeInstanceId = ((h) => Array.isArray(h) ? h[0] : h)(req.headers["x-runtime-instance-id"]);
18551
+ const modelTierOverrides = parseModelTierOverridesHeader(((h) => Array.isArray(h) ? h[0] : h)(req.headers["x-model-tier-overrides"]));
17931
18552
  if (commitCursorsRoute.match(req.method, pathSegments)) {
17932
18553
  const parsed = await commitCursorsRoute.parse(req, res, pathSegments, queryParams);
17933
18554
  if (!parsed)
@@ -17955,6 +18576,9 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
17955
18576
  if (!agent) {
17956
18577
  return { error: "Agent not found", status: 404 };
17957
18578
  }
18579
+ if (modelTierOverrides) {
18580
+ await setAgentModelTierOverrides(agent.id, modelTierOverrides);
18581
+ }
17958
18582
  if (isExtensionAgent(agent)) {
17959
18583
  return { trigger: null };
17960
18584
  }
@@ -18052,6 +18676,7 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
18052
18676
  taskId: pendingTask.id,
18053
18677
  task: {
18054
18678
  ...pendingTask,
18679
+ ...await claimModelFields(pendingTask, agent),
18055
18680
  status: "in_progress",
18056
18681
  attachments: await attachmentsForTrigger(pendingTask.id)
18057
18682
  },
@@ -18073,7 +18698,8 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
18073
18698
  }
18074
18699
  if (agent.isLead) {} else {
18075
18700
  if (await hasCapacity(myAgentId)) {
18076
- const unassignedIds = await getUnassignedTaskIdsForAgent(myAgentId, 5);
18701
+ const harness = agent.harnessProvider ?? agent.provider ?? null;
18702
+ const unassignedIds = await getUnassignedTaskIdsForAgent(myAgentId, 5, (task) => poolTaskRunsOnHarness(task, harness));
18077
18703
  if (unassignedIds.length > 0) {
18078
18704
  const candidateId = unassignedIds[0];
18079
18705
  const candidateTask = await getTaskById(candidateId);
@@ -18136,7 +18762,11 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
18136
18762
  trigger: {
18137
18763
  type: "task_assigned",
18138
18764
  taskId: claimed.id,
18139
- task: { ...claimed, attachments: await attachmentsForTrigger(claimed.id) },
18765
+ task: {
18766
+ ...claimed,
18767
+ ...await claimModelFields(claimed, agent),
18768
+ attachments: await attachmentsForTrigger(claimed.id)
18769
+ },
18140
18770
  ...claimedRequestedBy && { requestedBy: claimedRequestedBy }
18141
18771
  }
18142
18772
  };
@@ -19298,6 +19928,7 @@ var scheduleUpdateBodySchema = exports_external.object({
19298
19928
  timezone: exports_external.string().optional(),
19299
19929
  model: exports_external.string().nullable().optional(),
19300
19930
  modelTier: ModelTierSchema.nullable().optional(),
19931
+ allowCustomModel: exports_external.boolean().optional(),
19301
19932
  nextRunAt: exports_external.string().nullable().optional(),
19302
19933
  targetType: ScheduledTaskTargetTypeSchema.optional(),
19303
19934
  workflowId: exports_external.string().uuid().nullable().optional(),
@@ -19338,6 +19969,7 @@ var createSchedule = route({
19338
19969
  timezone: exports_external.string().optional(),
19339
19970
  model: exports_external.string().optional(),
19340
19971
  modelTier: ModelTierSchema.optional(),
19972
+ allowCustomModel: exports_external.boolean().optional(),
19341
19973
  scheduleType: exports_external.enum(["recurring", "one_time"]).optional(),
19342
19974
  targetType: ScheduledTaskTargetTypeSchema.optional(),
19343
19975
  workflowId: exports_external.string().uuid().optional(),
@@ -19575,6 +20207,15 @@ async function handleSchedules(req, res, pathSegments, queryParams, myAgentId) {
19575
20207
  return true;
19576
20208
  }
19577
20209
  }
20210
+ const modelError = await explicitModelErrorForAgent({
20211
+ model: splitLegacyModelAlias({ model: body.model, modelTier: body.modelTier }).model,
20212
+ allowCustomModel: body.allowCustomModel,
20213
+ agentId: body.targetAgentId
20214
+ });
20215
+ if (modelError) {
20216
+ jsonError(res, modelError, 400);
20217
+ return true;
20218
+ }
19578
20219
  try {
19579
20220
  const trustedUserId = await resolveHttpAuditUserId(req, myAgentId);
19580
20221
  let key;
@@ -19703,21 +20344,45 @@ async function handleSchedules(req, res, pathSegments, queryParams, myAgentId) {
19703
20344
  throw error;
19704
20345
  }
19705
20346
  }
20347
+ const allowCustomModel = parsed.body.allowCustomModel;
20348
+ delete body.allowCustomModel;
20349
+ const existing = await getScheduledTaskById(parsed.params.id);
20350
+ if (!existing) {
20351
+ jsonError(res, "Schedule not found", 404);
20352
+ return true;
20353
+ }
20354
+ const agentChanged = parsed.body.targetAgentId !== undefined && parsed.body.targetAgentId !== existing.targetAgentId;
19706
20355
  if (parsed.body.model !== undefined || parsed.body.modelTier !== undefined) {
19707
20356
  const normalizedModel = splitLegacyModelAlias({
19708
20357
  model: parsed.body.model,
19709
20358
  modelTier: parsed.body.modelTier
19710
20359
  });
20360
+ if (normalizedModel.model !== existing.model || agentChanged) {
20361
+ const modelError = await explicitModelErrorForAgent({
20362
+ model: normalizedModel.model,
20363
+ allowCustomModel: allowCustomModel || normalizedModel.model === existing.model,
20364
+ agentId: parsed.body.targetAgentId ?? existing.targetAgentId
20365
+ });
20366
+ if (modelError) {
20367
+ jsonError(res, modelError, 400);
20368
+ return true;
20369
+ }
20370
+ }
19711
20371
  if (parsed.body.model !== undefined)
19712
20372
  body.model = normalizedModel.model ?? null;
19713
20373
  if (parsed.body.modelTier !== undefined || normalizedModel.modelTier) {
19714
20374
  body.modelTier = normalizedModel.modelTier ?? null;
19715
20375
  }
19716
- }
19717
- const existing = await getScheduledTaskById(parsed.params.id);
19718
- if (!existing) {
19719
- jsonError(res, "Schedule not found", 404);
19720
- return true;
20376
+ } else if (agentChanged && existing.model) {
20377
+ const modelError = await explicitModelErrorForAgent({
20378
+ model: existing.model,
20379
+ allowCustomModel: true,
20380
+ agentId: parsed.body.targetAgentId ?? existing.targetAgentId
20381
+ });
20382
+ if (modelError) {
20383
+ jsonError(res, modelError, 400);
20384
+ return true;
20385
+ }
19721
20386
  }
19722
20387
  if (existing.scheduleType === "one_time" && !existing.enabled && existing.lastRunAt) {
19723
20388
  jsonError(res, "One-time schedule has already executed. Create a new one instead.", 400);
@@ -21950,6 +22615,7 @@ var agentTaskBodySchema = exports_external.object({
21950
22615
  dir: exports_external.string().min(1).optional(),
21951
22616
  vcsRepo: exports_external.string().min(1).optional(),
21952
22617
  model: exports_external.string().min(1).optional(),
22618
+ allowCustomModel: exports_external.boolean().optional(),
21953
22619
  parentTaskId: exports_external.string().uuid().optional(),
21954
22620
  requestedByUserId: exports_external.string().optional(),
21955
22621
  outputSchema: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
@@ -22402,6 +23068,15 @@ async function handleScriptRuns(req, res, pathSegments, queryParams, agentId) {
22402
23068
  const contextKey = `script-run:${run.id}:${parsed.body.stepKey}`;
22403
23069
  let task = await getLatestScriptRunStepTaskByContextKey(contextKey);
22404
23070
  if (!task) {
23071
+ const modelError = await explicitModelErrorForAgent({
23072
+ model: parsed.body.model,
23073
+ allowCustomModel: parsed.body.allowCustomModel,
23074
+ agentId: parsed.body.agentId
23075
+ });
23076
+ if (modelError) {
23077
+ jsonError(res, modelError, 400);
23078
+ return true;
23079
+ }
22405
23080
  try {
22406
23081
  task = await createTaskExtended(parsed.body.template ?? parsed.body.task ?? parsed.body.stepKey, {
22407
23082
  agentId: parsed.body.agentId,
@@ -23752,8 +24427,7 @@ async function handleSessionData(req, res, pathSegments, queryParams, _myAgentId
23752
24427
  userId: parsed.query.userId || undefined,
23753
24428
  groupBy: parsed.query.groupBy || "both"
23754
24429
  };
23755
- const version = await getUsageDataVersion();
23756
- const summary = await cachedUsageReport(`summary:${version}:${JSON.stringify(opts)}`, () => getSessionCostSummary(opts));
24430
+ const summary = await cachedUsageReport(`summary:${JSON.stringify(opts)}`, () => getSessionCostSummary(opts));
23757
24431
  getSessionCostSummaryRoute.respond(res, 200, summary);
23758
24432
  return true;
23759
24433
  }
@@ -23770,8 +24444,7 @@ async function handleSessionData(req, res, pathSegments, queryParams, _myAgentId
23770
24444
  startDate: parsed.query.startDate || undefined,
23771
24445
  endDate: parsed.query.endDate || undefined
23772
24446
  };
23773
- const version = await getUsageDataVersion();
23774
- const rows = await cachedUsageReport(`attribution:${version}:${JSON.stringify(opts)}`, () => getAttributionByPerson(opts));
24447
+ const rows = await cachedUsageReport(`attribution:${JSON.stringify(opts)}`, () => getAttributionByPerson(opts));
23775
24448
  getAttributionByPersonRoute.respond(res, 200, { rows });
23776
24449
  return true;
23777
24450
  }
@@ -24804,6 +25477,7 @@ init_zod();
24804
25477
  init_db();
24805
25478
  init_steering();
24806
25479
  init_types();
25480
+ init_env_flag();
24807
25481
  var AgentCountsSchema = exports_external.object({
24808
25482
  total: exports_external.number(),
24809
25483
  idle: exports_external.number(),
@@ -24825,7 +25499,8 @@ var DashboardStatsSchema = exports_external.object({
24825
25499
  agents: AgentCountsSchema,
24826
25500
  tasks: TaskCountsSchema,
24827
25501
  steeringEnabled: exports_external.boolean(),
24828
- multiRuntimeEnabled: exports_external.boolean()
25502
+ multiRuntimeEnabled: exports_external.boolean(),
25503
+ devMode: exports_external.boolean()
24829
25504
  });
24830
25505
  var RetentionTableStatsSchema = exports_external.object({
24831
25506
  at: exports_external.string(),
@@ -24990,15 +25665,10 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
24990
25665
  return true;
24991
25666
  }
24992
25667
  if (getStats.match(req.method, pathSegments)) {
24993
- const agents = await getAllAgents();
25668
+ const agents = await getAgentStatusCounts();
24994
25669
  const taskStats = await getTaskStats();
24995
25670
  const stats = {
24996
- agents: {
24997
- total: agents.length,
24998
- idle: agents.filter((a) => a.status === "idle").length,
24999
- busy: agents.filter((a) => a.status === "busy").length,
25000
- offline: agents.filter((a) => a.status === "offline").length
25001
- },
25671
+ agents,
25002
25672
  tasks: {
25003
25673
  total: taskStats.total,
25004
25674
  unassigned: taskStats.unassigned,
@@ -25011,6 +25681,7 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
25011
25681
  failed: taskStats.failed
25012
25682
  },
25013
25683
  steeringEnabled: isSteeringEnabled2(),
25684
+ devMode: isEnvFlagEnabled("SWARM_DEV_MODE", false),
25014
25685
  multiRuntimeEnabled: isMultiRuntimeEnabled()
25015
25686
  };
25016
25687
  getStats.respond(res, 200, stats);
@@ -25129,6 +25800,9 @@ var AgentTaskSummarySchema2 = AgentTaskSchema.pick({
25129
25800
  scheduleId: true,
25130
25801
  model: true,
25131
25802
  modelTier: true,
25803
+ resolvedModel: true,
25804
+ modelSource: true,
25805
+ modelAlias: true,
25132
25806
  effort: true,
25133
25807
  provider: true,
25134
25808
  requestedByUserId: true,
@@ -25254,8 +25928,9 @@ var createTask = route({
25254
25928
  outputSchema: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
25255
25929
  contextKey: exports_external.string().optional(),
25256
25930
  requestedByUserId: exports_external.string().optional(),
25257
- model: exports_external.string().optional(),
25931
+ model: exports_external.string().optional().describe("Concrete model override for this task, interpreted by the assignee's harness/provider. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
25258
25932
  modelTier: ModelTierSchema.optional(),
25933
+ allowCustomModel: exports_external.boolean().optional(),
25259
25934
  effort: ReasoningEffortSchema.optional(),
25260
25935
  draft: exports_external.boolean().optional()
25261
25936
  }).superRefine((body, ctx) => {
@@ -25269,7 +25944,9 @@ var createTask = route({
25269
25944
  }),
25270
25945
  responses: {
25271
25946
  201: { description: "Task created", schema: AgentTaskSchema },
25272
- 400: { description: "Validation error, or agentId/offeredTo targets an extension identity" },
25947
+ 400: {
25948
+ description: "Validation error, an unknown `model` (set `allowCustomModel` to store a custom id), or agentId/offeredTo targets an extension identity"
25949
+ },
25273
25950
  422: {
25274
25951
  description: "Task creation blocked by an extension",
25275
25952
  schema: exports_external.object({
@@ -25336,6 +26013,7 @@ var cancelTaskRoute = route({
25336
26013
  responses: {
25337
26014
  200: { description: "Task cancelled", schema: TaskActionResultSchema },
25338
26015
  400: { description: "Cannot cancel terminal task" },
26016
+ 403: { description: "Agent caller is neither a lead nor the task creator" },
25339
26017
  404: { description: "Task not found" }
25340
26018
  }
25341
26019
  });
@@ -25485,6 +26163,7 @@ var updateTaskProgressRoute = route({
25485
26163
  body: exports_external.object({ progress: exports_external.string().min(1) }),
25486
26164
  responses: {
25487
26165
  200: { description: "Progress updated", schema: exports_external.object({ success: exports_external.literal(true) }) },
26166
+ 403: { description: "Task is assigned to another agent" },
25488
26167
  404: { description: "Task not found" }
25489
26168
  }
25490
26169
  });
@@ -25668,6 +26347,16 @@ async function canActOnOwnTask(req, myAgentId, task) {
25668
26347
  }
25669
26348
  return can({ principal, verb: "task.action.own", resource, source: "http" }).allow;
25670
26349
  }
26350
+ async function resolveTaskWritePrincipal(req, myAgentId) {
26351
+ const auth = getRequestAuth(req);
26352
+ if (auth?.kind === "user")
26353
+ return { kind: "user", userId: auth.userId };
26354
+ const agentId = auth?.kind === "agent" ? auth.agentId : myAgentId;
26355
+ if (!agentId)
26356
+ return { kind: "operator" };
26357
+ const agent = await getAgentById(agentId);
26358
+ return { kind: "agent", agentId, isLead: agent?.isLead === true };
26359
+ }
25671
26360
  async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
25672
26361
  if (listTasks.match(req.method, pathSegments)) {
25673
26362
  const parsed = await listTasks.parse(req, res, pathSegments, queryParams);
@@ -25746,6 +26435,15 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
25746
26435
  if (lead)
25747
26436
  defaultAgentId = lead.id;
25748
26437
  }
26438
+ const modelError = await explicitModelErrorForAgent({
26439
+ model: splitLegacyModelAlias({ model: parsed.body.model, modelTier: parsed.body.modelTier }).model,
26440
+ allowCustomModel: parsed.body.allowCustomModel,
26441
+ agentId: defaultAgentId
26442
+ });
26443
+ if (modelError) {
26444
+ jsonError(res, modelError, 400);
26445
+ return true;
26446
+ }
25749
26447
  const parentTask = parsed.body.parentTaskId ? await getTaskById(parsed.body.parentTaskId) : null;
25750
26448
  let assetKey;
25751
26449
  try {
@@ -25784,7 +26482,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
25784
26482
  modelTier: parsed.body.modelTier
25785
26483
  }),
25786
26484
  effort: parsed.body.effort
25787
- }, { origin: "rest" });
26485
+ }, { origin: "rest", allowCustomModel: parsed.body.allowCustomModel });
25788
26486
  ensure({
25789
26487
  id: "created",
25790
26488
  flow: "task",
@@ -25858,6 +26556,16 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
25858
26556
  jsonError(res, "Task not found", 404);
25859
26557
  return true;
25860
26558
  }
26559
+ const principal = await resolveTaskWritePrincipal(req, myAgentId);
26560
+ if (principal.kind === "agent" && !can({
26561
+ principal,
26562
+ verb: "task.cancel.any",
26563
+ resource: { kind: "task", taskId: task.id, creatorAgentId: task.creatorAgentId },
26564
+ source: "http"
26565
+ }).allow) {
26566
+ jsonError(res, "Only the lead or task creator can cancel tasks.", 403);
26567
+ return true;
26568
+ }
25861
26569
  if (isTerminalTaskStatus(task.status)) {
25862
26570
  jsonError(res, `Cannot cancel task with status '${task.status}'`, 400);
25863
26571
  return true;
@@ -26134,12 +26842,30 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
26134
26842
  const parsed = await updateTaskProgressRoute.parse(req, res, pathSegments, queryParams);
26135
26843
  if (!parsed)
26136
26844
  return true;
26137
- const task = await getTaskById(parsed.params.id);
26138
- if (!task) {
26845
+ const principal = await resolveTaskWritePrincipal(req, myAgentId);
26846
+ const status = await getDbClient().transaction(async () => {
26847
+ const task = await getTaskById(parsed.params.id);
26848
+ if (!task)
26849
+ return 404;
26850
+ const decision = can({
26851
+ principal,
26852
+ verb: "task.progress.write",
26853
+ resource: { kind: "task", taskId: task.id, agentId: task.agentId },
26854
+ source: "http"
26855
+ });
26856
+ if (!decision.allow)
26857
+ return 403;
26858
+ await updateTaskProgress(parsed.params.id, parsed.body.progress);
26859
+ return 200;
26860
+ });
26861
+ if (status === 404) {
26139
26862
  jsonError(res, "Task not found", 404);
26140
26863
  return true;
26141
26864
  }
26142
- await updateTaskProgress(parsed.params.id, parsed.body.progress);
26865
+ if (status === 403) {
26866
+ jsonError(res, "Task is assigned to another agent", 403);
26867
+ return true;
26868
+ }
26143
26869
  updateTaskProgressRoute.respond(res, 200, { success: true });
26144
26870
  return true;
26145
26871
  }
@@ -26423,6 +27149,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
26423
27149
  reason: parsed.body.reason
26424
27150
  });
26425
27151
  if (followUp.kind !== "created") {
27152
+ await settleSupersededTaskDependents(parsed.params.id, null);
26426
27153
  console.warn(`[Supersede] Task ${parsed.params.id.slice(0, 8)} superseded but resume creation skipped (${followUp.kind === "skipped" ? followUp.reason : followUp.kind})`);
26427
27154
  supersedeTaskRoute.respond(res, 200, {
26428
27155
  success: true,
@@ -28691,6 +29418,9 @@ init_zod();
28691
29418
  init_db();
28692
29419
  init_types();
28693
29420
  var WorkflowWithFavoriteSchema = WorkflowSchema.extend({ favorite: exports_external.boolean() });
29421
+ var WorkflowSaveResponseSchema = WorkflowSchema.extend({
29422
+ warnings: exports_external.array(exports_external.string()).optional()
29423
+ });
28694
29424
  var WorkflowSummarySchema = WorkflowSchema.omit({
28695
29425
  definition: true,
28696
29426
  triggers: true,
@@ -28716,6 +29446,10 @@ var WorkflowRunPageSchema = exports_external.object({
28716
29446
  })
28717
29447
  });
28718
29448
  var SuccessResponseSchema = exports_external.object({ success: exports_external.literal(true) });
29449
+ async function withSaveWarnings(workflow) {
29450
+ const warnings = await workflowSaveWarnings(workflow.definition, getExecutorRegistry());
29451
+ return warnings.length > 0 ? { ...workflow, warnings } : workflow;
29452
+ }
28719
29453
  var listWorkflowsRoute = route({
28720
29454
  method: "get",
28721
29455
  path: "/api/workflows",
@@ -28760,7 +29494,7 @@ var createWorkflowRoute = route({
28760
29494
  vcsRepo: exports_external.string().min(1).optional()
28761
29495
  }),
28762
29496
  responses: {
28763
- 201: { description: "Workflow created", schema: WorkflowSchema },
29497
+ 201: { description: "Workflow created", schema: WorkflowSaveResponseSchema },
28764
29498
  400: { description: "Invalid definition" }
28765
29499
  }
28766
29500
  });
@@ -28806,7 +29540,10 @@ var updateWorkflowRoute = route({
28806
29540
  enabled: exports_external.boolean().optional()
28807
29541
  }),
28808
29542
  responses: {
28809
- 200: { description: "Workflow updated (version snapshot created)", schema: WorkflowSchema },
29543
+ 200: {
29544
+ description: "Workflow updated (version snapshot created)",
29545
+ schema: WorkflowSaveResponseSchema
29546
+ },
28810
29547
  400: { description: "Invalid definition" },
28811
29548
  404: { description: "Workflow not found" }
28812
29549
  }
@@ -28820,7 +29557,10 @@ var patchWorkflowRoute = route({
28820
29557
  params: exports_external.object({ id: exports_external.string() }),
28821
29558
  body: WorkflowPatchSchema.extend({ key: AssetKeySchema.optional() }),
28822
29559
  responses: {
28823
- 200: { description: "Workflow patched (version snapshot created)", schema: WorkflowSchema },
29560
+ 200: {
29561
+ description: "Workflow patched (version snapshot created)",
29562
+ schema: WorkflowSaveResponseSchema
29563
+ },
28824
29564
  400: { description: "Invalid patch or resulting definition" },
28825
29565
  404: { description: "Workflow not found" }
28826
29566
  }
@@ -28834,7 +29574,10 @@ var patchWorkflowNodeRoute = route({
28834
29574
  params: exports_external.object({ id: exports_external.string(), nodeId: exports_external.string() }),
28835
29575
  body: WorkflowNodePatchSchema,
28836
29576
  responses: {
28837
- 200: { description: "Node patched (version snapshot created)", schema: WorkflowSchema },
29577
+ 200: {
29578
+ description: "Node patched (version snapshot created)",
29579
+ schema: WorkflowSaveResponseSchema
29580
+ },
28838
29581
  400: { description: "Invalid patch or resulting definition" },
28839
29582
  404: { description: "Workflow or node not found" }
28840
29583
  }
@@ -29114,6 +29857,11 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
29114
29857
  jsonError(res, `Invalid definition: ${validation.errors.join("; ")}`, 400);
29115
29858
  return true;
29116
29859
  }
29860
+ const modelErrors = await workflowModelErrors(parsed.body.definition);
29861
+ if (modelErrors.length > 0) {
29862
+ jsonError(res, `Invalid definition: ${modelErrors.join("; ")}`, 400);
29863
+ return true;
29864
+ }
29117
29865
  const trustedUserId = await resolveHttpAuditUserId(req, myAgentId);
29118
29866
  let key;
29119
29867
  try {
@@ -29142,7 +29890,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
29142
29890
  createdByAgentId: myAgentId ?? undefined,
29143
29891
  createdBy: await resolveHttpAuditUserId(req, myAgentId) ?? undefined
29144
29892
  }, "api");
29145
- createWorkflowRoute.respond(res, 201, workflow);
29893
+ createWorkflowRoute.respond(res, 201, await withSaveWarnings(workflow));
29146
29894
  return true;
29147
29895
  }
29148
29896
  if (getWorkflowRoute.match(req.method, pathSegments)) {
@@ -29187,7 +29935,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
29187
29935
  jsonError(res, result.reason === "patch" ? result.errors.join("; ") : `Invalid definition: ${result.errors.join("; ")}`, 400);
29188
29936
  return true;
29189
29937
  }
29190
- patchWorkflowNodeRoute.respond(res, 200, result.workflow);
29938
+ patchWorkflowNodeRoute.respond(res, 200, await withSaveWarnings(result.workflow));
29191
29939
  return true;
29192
29940
  }
29193
29941
  if (patchWorkflowRoute.match(req.method, pathSegments)) {
@@ -29238,7 +29986,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
29238
29986
  jsonError(res, result.reason === "patch" ? result.errors.join("; ") : `Invalid definition: ${result.errors.join("; ")}`, 400);
29239
29987
  return true;
29240
29988
  }
29241
- patchWorkflowRoute.respond(res, 200, result.workflow);
29989
+ patchWorkflowRoute.respond(res, 200, await withSaveWarnings(result.workflow));
29242
29990
  return true;
29243
29991
  }
29244
29992
  if (updateWorkflowRoute.match(req.method, pathSegments)) {
@@ -29261,6 +30009,11 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
29261
30009
  jsonError(res, `Invalid definition: ${validation.errors.join("; ")}`, 400);
29262
30010
  return true;
29263
30011
  }
30012
+ const modelErrors = await workflowModelErrors(body.definition);
30013
+ if (modelErrors.length > 0) {
30014
+ jsonError(res, `Invalid definition: ${modelErrors.join("; ")}`, 400);
30015
+ return true;
30016
+ }
29264
30017
  }
29265
30018
  const updatedBy2 = await resolveHttpAuditUserId(req, myAgentId) ?? undefined;
29266
30019
  let key;
@@ -29297,7 +30050,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
29297
30050
  res.end();
29298
30051
  return true;
29299
30052
  }
29300
- updateWorkflowRoute.respond(res, 200, workflow);
30053
+ updateWorkflowRoute.respond(res, 200, await withSaveWarnings(workflow));
29301
30054
  return true;
29302
30055
  }
29303
30056
  if (deleteWorkflowRoute.match(req.method, pathSegments)) {
@@ -29850,7 +30603,7 @@ async function shutdown() {
29850
30603
  sessionsProcessed: getServerSessionsProcessed()
29851
30604
  });
29852
30605
  if (hasCapability("scheduling")) {
29853
- const { stopScheduler } = await import("./index-chgdkq36.js");
30606
+ const { stopScheduler } = await import("./index-kkv84jq9.js");
29854
30607
  stopScheduler();
29855
30608
  }
29856
30609
  stopHeartbeat();
@@ -29858,12 +30611,13 @@ async function shutdown() {
29858
30611
  await stopScriptRunSupervisor();
29859
30612
  await stopSlackApp();
29860
30613
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
29861
- const { stopOAuthKeepalive } = await import("./keepalive-vtkf5n99.js");
30614
+ const { stopOAuthKeepalive } = await import("./keepalive-yra8dy57.js");
29862
30615
  await stopOAuthKeepalive();
29863
30616
  }
29864
30617
  stopOAuthPendingGc();
29865
30618
  stopMemoryGc();
29866
30619
  await stopDbRetention();
30620
+ stopHumanFreeDrain();
29867
30621
  stopScratchScriptGc();
29868
30622
  await stopExtensionRuntime();
29869
30623
  stopAuditGc();
@@ -29926,15 +30680,15 @@ try {
29926
30680
  console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
29927
30681
  }
29928
30682
  try {
29929
- const { ensurePricingSeeded } = await import("./boot-seeds-s3q01xj3.js");
30683
+ const { ensurePricingSeeded } = await import("./boot-seeds-gsetbs5y.js");
29930
30684
  ensurePricingSeeded();
29931
- const { startPricingRefreshLoop } = await import("./pricing-refresh-v1cbr9te.js");
30685
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-wx0tp7cb.js");
29932
30686
  startPricingRefreshLoop();
29933
30687
  } catch (err) {
29934
30688
  console.error("[startup] Failed to seed pricing rows:", err);
29935
30689
  }
29936
30690
  try {
29937
- const { ensureRbacSeeded } = await import("./boot-seeds-s3q01xj3.js");
30691
+ const { ensureRbacSeeded } = await import("./boot-seeds-gsetbs5y.js");
29938
30692
  ensureRbacSeeded();
29939
30693
  } catch (err) {
29940
30694
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -29942,7 +30696,7 @@ try {
29942
30696
  throw err;
29943
30697
  }
29944
30698
  try {
29945
- const { runAllSeeders } = await import("./index-a3vn96n8.js");
30699
+ const { runAllSeeders } = await import("./index-zg7vp46x.js");
29946
30700
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
29947
30701
  } catch (err) {
29948
30702
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -29996,36 +30750,37 @@ httpServer.listen(port, async () => {
29996
30750
  await initWorkflows();
29997
30751
  await startScriptRunSupervisor(getMcpBaseUrl());
29998
30752
  if (hasCapability("scheduling")) {
29999
- const { startScheduler } = await import("./index-chgdkq36.js");
30000
- const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-1yks3qcr.js");
30753
+ const { startScheduler } = await import("./index-kkv84jq9.js");
30754
+ const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-fg0dsp6c.js");
30001
30755
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
30002
30756
  startScheduler(getExecutorRegistry2(), intervalMs, {
30003
30757
  runId: globalState.__runId
30004
30758
  });
30005
30759
  }
30006
30760
  if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
30007
- const { startHeartbeat } = await import("./index-x71bvq0p.js");
30761
+ const { startHeartbeat } = await import("./index-668me3f0.js");
30008
30762
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
30009
30763
  startHeartbeat(heartbeatMs);
30010
30764
  }
30011
30765
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
30012
- const { startOAuthKeepalive } = await import("./keepalive-vtkf5n99.js");
30766
+ const { startOAuthKeepalive } = await import("./keepalive-yra8dy57.js");
30013
30767
  startOAuthKeepalive();
30014
30768
  }
30015
30769
  if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
30016
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-qp3dzmdp.js");
30770
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-7rdt1m9n.js");
30017
30771
  startOAuthRefreshSweep();
30018
30772
  }
30019
30773
  startOAuthPendingGc();
30020
30774
  await startMemoryGc();
30021
30775
  await startDbRetention();
30022
- import("./boot-reembed-se8zmdcp.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
30776
+ startHumanFreeDrain();
30777
+ import("./boot-reembed-cqz9swn5.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
30023
30778
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
30024
30779
  });
30025
- import("./boot-reembed-g5ckg9yb.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
30780
+ import("./boot-reembed-m3656j2n.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
30026
30781
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
30027
30782
  });
30028
- import("./boot-scrub-logs-wfxqan61.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
30783
+ import("./boot-scrub-logs-xbxf5d7w.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
30029
30784
  console.error("[boot-scrub-logs] startup scrub failed (non-fatal):", err);
30030
30785
  });
30031
30786
  }).on("error", (err) => {