@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
@@ -17,6 +17,7 @@ import {
17
17
  isExtensionAgent,
18
18
  } from "@/be/db";
19
19
  import { repointTrackerSyncBySwarmId } from "@/be/db-queries/tracker";
20
+ import { explicitModelErrorForAgent } from "@/be/model-validation";
20
21
  import { applyPreTaskCreate } from "@/extensions/apply-task-create";
21
22
  import { checkSlackRoutingCoherence } from "@/tasks/slack-routing";
22
23
  import { findDuplicateTask } from "@/tools/task-dedup";
@@ -131,11 +132,17 @@ export const sendTaskInputSchema = z
131
132
  .min(1)
132
133
  .optional()
133
134
  .describe(
134
- "Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent.",
135
+ "Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent. 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.",
135
136
  ),
136
137
  modelTier: ModelTierSchema.optional().describe(
137
138
  "Portable model tier for this task: 'smol', 'regular', 'smart', or 'ultra'. Resolved at claim/run time using the assignee's harness/provider. Legacy model shortnames map as haiku→smol, sonnet→regular, opus→smart, fable→ultra.",
138
139
  ),
140
+ allowCustomModel: z
141
+ .boolean()
142
+ .optional()
143
+ .describe(
144
+ "Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet (a fresh launch, a private deployment).",
145
+ ),
139
146
  effort: ReasoningEffortSchema.optional().describe(
140
147
  "Reasoning effort for this task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. If omitted, the assignee's REASONING_EFFORT_OVERRIDE/default applies.",
141
148
  ),
@@ -268,6 +275,7 @@ export async function sendTaskHandler(
268
275
  vcsRepo,
269
276
  model,
270
277
  modelTier,
278
+ allowCustomModel,
271
279
  effort,
272
280
  allowDuplicate,
273
281
  slackChannelId,
@@ -380,6 +388,14 @@ export async function sendTaskHandler(
380
388
  effectiveAgentId = effectiveParentTask.agentId;
381
389
  }
382
390
  }
391
+ // Judge the model against the harness that will actually run it, including the
392
+ // parent auto-route target.
393
+ const modelError = await explicitModelErrorForAgent({
394
+ model: normalizedModel.model,
395
+ allowCustomModel,
396
+ agentId: effectiveAgentId,
397
+ });
398
+ if (modelError) return toolErr(modelError, { data: { yourAgentId: creatorAgentId } });
383
399
  const effectiveRoutingReason =
384
400
  agentId !== undefined ? routingReason : effectiveAgentId ? "continuity" : undefined;
385
401
  const effectiveRoutingNote = effectiveRoutingReason ? routingNote : undefined;
@@ -427,6 +443,7 @@ export async function sendTaskHandler(
427
443
  options: requestedTaskOptions,
428
444
  origin: "mcp",
429
445
  requestInfo: ctx.kind === "owner" ? ctx.requestInfo : undefined,
446
+ allowCustomModel,
430
447
  });
431
448
  if (preCreate.kind === "blocked") {
432
449
  return toolErr(preCreate.reason, {
@@ -6,6 +6,7 @@ import {
6
6
  createLogEntry,
7
7
  failTask,
8
8
  getAgentById,
9
+ getAgentCurrentTask,
9
10
  getDbClient,
10
11
  getResolvedConfig,
11
12
  getTaskById,
@@ -21,6 +22,7 @@ import {
21
22
  upsertTaskCitations,
22
23
  } from "@/be/task-citations";
23
24
  import { AgentFsProvider } from "@/fs/agent-fs-provider";
25
+ import { can } from "@/rbac";
24
26
  import { runTaskTerminalEffects } from "@/tasks/task-terminal-effects";
25
27
  import {
26
28
  getTaskOutputValidationError,
@@ -49,6 +51,36 @@ const BLOCKED_WAITING_PATTERN =
49
51
  // noise and calling defer-task buys nothing over checking in again shortly.
50
52
  const BLOCKED_WAITING_MIN_ELAPSED_MS = 3 * 60 * 1000;
51
53
 
54
+ /**
55
+ * Only the assigned agent may write a task's progress, status, or artifacts
56
+ * (`task.progress.write`). Workflow siblings see each other's task ids in
57
+ * their prompt, and a worker once completed a sibling's task with its own
58
+ * report. Leads keep cross-task writes (the task-citations suite pins lead
59
+ * completion of a worker task); unassigned tasks stay writable, matching
60
+ * `POST /api/tasks/:id/finish`. Returns the refusal message, naming the
61
+ * caller's own task so it can retry.
62
+ */
63
+ async function foreignTaskWriteError(
64
+ caller: { id: string; isLead?: boolean },
65
+ task: { id: string; agentId?: string | null },
66
+ sourceTaskId: string | undefined,
67
+ ): Promise<string | undefined> {
68
+ const decision = can({
69
+ principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead === true },
70
+ verb: "task.progress.write",
71
+ resource: { kind: "task", taskId: task.id, agentId: task.agentId },
72
+ source: "mcp",
73
+ });
74
+ if (decision.allow) return undefined;
75
+ const sourceTask = sourceTaskId ? await getTaskById(sourceTaskId) : null;
76
+ const ownTask =
77
+ sourceTask?.agentId === caller.id ? sourceTask : await getAgentCurrentTask(caller.id);
78
+ const retry = ownTask
79
+ ? ` Your own task is "${ownTask.id}"; call store-progress with that taskId.`
80
+ : " You have no in-progress task.";
81
+ return `Task "${task.id}" is assigned to another agent; only its assignee may store progress on it. Nothing was written.${retry}`;
82
+ }
83
+
52
84
  export const storeProgressOutputSchema = swarmToolOutputSchema({
53
85
  // Bounded confirmation only. The handler keeps the full task row internally
54
86
  // for completion memory, raters, and follow-up creation, but never echoes it
@@ -227,14 +259,18 @@ export const registerStoreProgressTool = (server: McpServer) => {
227
259
  // Validate the caller and target before an agent-fs lookup. Otherwise a
228
260
  // forged X-Agent-ID or unknown task could use this tool as a file-existence
229
261
  // oracle through the API-owned agent-fs credential fallback.
230
- if (!(await getAgentById(requestInfo.agentId))) {
262
+ const caller = await getAgentById(requestInfo.agentId);
263
+ if (!caller) {
231
264
  return toolErr(
232
265
  `Agent with ID "${requestInfo.agentId}" not found in the swarm, register before storing task progress.`,
233
266
  );
234
267
  }
235
- if (!(await getTaskById(taskId))) {
268
+ const target = await getTaskById(taskId);
269
+ if (!target) {
236
270
  return toolErr(`Task with ID "${taskId}" not found.`);
237
271
  }
272
+ const foreignError = await foreignTaskWriteError(caller, target, requestInfo.sourceTaskId);
273
+ if (foreignError) return toolErr(foreignError);
238
274
 
239
275
  const configs = await getResolvedConfig(requestInfo.agentId ?? undefined);
240
276
  const configValue = (key: string) => configs.find((c) => c.key === key)?.value?.trim();
@@ -315,6 +351,15 @@ export const registerStoreProgressTool = (server: McpServer) => {
315
351
  };
316
352
  }
317
353
 
354
+ const foreignError = await foreignTaskWriteError(
355
+ agent,
356
+ existingTask,
357
+ requestInfo.sourceTaskId,
358
+ );
359
+ if (foreignError) {
360
+ return { success: false, message: foreignError };
361
+ }
362
+
318
363
  let updatedTask = existingTask;
319
364
  const isTerminal = isTerminalTaskStatus(existingTask.status);
320
365
  // This call's own status can finish the task even though existingTask
@@ -382,8 +427,8 @@ export const registerStoreProgressTool = (server: McpServer) => {
382
427
  }
383
428
  }
384
429
 
385
- // Explicit task IDs retain the existing progress-update policy, but
386
- // only the assigned agent may author sources. Check under the same
430
+ // A lead may update another agent's task (see foreignTaskWriteError),
431
+ // but only the assigned agent may author sources. Check under the same
387
432
  // transaction as the upsert, including for terminal tasks. Ignore an
388
433
  // unauthorized batch so citations never block the task update itself.
389
434
  if (citations?.length && existingTask.agentId === agent.id) {
@@ -27,6 +27,7 @@ import {
27
27
  releaseTask,
28
28
  updateTaskClaudeSessionId,
29
29
  } from "@/be/db";
30
+ import { explicitModelErrorForAgent } from "@/be/model-validation";
30
31
  import { touchRuntimeInstance } from "@/be/multi-runtime";
31
32
  import { applyPreTaskCreate } from "@/extensions/apply-task-create";
32
33
  import { assertOwnsTask, ownerCtx, type ToolCtx } from "@/tools/task-tool-ctx";
@@ -93,11 +94,17 @@ export const taskActionInputSchema = z.object({
93
94
  .min(1)
94
95
  .optional()
95
96
  .describe(
96
- "Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action.",
97
+ "Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action. 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.",
97
98
  ),
98
99
  modelTier: ModelTierSchema.optional().describe(
99
100
  "Portable model tier for the created task: 'smol', 'regular', 'smart', or 'ultra'. Resolved when a worker claims/runs the task. Only used with 'create' action.",
100
101
  ),
102
+ allowCustomModel: z
103
+ .boolean()
104
+ .optional()
105
+ .describe(
106
+ "Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only used with 'create' action.",
107
+ ),
101
108
  effort: ReasoningEffortSchema.optional().describe(
102
109
  "Reasoning effort for the created task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. Only used with 'create' action.",
103
110
  ),
@@ -275,6 +282,11 @@ export async function taskActionHandler(
275
282
  agentId,
276
283
  );
277
284
  }
285
+ const modelError = await explicitModelErrorForAgent({
286
+ model: normalizedModel.model,
287
+ allowCustomModel: input.allowCustomModel,
288
+ });
289
+ if (modelError) return taskActionResult({ success: false, message: modelError }, agentId);
278
290
  try {
279
291
  assetKey = key
280
292
  ? await authorizeAssetKeyWrite(key, await resolveTaskAuditUserId(ctx.sourceTaskId, agentId))
@@ -310,6 +322,7 @@ export async function taskActionHandler(
310
322
  },
311
323
  origin: "mcp",
312
324
  requestInfo: ctx.requestInfo,
325
+ allowCustomModel: input.allowCustomModel,
313
326
  });
314
327
  if (preCreate.kind === "blocked") {
315
328
  return taskActionResult({ success: false, message: preCreate.reason }, agentId);
@@ -78,12 +78,14 @@ export const DEFERRED_TOOLS = new Set([
78
78
  "list-services",
79
79
  "update-service-status",
80
80
 
81
- // Config (5)
81
+ // Config (7)
82
82
  "set-config",
83
83
  "list-config",
84
84
  "delete-config",
85
85
  "credential-bindings",
86
86
  "script-connections",
87
+ "model-catalog-refresh",
88
+ "model-catalog-overlay-upsert",
87
89
 
88
90
  // Repos (1)
89
91
  "update-repo",
@@ -19,6 +19,8 @@ import {
19
19
  } from "@/types";
20
20
  import { getExecutorRegistry } from "@/workflows";
21
21
  import { validateDefinition } from "@/workflows/definition";
22
+ import { workflowModelErrors } from "@/workflows/model-validation";
23
+ import { withSaveWarnings, workflowSaveWarnings } from "@/workflows/readiness";
22
24
 
23
25
  export const registerCreateWorkflowTool = (server: McpServer) => {
24
26
  createToolRegistrar(server)(
@@ -49,7 +51,8 @@ export const registerCreateWorkflowTool = (server: McpServer) => {
49
51
  "- WEBHOOK VERIFICATION: Webhook triggers use hmacSecret for all verification formats. " +
50
52
  "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " +
51
53
  "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " +
52
- "or { format: 'token-equality', header }. Example: { type: 'webhook', hmacSecret: 'secret.SUPERAGENT_WEBHOOK_SECRET', " +
54
+ "{ format: 'token-equality', header }, or { format: 'standard-webhooks', toleranceSeconds? } " +
55
+ "(standardwebhooks.com: webhook-id/webhook-timestamp/webhook-signature headers, hmacSecret is the whsec_ signing secret). Example: { type: 'webhook', hmacSecret: 'secret.SUPERAGENT_WEBHOOK_SECRET', " +
53
56
  "verification: { format: 'timestamped-hmac-sha256', header: 'X-Superagent-Signature', toleranceSeconds: 300 } }.\n" +
54
57
  "- WAIT NODE: type 'wait' pauses a workflow for a duration or until a named workflowEventBus event arrives. " +
55
58
  "See runbooks/workflows.md#wait-nodes for config shapes, ordering caveats, and built-in event names.",
@@ -66,7 +69,7 @@ export const registerCreateWorkflowTool = (server: McpServer) => {
66
69
  .array(TriggerConfigSchema)
67
70
  .optional()
68
71
  .describe(
69
- "Optional trigger configurations (webhook, schedule, event). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality.",
72
+ "Optional trigger configurations (webhook, schedule, event). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality, standard-webhooks.",
70
73
  ),
71
74
  cooldown: CooldownConfigSchema.optional().describe(
72
75
  "Optional cooldown configuration to prevent re-triggering too frequently",
@@ -102,6 +105,7 @@ export const registerCreateWorkflowTool = (server: McpServer) => {
102
105
  outputSchema: swarmToolOutputSchema({
103
106
  yourAgentId: z.string().optional(),
104
107
  workflow: z.unknown().optional(),
108
+ warnings: z.array(z.string()).optional(),
105
109
  }),
106
110
  },
107
111
  async (
@@ -128,6 +132,10 @@ export const registerCreateWorkflowTool = (server: McpServer) => {
128
132
  if (!validation.valid) {
129
133
  return toolErr(`Invalid definition: ${validation.errors.join("; ")}`);
130
134
  }
135
+ const modelErrors = await workflowModelErrors(definition);
136
+ if (modelErrors.length > 0) {
137
+ return toolErr(`Invalid definition: ${modelErrors.join("; ")}`);
138
+ }
131
139
 
132
140
  const createdBy =
133
141
  (await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId)) ??
@@ -152,11 +160,16 @@ export const registerCreateWorkflowTool = (server: McpServer) => {
152
160
  "mcp",
153
161
  );
154
162
  const longScriptTimeoutHint = findLongScriptTimeoutHint(definition.nodes);
155
- return toolOk(`Created workflow "${workflow.name}".`, {
156
- details: `Created workflow "${workflow.name}" (${workflow.id}).`,
163
+ const warnings = await workflowSaveWarnings(workflow.definition, getExecutorRegistry());
164
+ return toolOk(withSaveWarnings(`Created workflow "${workflow.name}".`, warnings), {
165
+ details: withSaveWarnings(
166
+ `Created workflow "${workflow.name}" (${workflow.id}).`,
167
+ warnings,
168
+ ),
157
169
  data: {
158
170
  yourAgentId: requestInfo.agentId,
159
171
  workflow,
172
+ ...(warnings.length > 0 ? { warnings } : {}),
160
173
  ...(longScriptTimeoutHint ? { longScriptTimeoutHint } : {}),
161
174
  },
162
175
  });
@@ -11,6 +11,7 @@ import {
11
11
  import { WorkflowNodePatchSchema } from "@/types";
12
12
  import { getExecutorRegistry } from "@/workflows";
13
13
  import { patchWorkflowDefinition } from "@/workflows/patch-definition";
14
+ import { withSaveWarnings, workflowSaveWarnings } from "@/workflows/readiness";
14
15
 
15
16
  export const registerPatchWorkflowNodeTool = (server: McpServer) => {
16
17
  createToolRegistrar(server)(
@@ -30,6 +31,7 @@ export const registerPatchWorkflowNodeTool = (server: McpServer) => {
30
31
  outputSchema: swarmToolOutputSchema({
31
32
  workflow: z.unknown().optional(),
32
33
  versionCreated: z.number().optional(),
34
+ warnings: z.array(z.string()).optional(),
33
35
  }),
34
36
  },
35
37
  async ({ id, nodeId, ...nodeFields }, requestInfo) => {
@@ -59,14 +61,22 @@ export const registerPatchWorkflowNodeTool = (server: McpServer) => {
59
61
  { id: nodeId, type: patchedNode?.type, config: nodeFields.config },
60
62
  ]);
61
63
 
62
- return toolOk(`Patched node "${nodeId}" in workflow "${workflow.name}".`, {
63
- details: `Patched node "${nodeId}" in workflow "${workflow.name}" (${id}). Version ${version} snapshot created.`,
64
- data: {
65
- workflow,
66
- versionCreated: version ?? undefined,
67
- ...(longScriptTimeoutHint ? { longScriptTimeoutHint } : {}),
64
+ const warnings = await workflowSaveWarnings(result.definition, getExecutorRegistry());
65
+ return toolOk(
66
+ withSaveWarnings(`Patched node "${nodeId}" in workflow "${workflow.name}".`, warnings),
67
+ {
68
+ details: withSaveWarnings(
69
+ `Patched node "${nodeId}" in workflow "${workflow.name}" (${id}). Version ${version} snapshot created.`,
70
+ warnings,
71
+ ),
72
+ data: {
73
+ workflow,
74
+ versionCreated: version ?? undefined,
75
+ ...(warnings.length > 0 ? { warnings } : {}),
76
+ ...(longScriptTimeoutHint ? { longScriptTimeoutHint } : {}),
77
+ },
68
78
  },
69
- });
79
+ );
70
80
  } catch (err) {
71
81
  return toolErr(String(err));
72
82
  }
@@ -14,6 +14,7 @@ import type { WorkflowPatch } from "@/types";
14
14
  import { AssetKeySchema, WorkflowNodePatchSchema } from "@/types";
15
15
  import { getExecutorRegistry } from "@/workflows";
16
16
  import { patchWorkflowDefinition } from "@/workflows/patch-definition";
17
+ import { withSaveWarnings, workflowSaveWarnings } from "@/workflows/readiness";
17
18
 
18
19
  export const registerPatchWorkflowTool = (server: McpServer) => {
19
20
  createToolRegistrar(server)(
@@ -78,6 +79,7 @@ export const registerPatchWorkflowTool = (server: McpServer) => {
78
79
  nodesCreated: z.number().optional(),
79
80
  nodesUpdated: z.number().optional(),
80
81
  nodesDeleted: z.number().optional(),
82
+ warnings: z.array(z.string()).optional(),
81
83
  }),
82
84
  },
83
85
  async ({ id, key, update, delete: del, create, onNodeFailure, triggerSchema }, requestInfo) => {
@@ -133,14 +135,19 @@ export const registerPatchWorkflowTool = (server: McpServer) => {
133
135
  );
134
136
  const longScriptTimeoutHint = findLongScriptTimeoutHint(authoredFinalNodes);
135
137
 
136
- return toolOk(`Patched workflow "${workflow.name}".`, {
137
- details: `Patched workflow "${workflow.name}" (${id}). Version ${version} snapshot created.`,
138
+ const warnings = await workflowSaveWarnings(result.definition, getExecutorRegistry());
139
+ return toolOk(withSaveWarnings(`Patched workflow "${workflow.name}".`, warnings), {
140
+ details: withSaveWarnings(
141
+ `Patched workflow "${workflow.name}" (${id}). Version ${version} snapshot created.`,
142
+ warnings,
143
+ ),
138
144
  data: {
139
145
  workflow,
140
146
  versionCreated: version ?? undefined,
141
147
  nodesCreated: create?.length ?? 0,
142
148
  nodesUpdated: update?.length ?? 0,
143
149
  nodesDeleted: del?.length ?? 0,
150
+ ...(warnings.length > 0 ? { warnings } : {}),
144
151
  ...(longScriptTimeoutHint ? { longScriptTimeoutHint } : {}),
145
152
  },
146
153
  });
@@ -19,6 +19,8 @@ import {
19
19
  } from "@/types";
20
20
  import { getExecutorRegistry } from "@/workflows";
21
21
  import { definitionNodeIds, validateDefinition } from "@/workflows/definition";
22
+ import { workflowModelErrors } from "@/workflows/model-validation";
23
+ import { withSaveWarnings, workflowSaveWarnings } from "@/workflows/readiness";
22
24
  import { snapshotAndUpdateWorkflow } from "@/workflows/version";
23
25
 
24
26
  export const registerUpdateWorkflowTool = (server: McpServer) => {
@@ -36,7 +38,8 @@ export const registerUpdateWorkflowTool = (server: McpServer) => {
36
38
  "WEBHOOK VERIFICATION: webhook triggers use hmacSecret for all verification formats. " +
37
39
  "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " +
38
40
  "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " +
39
- "or { format: 'token-equality', header }.",
41
+ "{ format: 'token-equality', header }, or { format: 'standard-webhooks', toleranceSeconds? } " +
42
+ "(standardwebhooks.com: webhook-id/webhook-timestamp/webhook-signature headers, hmacSecret is the whsec_ signing secret).",
40
43
  inputSchema: z.object({
41
44
  id: z.string().uuid().describe("Workflow ID to update"),
42
45
  key: AssetKeySchema.optional().describe("Move to a logical namespace."),
@@ -47,7 +50,7 @@ export const registerUpdateWorkflowTool = (server: McpServer) => {
47
50
  .array(TriggerConfigSchema)
48
51
  .optional()
49
52
  .describe(
50
- "New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality.",
53
+ "New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality, standard-webhooks.",
51
54
  ),
52
55
  cooldown: CooldownConfigSchema.optional()
53
56
  .nullable()
@@ -84,6 +87,7 @@ export const registerUpdateWorkflowTool = (server: McpServer) => {
84
87
  outputSchema: swarmToolOutputSchema({
85
88
  workflow: z.unknown().optional(),
86
89
  versionCreated: z.number().optional(),
90
+ warnings: z.array(z.string()).optional(),
87
91
  }),
88
92
  },
89
93
  async (
@@ -118,6 +122,10 @@ export const registerUpdateWorkflowTool = (server: McpServer) => {
118
122
  if (!validation.valid) {
119
123
  return toolErr(`Invalid definition: ${validation.errors.join("; ")}`);
120
124
  }
125
+ const modelErrors = await workflowModelErrors(definition);
126
+ if (modelErrors.length > 0) {
127
+ return toolErr(`Invalid definition: ${modelErrors.join("; ")}`);
128
+ }
121
129
  }
122
130
 
123
131
  const updatedBy =
@@ -152,11 +160,16 @@ export const registerUpdateWorkflowTool = (server: McpServer) => {
152
160
  const longScriptTimeoutHint = definition
153
161
  ? findLongScriptTimeoutHint(definition.nodes)
154
162
  : undefined;
155
- return toolOk(`Updated workflow "${workflow.name}".`, {
156
- details: `Updated workflow "${workflow.name}" (${id}). Version ${version.version} snapshot created.`,
163
+ const warnings = await workflowSaveWarnings(workflow.definition, getExecutorRegistry());
164
+ return toolOk(withSaveWarnings(`Updated workflow "${workflow.name}".`, warnings), {
165
+ details: withSaveWarnings(
166
+ `Updated workflow "${workflow.name}" (${id}). Version ${version.version} snapshot created.`,
167
+ warnings,
168
+ ),
157
169
  data: {
158
170
  workflow,
159
171
  versionCreated: version.version,
172
+ ...(warnings.length > 0 ? { warnings } : {}),
160
173
  ...(longScriptTimeoutHint ? { longScriptTimeoutHint } : {}),
161
174
  },
162
175
  });
package/src/types.ts CHANGED
@@ -231,6 +231,25 @@ export function resolveModelTier(opts: {
231
231
  return DEFAULT_MODEL_TIER_MAP[opts.harnessProvider]?.[tier];
232
232
  }
233
233
 
234
+ export type ModelTierOverrides = Partial<Record<string, Partial<Record<ModelTier, string>>>>;
235
+
236
+ /**
237
+ * The worker's own MODEL_TIER_<TIER> / MODEL_TIER_MAP overrides, keyed by its
238
+ * harness provider, in the shape the worker sends on register and poll so the
239
+ * server can apply them at claim time. Values only (model ids), never secrets.
240
+ */
241
+ export function parseWorkerModelTierOverrides(
242
+ env: Record<string, string | undefined>,
243
+ harnessProvider: ProviderName,
244
+ ): ModelTierOverrides {
245
+ const tiers: Partial<Record<ModelTier, string>> = { ...parseTierMapJson(env.MODEL_TIER_MAP) };
246
+ for (const tier of MODEL_TIERS) {
247
+ const direct = env[`MODEL_TIER_${tier.toUpperCase()}`]?.trim();
248
+ if (direct) tiers[tier] = direct;
249
+ }
250
+ return Object.keys(tiers).length > 0 ? { [harnessProvider]: tiers } : {};
251
+ }
252
+
234
253
  export function resolveTaskModelSelection(opts: {
235
254
  model?: string | null;
236
255
  modelTier?: string | null;
@@ -612,6 +631,12 @@ export const AgentTaskSchema = z
612
631
  model: z.string().optional(),
613
632
  modelTier: ModelTierSchema.optional(),
614
633
  effort: ReasoningEffortSchema.optional(),
634
+ // Claim-time model resolution (server-side, see runbooks/model-tiers.md).
635
+ // resolvedModel is what the worker runs; modelSource says which layer won;
636
+ // modelAlias is the `latest:` alias the value came from, when any.
637
+ resolvedModel: z.string().optional(),
638
+ modelSource: z.string().optional(),
639
+ modelAlias: z.string().optional(),
615
640
 
616
641
  // Schedule linking (optional — set when task was created by a schedule).
617
642
  // z.string(): also reachable verbatim from the create-task query param.
@@ -1996,7 +2021,7 @@ export const WorkflowNodeSchema = z
1996
2021
  type: z
1997
2022
  .string()
1998
2023
  .describe(
1999
- "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'",
2024
+ "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'system-one-decision', 'validate', 'property-match'",
2000
2025
  ),
2001
2026
  label: z.string().optional().describe("Human-readable label for UI display"),
2002
2027
  config: z
@@ -2005,6 +2030,7 @@ export const WorkflowNodeSchema = z
2005
2030
  "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. " +
2006
2031
  "For script: { runtime, script, args?, timeout? }. " +
2007
2032
  "For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. " +
2033
+ "For system-one-decision (typed decisions, Jev by default): { provider? ('typesafe' default | 'openrouter' | 'laya'; a literal, never a {{token}}), state, questions: { <id>: { type: 'noul'|'choice'|'score', instructions, criteria? } }, returns: { <id>: { type } }, model? (provider-specific; unset = the provider's default, and laya has none so it sends no model and picks its own checkpoint), timeoutMs?, maxRetries? (0-3), humanReview? { band: { min, max } (0-1, inclusive), approvers: { users?, roles?, policy }, title?, timeout?, notifications? } }; each provider needs its own global secret (TYPESAFE_API_KEY, OPENROUTER_API_KEY, or LAYA_API_KEY; laya also needs the global config LAYA_URL), and a save warns and a run fails before any node executes when one is missing; system-one-decision nodes must not set retry or validation.retry. With humanReview, an answer whose confidence is inside the band waits for a person (human-in-the-loop approval), and next must map ports { approved, rejected?, timeout? }. " +
2008
2034
  "Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. " +
2009
2035
  "SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. " +
2010
2036
  "Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). " +
@@ -2127,6 +2153,8 @@ export interface PatchResult {
2127
2153
 
2128
2154
  // Presets only: Slack-style separate timestamp headers, asymmetric signatures,
2129
2155
  // and generic signature-template DSLs are intentionally out of scope for v1.
2156
+ // `standard-webhooks` follows https://www.standardwebhooks.com/ (symmetric v1 only):
2157
+ // fixed webhook-id / webhook-timestamp / webhook-signature headers, so no `header`.
2130
2158
  export const WebhookVerificationSchema = z.discriminatedUnion("format", [
2131
2159
  z.object({
2132
2160
  format: z.literal("hmac-sha256"),
@@ -2161,6 +2189,15 @@ export const WebhookVerificationSchema = z.discriminatedUnion("format", [
2161
2189
  format: z.literal("token-equality"),
2162
2190
  header: z.string().min(1).describe("Header containing the shared token to compare"),
2163
2191
  }),
2192
+ z.object({
2193
+ format: z.literal("standard-webhooks"),
2194
+ toleranceSeconds: z
2195
+ .number()
2196
+ .int()
2197
+ .positive()
2198
+ .default(300)
2199
+ .describe("Maximum allowed clock skew, in seconds, for the webhook-timestamp header"),
2200
+ }),
2164
2201
  ]);
2165
2202
  export type WebhookVerification = z.infer<typeof WebhookVerificationSchema>;
2166
2203
 
@@ -2412,6 +2449,9 @@ export type AgentTaskSummary = Pick<
2412
2449
  | "scheduleId"
2413
2450
  | "model"
2414
2451
  | "modelTier"
2452
+ | "resolvedModel"
2453
+ | "modelSource"
2454
+ | "modelAlias"
2415
2455
  | "effort"
2416
2456
  | "provider"
2417
2457
  | "requestedByUserId"
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Codex pool auth-failure benching: shared by the runner (classifies and
3
+ * reports failures) and the API (counts them and benches the login).
4
+ *
5
+ * Worker-side code imports this file, so it must never import `src/be/db`
6
+ * or `bun:sqlite`.
7
+ */
8
+
9
+ /** Consecutive auth failures that bench a Codex pool login. */
10
+ export const CODEX_AUTH_FAILURE_BENCH_THRESHOLD = 2;
11
+ /** Bench length. Matches the codex-auth-expiry-watch bench (benchDays = 365). */
12
+ export const CODEX_AUTH_FAILURE_BENCH_MS = 365 * 24 * 60 * 60 * 1000;
13
+ /** KV namespace and key shared with codex-auth-expiry-watch and keep-warm. */
14
+ export const CODEX_AUTH_WATCH_NAMESPACE = "codex-auth-watch";
15
+ export const codexAuthBenchMarkerKey = (keySuffix: string) => `bench:${keySuffix}`;
16
+
17
+ /** Transient `[auth-error]` texts that must not count. */
18
+ const TRANSIENT_AUTH_ERROR_MARKERS = [
19
+ "waiting for the refresh lock",
20
+ "refresh rejected (429",
21
+ "refresh rejected (5",
22
+ "refresh rejected (unknown status",
23
+ "out of credits",
24
+ "no credentials found in config store",
25
+ // Revalidation threw something other than a refresh rejection (lock HTTP,
26
+ // network, or persistence failure). See buildPoolRevalidationFailureReason.
27
+ "not a confirmed auth rejection",
28
+ ];
29
+
30
+ export function isCodexAuthFailureReason(failureReason: string | undefined | null): boolean {
31
+ if (!failureReason || !failureReason.includes("[auth-error]")) return false;
32
+ const lower = failureReason.toLowerCase();
33
+ return !TRANSIENT_AUTH_ERROR_MARKERS.some((m) => lower.includes(m));
34
+ }