@desplega.ai/agent-swarm 1.173.0 → 2.0.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 (432) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-sj2g0m84.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-fegk44gr.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-kfvgbvzy.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-z7zdy9ja.js} +40 -35
  7. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-5c2z0mbe.js} +10 -9
  8. package/dist/{boot-reembed-16rv9843.js → boot-reembed-j8xa181e.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-hnkn3rgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-kwjq4d2z.js} +14 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-9vmvpvgd.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-9jye6cxr.js} +11881 -11472
  15. package/dist/{cli-94b48jhk.js → cli-03gedhng.js} +16 -14
  16. package/dist/{cli-1w0vj3gw.js → cli-1e4b6bzh.js} +7 -7
  17. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  18. package/dist/cli-2m1ktfzz.js +17795 -0
  19. package/dist/{cli-x119kdba.js → cli-3dj8k4vy.js} +1 -1
  20. package/dist/{cli-srqq3gc5.js → cli-3fbmmawm.js} +5 -5
  21. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  22. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  23. package/dist/{cli-42qhyvwx.js → cli-5t4f29ez.js} +3 -3
  24. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  25. package/dist/cli-6cvfxs8r.js +47 -0
  26. package/dist/{cli-0kxf81jj.js → cli-6jyj59nb.js} +2 -2
  27. package/dist/{cli-w1apjecb.js → cli-6razj6t4.js} +2 -2
  28. package/dist/{cli-anzdk0z4.js → cli-74ahz61x.js} +2 -2
  29. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  30. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  31. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  32. package/dist/cli-9traj3dn.js +638 -0
  33. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  34. package/dist/{cli-na2pxe4f.js → cli-apx87jne.js} +2 -2
  35. package/dist/{cli-rfz2ve55.js → cli-bzszjf2p.js} +2855 -862
  36. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  37. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  38. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  39. package/dist/{cli-rfs4vddv.js → cli-d5f9ed5c.js} +5 -5
  40. package/dist/cli-e3g5mbkz.js +776 -0
  41. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  42. package/dist/{cli-7a93cv8c.js → cli-ee9gtz70.js} +98 -23
  43. package/dist/{cli-3nxdmjrc.js → cli-eejsgvm4.js} +4 -4
  44. package/dist/{cli-fmhj1ehj.js → cli-ef1hg1wv.js} +470 -51
  45. package/dist/cli-f527ce74.js +781 -0
  46. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  47. package/dist/cli-hjwmhcg1.js +10622 -0
  48. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  49. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  50. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  51. package/dist/{cli-s8z6x4b4.js → cli-j0pfptdp.js} +218 -102
  52. package/dist/cli-jta2eyzc.js +619 -0
  53. package/dist/{cli-5er5gjbm.js → cli-k382tshb.js} +10 -11
  54. package/dist/{cli-v3zhnxsb.js → cli-k3dp5tpf.js} +2 -2
  55. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  56. package/dist/cli-kceah1eh.js +92 -0
  57. package/dist/{cli-ne7smj1b.js → cli-ke896fcf.js} +10 -10
  58. package/dist/{cli-xc7p7s3g.js → cli-kt6zqg0e.js} +6 -6
  59. package/dist/{cli-wrh08zjd.js → cli-m50t4309.js} +5 -18
  60. package/dist/cli-n2wq4j7m.js +6985 -0
  61. package/dist/{cli-bv2etw2y.js → cli-n3hzg89b.js} +46 -15
  62. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  63. package/dist/{cli-qm1448f9.js → cli-ne236afy.js} +8 -8
  64. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  65. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  66. package/dist/{cli-0a7mm3zp.js → cli-q0ke1yww.js} +25 -21
  67. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  68. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  69. package/dist/{cli-phcqp1b9.js → cli-r2pnvj8g.js} +2 -2
  70. package/dist/{cli-jpc4r224.js → cli-r62a35ea.js} +19 -3
  71. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  72. package/dist/cli-rhs9pz33.js +294 -0
  73. package/dist/{cli-r4fqfpwf.js → cli-s2sp957d.js} +50 -27
  74. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  75. package/dist/{cli-6thk4jz3.js → cli-se8w6wny.js} +6 -6
  76. package/dist/cli-skxvvpap.js +10140 -0
  77. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  78. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  79. package/dist/{cli-nwrdx840.js → cli-tr4sxp68.js} +3 -3
  80. package/dist/{cli-r0byd61h.js → cli-tsde1hdr.js} +15 -15
  81. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  82. package/dist/{cli-6r2f7edk.js → cli-v1yb0rqb.js} +6 -6
  83. package/dist/{cli-saqyage0.js → cli-vatyhshy.js} +179 -27
  84. package/dist/{cli-5wpw4rab.js → cli-vdach5a9.js} +5 -5
  85. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  86. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  87. package/dist/{cli-c3rk1v0x.js → cli-wayw93nt.js} +3 -3
  88. package/dist/cli-wmgrkscj.js +23254 -0
  89. package/dist/{cli-9xf7fdtp.js → cli-z5jjpaxw.js} +29 -6
  90. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  91. package/dist/cli.js +29 -45
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-y81sssk0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-8vx4j6a9.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-kcpvpcrr.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-kwpvj3rf.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  99. package/dist/{db-yyhqqrbf.js → db-k8ankj20.js} +12 -11
  100. package/dist/{db-qfpq4bt7.js → db-ww5d7jq3.js} +28 -9
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-e8gq5m68.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-3epjm3af.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-h3359cwn.js} +11 -10
  109. package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
  110. package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
  111. package/dist/{grok-adapter-e7mr287e.js → grok-adapter-0d4x7gkx.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-an1gzv21.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-6dakeb61.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-6v6cv6d5.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-sa5xye4y.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r7f3eky0.js} +1499 -251
  117. package/dist/index-52j1aja4.js +3465 -0
  118. package/dist/{index-fx3jqq1e.js → index-7ep4gzdk.js} +38 -33
  119. package/dist/index-9gw58n4k.js +193 -0
  120. package/dist/index-9j87mcm8.js +56305 -0
  121. package/dist/index-bsmcresk.js +79424 -0
  122. package/dist/index-mh85qhec.js +475 -0
  123. package/dist/{index-g2byveez.js → index-rmpw9a8q.js} +38 -33
  124. package/dist/{index-2ybk7khy.js → index-s2wxgzr0.js} +468 -683
  125. package/dist/{index-bdsqa799.js → index-v1v6n7hg.js} +43 -38
  126. package/dist/index-we27kd31.js +12810 -0
  127. package/dist/{index-jd7sejm2.js → index-zk96aq1k.js} +10 -9
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-be9vwy5h.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-0861cwrf.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-mzzgc8bn.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-cpdnfwdj.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-fh8qs4r3.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-nm42wwj8.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-x6c1c9g4.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-9n2ya240.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-qb0rv0ap.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-1gzdwbh1.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-3mraey52.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-agpa45zz.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-x0ydy9s9.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-as9ga0d6.js} +2 -2
  144. package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
  145. package/dist/{work-objects-wpj8ck95.js → work-objects-y5g1y7ev.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-860c3e38.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  148. package/openapi.json +523 -344
  149. package/package.json +10 -11
  150. package/src/be/config-refs.ts +60 -0
  151. package/src/be/db/page-versions.ts +15 -0
  152. package/src/be/db/runtime.ts +35 -8
  153. package/src/be/db/skill-name-resolution.ts +36 -0
  154. package/src/be/db/tasks/read.ts +230 -0
  155. package/src/be/db/tasks/write.ts +7 -0
  156. package/src/be/db.ts +52 -7
  157. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  158. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  159. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  160. package/src/be/model-catalog-store.ts +5 -1
  161. package/src/be/model-tier-resolution.ts +12 -1
  162. package/src/be/model-validation.ts +5 -2
  163. package/src/be/models-catalog.ts +26 -1
  164. package/src/be/modelsdev-cache.json +198 -63
  165. package/src/be/modelsdev-cache.ts +9 -1
  166. package/src/be/script-credential-broker.ts +39 -2
  167. package/src/be/scripts/run-saved.ts +1 -0
  168. package/src/be/scripts/typecheck.ts +10 -8
  169. package/src/be/seed/runner.ts +13 -1
  170. package/src/be/seed/state-db.ts +5 -0
  171. package/src/be/seed/types.ts +6 -0
  172. package/src/be/seed-pricing.ts +19 -2
  173. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  174. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  175. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  176. package/src/be/seed-skills/index.ts +104 -3
  177. package/src/be/swarm-config-guard.ts +52 -0
  178. package/src/cli.tsx +0 -16
  179. package/src/commands/onboard/non-interactive.ts +4 -2
  180. package/src/commands/provider-credentials.ts +52 -6
  181. package/src/commands/runner.ts +190 -54
  182. package/src/e2b/env.ts +5 -0
  183. package/src/extensions/contract-types.generated.ts +1 -1
  184. package/src/extensions/contract.ts +45 -0
  185. package/src/extensions/dispatcher.ts +7 -0
  186. package/src/extensions/post-bridge.ts +40 -0
  187. package/src/github/handlers.ts +11 -4
  188. package/src/heartbeat/templates.ts +8 -5
  189. package/src/hooks/hook.ts +0 -26
  190. package/src/http/all-routes.ts +0 -1
  191. package/src/http/config.ts +36 -17
  192. package/src/http/core.ts +4 -0
  193. package/src/http/index.ts +14 -2
  194. package/src/http/integrations.ts +88 -1
  195. package/src/http/mcp.ts +15 -5
  196. package/src/http/page-proxy.ts +2 -4
  197. package/src/http/pages-public.ts +3 -3
  198. package/src/http/pages.ts +3 -13
  199. package/src/http/poll.ts +28 -68
  200. package/src/http/requested-by.ts +54 -0
  201. package/src/http/scripts.ts +1 -0
  202. package/src/http/stats.ts +1 -30
  203. package/src/http/tasks.ts +61 -5
  204. package/src/http/utils.ts +14 -0
  205. package/src/http/webhooks.ts +159 -1
  206. package/src/http/x.ts +1 -0
  207. package/src/integrations/chat-sdk/adapters.ts +129 -0
  208. package/src/integrations/chat-sdk/attachments.ts +232 -0
  209. package/src/integrations/chat-sdk/background.ts +36 -0
  210. package/src/integrations/chat-sdk/commands.ts +194 -0
  211. package/src/integrations/chat-sdk/config.ts +198 -0
  212. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  213. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  214. package/src/integrations/chat-sdk/handlers.ts +28 -0
  215. package/src/integrations/chat-sdk/inbound.ts +426 -0
  216. package/src/integrations/chat-sdk/limits.ts +48 -0
  217. package/src/integrations/chat-sdk/logger.ts +81 -0
  218. package/src/integrations/chat-sdk/outbound.ts +123 -0
  219. package/src/integrations/chat-sdk/relay.ts +172 -0
  220. package/src/integrations/chat-sdk/router.ts +169 -0
  221. package/src/integrations/chat-sdk/runtime.ts +351 -0
  222. package/src/integrations/chat-sdk/schema.ts +245 -0
  223. package/src/integrations/chat-sdk/state.ts +243 -0
  224. package/src/integrations/chat-sdk/status.ts +244 -0
  225. package/src/integrations/chat-sdk/steering.ts +58 -0
  226. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  227. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  228. package/src/integrations/chat-sdk/templates.ts +16 -0
  229. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  230. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  231. package/src/integrations/chat-sdk/typing.ts +65 -0
  232. package/src/pages/version.ts +4 -5
  233. package/src/prompts/base-prompt.ts +111 -45
  234. package/src/providers/acp-target-catalog.ts +6 -0
  235. package/src/providers/acp-targets.ts +55 -2
  236. package/src/providers/amp-adapter.ts +1 -1
  237. package/src/providers/claude-adapter.ts +1 -1
  238. package/src/providers/claude-flag-settings.ts +17 -5
  239. package/src/providers/claude-managed-adapter.ts +1 -1
  240. package/src/providers/claude-session-events.ts +6 -1
  241. package/src/providers/dsh-adapter.ts +1 -1
  242. package/src/providers/opencode-adapter.ts +243 -26
  243. package/src/providers/opencode-swarm-plugin.ts +31 -0
  244. package/src/providers/pi-mono-adapter.ts +398 -153
  245. package/src/providers/pricing-sources.md +33 -2
  246. package/src/providers/reasoning-effort.ts +27 -0
  247. package/src/providers/types.ts +6 -2
  248. package/src/rbac/legacy-policy.ts +8 -2
  249. package/src/rbac/permissions.ts +21 -0
  250. package/src/scheduler/scheduler.ts +4 -2
  251. package/src/scripts-runtime/loader.ts +19 -7
  252. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  253. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  254. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  255. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  256. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  257. package/src/server.ts +52 -18
  258. package/src/slack/event-dedup.ts +1 -1
  259. package/src/tasks/additive-buffer.ts +4 -2
  260. package/src/tasks/context-key.ts +60 -1
  261. package/src/tasks/model-pin.ts +67 -0
  262. package/src/tasks/worker-follow-up.ts +4 -31
  263. package/src/tests/acp-adapter.test.ts +42 -0
  264. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  265. package/src/tests/base-prompt.test.ts +58 -54
  266. package/src/tests/chat-sdk-commands.test.ts +191 -0
  267. package/src/tests/chat-sdk-config.test.ts +334 -0
  268. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  269. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  270. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  271. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  272. package/src/tests/chat-sdk-harness.ts +146 -0
  273. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  274. package/src/tests/chat-sdk-relay.test.ts +470 -0
  275. package/src/tests/chat-sdk-reload.test.ts +128 -0
  276. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  277. package/src/tests/chat-sdk-slack.test.ts +268 -0
  278. package/src/tests/chat-sdk-state.test.ts +163 -0
  279. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  280. package/src/tests/chat-sdk-teams.test.ts +277 -0
  281. package/src/tests/chat-sdk-tools.test.ts +520 -0
  282. package/src/tests/chat-sdk-typing.test.ts +120 -0
  283. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  284. package/src/tests/claude-adapter-binary.test.ts +9 -4
  285. package/src/tests/claude-flag-settings.test.ts +11 -3
  286. package/src/tests/claude-managed-adapter.test.ts +1 -1
  287. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  288. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  289. package/src/tests/claude-worker-parity.test.ts +2 -7
  290. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  291. package/src/tests/config-refs.test.ts +66 -0
  292. package/src/tests/context-key.test.ts +19 -0
  293. package/src/tests/cors-allowlist.test.ts +25 -0
  294. package/src/tests/create-page-tool.test.ts +18 -0
  295. package/src/tests/credential-check.test.ts +139 -0
  296. package/src/tests/credentials.test.ts +21 -0
  297. package/src/tests/db-runtime.test.ts +61 -0
  298. package/src/tests/db-task-read-contract.test.ts +20 -0
  299. package/src/tests/db-task-write-contract.test.ts +10 -0
  300. package/src/tests/docs-index-footprint.test.js +3 -3
  301. package/src/tests/dsh-adapter.test.ts +1 -1
  302. package/src/tests/enabled-capabilities.test.ts +20 -0
  303. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  304. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  305. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  306. package/src/tests/explicit-model-validation.test.ts +105 -1
  307. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  308. package/src/tests/extensions-post-bridge.test.ts +51 -0
  309. package/src/tests/fetch-resolved-env.test.ts +128 -0
  310. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  311. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  312. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  313. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  314. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  315. package/src/tests/github-handlers.test.ts +35 -0
  316. package/src/tests/harness-provider-resolution.test.ts +12 -0
  317. package/src/tests/heartbeat-checklist.test.ts +3 -2
  318. package/src/tests/hook-runtime-close.test.ts +0 -2
  319. package/src/tests/http-api-integration.test.ts +0 -25
  320. package/src/tests/migration-046-budgets.test.ts +17 -16
  321. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  322. package/src/tests/model-tier-resolution.test.ts +93 -0
  323. package/src/tests/models-catalog.test.ts +42 -1
  324. package/src/tests/openai-compatible-providers.test.ts +134 -0
  325. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  326. package/src/tests/opencode-adapter.test.ts +216 -2
  327. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  328. package/src/tests/opencode-shell-env.test.ts +145 -0
  329. package/src/tests/openrouter-base-url.test.ts +101 -151
  330. package/src/tests/page-proxy.test.ts +1 -1
  331. package/src/tests/pages-browser-sdk.test.ts +76 -0
  332. package/src/tests/pages-feedback.test.ts +1 -1
  333. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  334. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  335. package/src/tests/pi-mono-adapter.test.ts +385 -5
  336. package/src/tests/pi-shell-env.test.ts +170 -0
  337. package/src/tests/prompt-template-remaining.test.ts +35 -0
  338. package/src/tests/rbac-engine.test.ts +11 -3
  339. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  340. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  341. package/src/tests/script-connections.test.ts +2 -0
  342. package/src/tests/scripts-http.test.ts +201 -1
  343. package/src/tests/scripts-only-gating.test.ts +2 -3
  344. package/src/tests/scripts-runtime.test.ts +58 -40
  345. package/src/tests/secret-scrubber.test.ts +86 -0
  346. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  347. package/src/tests/seed-skills-retire.test.ts +182 -0
  348. package/src/tests/send-task-requester-gate.test.ts +58 -0
  349. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  350. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  351. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  352. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  353. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  354. package/src/tests/swarm-diff.test.ts +1 -1
  355. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  356. package/src/tests/task-session-prompts.test.ts +132 -0
  357. package/src/tests/task-tool-manifest.test.ts +14 -0
  358. package/src/tests/task-tools-ctx.test.ts +2 -0
  359. package/src/tests/tool-annotations.test.ts +6 -6
  360. package/src/tests/ui-logs-parser.test.ts +43 -0
  361. package/src/tests/used-by-route.test.ts +6 -0
  362. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  363. package/src/tests/workflow-swarm-script.test.ts +38 -0
  364. package/src/tests/workflow-wait-filter.test.ts +5 -3
  365. package/src/tools/chat-access.ts +41 -0
  366. package/src/tools/chat-open-dm.ts +59 -0
  367. package/src/tools/chat-post.ts +74 -0
  368. package/src/tools/chat-read-thread.ts +100 -0
  369. package/src/tools/chat-reply.ts +75 -0
  370. package/src/tools/create-page.ts +3 -13
  371. package/src/tools/model-catalog/index.ts +2 -1
  372. package/src/tools/register-chat-channel.ts +139 -0
  373. package/src/tools/send-task.ts +24 -0
  374. package/src/tools/skills/skill-get.ts +17 -9
  375. package/src/tools/swarm-config/get-config.ts +2 -1
  376. package/src/tools/swarm-config/list-config.ts +2 -1
  377. package/src/tools/swarm-config/set-config.ts +16 -3
  378. package/src/tools/tool-config.ts +8 -6
  379. package/src/types.ts +12 -2
  380. package/src/utils/config-env-export.ts +74 -0
  381. package/src/utils/credentials.test.ts +92 -0
  382. package/src/utils/credentials.ts +52 -4
  383. package/src/utils/harness-provider.ts +15 -6
  384. package/src/utils/runtime-model-catalog.ts +11 -1
  385. package/src/utils/secret-scrubber.ts +71 -2
  386. package/src/utils/task-tool-manifest.ts +19 -2
  387. package/src/workflows/executors/swarm-script.ts +1 -0
  388. package/templates/skills/agent-browser/SKILL.md +1 -1
  389. package/templates/skills/agent-browser/content.md +1 -1
  390. package/templates/skills/apps/SKILL.md +8 -1
  391. package/templates/skills/apps/content.md +8 -1
  392. package/templates/skills/chat-sdk/config.json +14 -0
  393. package/templates/skills/chat-sdk/content.md +84 -0
  394. package/templates/skills/composio-gmail/content.md +7 -0
  395. package/templates/skills/composio-google-docs/content.md +1 -1
  396. package/templates/skills/email-domain-health/config.json +14 -0
  397. package/templates/skills/email-domain-health/content.md +131 -0
  398. package/templates/skills/kv-storage/content.md +2 -2
  399. package/templates/skills/pages/content.md +8 -10
  400. package/templates/skills/swarm-extensions/content.md +2 -0
  401. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  402. package/templates/skills/swarm-scripts/config.json +1 -1
  403. package/templates/skills/swarm-scripts/content.md +4 -2
  404. package/templates/skills/workflow-iterate/content.md +38 -0
  405. package/dist/artifact-eczsknc3.js +0 -3843
  406. package/dist/cli-bd957dgb.js +0 -153
  407. package/dist/cli-q51yprfq.js +0 -1104
  408. package/dist/cli-t1ze64h3.js +0 -811
  409. package/dist/cli-tcc4wd5d.js +0 -56471
  410. package/dist/index-9ch1n761.js +0 -1102
  411. package/src/artifact-sdk/index.ts +0 -2
  412. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  413. package/src/artifact-sdk/port.ts +0 -12
  414. package/src/artifact-sdk/server.ts +0 -183
  415. package/src/artifact-sdk/tunnel.ts +0 -19
  416. package/src/commands/artifact.ts +0 -249
  417. package/src/http/ecosystem.ts +0 -77
  418. package/src/tests/artifact-commands.test.ts +0 -92
  419. package/src/tests/artifact-sdk.test.ts +0 -793
  420. package/src/tests/register-service-security.test.ts +0 -194
  421. package/src/tools/list-services.ts +0 -107
  422. package/src/tools/register-service.ts +0 -177
  423. package/src/tools/unregister-service.ts +0 -73
  424. package/src/tools/update-service-status.ts +0 -96
  425. package/templates/skills/artifacts/config.json +0 -14
  426. package/templates/skills/artifacts/content.md +0 -344
  427. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  428. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  429. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  430. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  431. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  432. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
package/src/be/db.ts CHANGED
@@ -136,6 +136,12 @@ import {
136
136
  CODEX_AUTH_WATCH_NAMESPACE,
137
137
  codexAuthBenchMarkerKey,
138
138
  } from "../utils/codex-auth-failure";
139
+ import {
140
+ defaultExportToEnv,
141
+ effectiveExportToEnv,
142
+ envExportRestrictedError,
143
+ isEnvExportRestrictedKey,
144
+ } from "../utils/config-env-export";
139
145
  import { MASKED_SECRET_VALUE } from "../utils/config-secrets";
140
146
  import { deriveProviderFromKeyType } from "../utils/credentials";
141
147
  import type { RateLimitWindowTelemetry } from "../utils/error-tracker";
@@ -205,7 +211,12 @@ import { scrubJsonValue } from "./scrub-json";
205
211
  import { openSealedJson, sealedJsonForDisplay, sealJson } from "./sealed-json";
206
212
  import { configSecretName, registerStoredSecret } from "./secret-registry";
207
213
  import { promotePendingSteeringForTask } from "./steering";
208
- import { isInternalConfigKey, isReservedConfigKey, reservedKeyError } from "./swarm-config-guard";
214
+ import {
215
+ isInternalConfigKey,
216
+ isReservedConfigKey,
217
+ reservedKeyError,
218
+ teamsSdkEnvKeysSql,
219
+ } from "./swarm-config-guard";
209
220
  import { emitTaskStarted } from "./task-lifecycle-events";
210
221
  import { publishWorkerConfigNudge, publishWorkerNudge } from "./worker-nudges";
211
222
  import { defineWorkflowPayload, type WorkflowPayloadView } from "./workflow-replay";
@@ -292,17 +303,21 @@ export {
292
303
  findTaskByGitHub,
293
304
  findTaskByVcs,
294
305
  getAgentCurrentTask,
306
+ getAgentWorkingOnContextKey,
295
307
  getAgentWorkingOnThread,
296
308
  getAllTasks,
297
309
  getChildTasks,
298
310
  getCompletedSlackTasks,
299
311
  getInProgressSlackTasks,
300
312
  getInProgressTasksByContextKey,
313
+ getLatestActiveTaskByContextKey,
301
314
  getLatestActiveTaskInThread,
315
+ getLatestLeadTaskByContextKey,
302
316
  getLatestLeadTaskInThread,
303
317
  getLatestScriptRunStepTaskByContextKey,
304
318
  getLatestTaskByContextKey,
305
319
  getMostRecentTaskInThread,
320
+ getPendingChatRelayTasks,
306
321
  getPendingSlackRelayTasks,
307
322
  getRecentlyFinishedWorkerTasks,
308
323
  getSlackTasksMissingTree,
@@ -313,13 +328,19 @@ export {
313
328
  getTasksByAgentId,
314
329
  getTasksByStatus,
315
330
  getTasksCount,
331
+ giveUpStaleChatRelays,
316
332
  hasNonTerminalRerouteDecisionChild,
317
333
  hasNonTerminalResumeChild,
318
334
  isLinearTrackerContextKey,
335
+ markChatRelayAttempted,
336
+ markChatRelayDelivered,
337
+ markChatRelayGivenUp,
319
338
  markFinalizedSlackRelaysDelivered,
320
339
  markSlackRelayAttempted,
321
340
  markSlackRelayDelivered,
322
341
  markTasksNotified,
342
+ type PendingChatRelay,
343
+ recordChatRelayError,
323
344
  resetTasksNotified,
324
345
  type TaskFilters,
325
346
  } from "./db/tasks/read";
@@ -4375,7 +4396,8 @@ export async function releaseStaleMentionProcessing(timeoutMinutes: number = 30)
4375
4396
  }
4376
4397
 
4377
4398
  // ============================================================================
4378
- // Service Operations (PM2/background services)
4399
+ // Service Operations (removed PM2 service registry; the table and these
4400
+ // accessors stay until a drop migration lands)
4379
4401
  // ============================================================================
4380
4402
 
4381
4403
  type ServiceRow = {
@@ -6342,6 +6364,7 @@ type SwarmConfigRow = {
6342
6364
  createdAt: string;
6343
6365
  lastUpdatedAt: string;
6344
6366
  encrypted: number; // SQLite boolean: 0 = plaintext, 1 = AES-256-GCM ciphertext
6367
+ exportToEnv?: number; // SQLite boolean; absent only on pre-215 test schemas
6345
6368
  };
6346
6369
 
6347
6370
  type SwarmConfigLookupRow = {
@@ -6370,6 +6393,7 @@ function rowToSwarmConfig(row: SwarmConfigRow): SwarmConfig {
6370
6393
  createdAt: row.createdAt,
6371
6394
  lastUpdatedAt: row.lastUpdatedAt,
6372
6395
  encrypted: isEncrypted,
6396
+ exportToEnv: effectiveExportToEnv(row.key, row.exportToEnv !== 0),
6373
6397
  };
6374
6398
  }
6375
6399
 
@@ -6396,6 +6420,7 @@ function rowToSwarmConfig(row: SwarmConfigRow): SwarmConfig {
6396
6420
  createdAt: row.createdAt,
6397
6421
  lastUpdatedAt: row.lastUpdatedAt,
6398
6422
  encrypted: isEncrypted,
6423
+ exportToEnv: effectiveExportToEnv(row.key, row.exportToEnv !== 0),
6399
6424
  };
6400
6425
  }
6401
6426
 
@@ -6550,7 +6575,7 @@ export async function getInjectableGlobalConfigs(): Promise<SwarmConfig[]> {
6550
6575
  const rows = await getDbClient().query<SwarmConfigRow>(
6551
6576
  `SELECT * FROM swarm_config
6552
6577
  WHERE scope = 'global'
6553
- AND UPPER(key) NOT IN ('API_KEY', 'SECRETS_ENCRYPTION_KEY', 'CORS_ALLOW_ANY_ORIGIN', 'EXTENSION_ALLOW_LEAD_ACTIVATION')
6578
+ AND UPPER(key) NOT IN ('API_KEY', 'SECRETS_ENCRYPTION_KEY', 'CORS_ALLOW_ANY_ORIGIN', 'EXTENSION_ALLOW_LEAD_ACTIVATION', 'CHAT_SDK_API_URL_OVERRIDES', ${teamsSdkEnvKeysSql()})
6554
6579
  ORDER BY key ASC`,
6555
6580
  );
6556
6581
  return rows.filter((row) => !isInternalConfigKey(row.key)).map(rowToSwarmConfig);
@@ -6604,10 +6629,16 @@ export async function upsertSwarmConfig(data: {
6604
6629
  isSecret?: boolean;
6605
6630
  envPath?: string | null;
6606
6631
  description?: string | null;
6632
+ /** Omitted: an update keeps the stored flag; an insert uses `defaultExportToEnv`. */
6633
+ exportToEnv?: boolean;
6607
6634
  }): Promise<SwarmConfig> {
6608
6635
  if (isReservedConfigKey(data.key)) {
6609
6636
  throw reservedKeyError(data.key);
6610
6637
  }
6638
+ if (data.exportToEnv === true && isEnvExportRestrictedKey(data.key)) {
6639
+ throw new Error(envExportRestrictedError(data.key));
6640
+ }
6641
+ const restricted = isEnvExportRestrictedKey(data.key);
6611
6642
 
6612
6643
  const now = new Date().toISOString();
6613
6644
  const scopeId = data.scope === "global" ? null : (data.scopeId ?? null);
@@ -6641,17 +6672,30 @@ export async function upsertSwarmConfig(data: {
6641
6672
  );
6642
6673
 
6643
6674
  if (existing) {
6675
+ // COALESCE keeps the stored flag when the caller did not send one.
6644
6676
  return await getDbClient().get<SwarmConfigRow>(
6645
- `UPDATE swarm_config SET value = ?, isSecret = ?, envPath = ?, description = ?, encrypted = ?, lastUpdatedAt = ?
6677
+ `UPDATE swarm_config SET value = ?, isSecret = ?, envPath = ?, description = ?, encrypted = ?, lastUpdatedAt = ?,
6678
+ exportToEnv = CASE WHEN ? THEN 0 ELSE COALESCE(?, exportToEnv) END
6646
6679
  WHERE id = ? RETURNING *`,
6647
- [storedValue, isSecret, envPath, description, encryptedFlag, now, existing.id],
6680
+ [
6681
+ storedValue,
6682
+ isSecret,
6683
+ envPath,
6684
+ description,
6685
+ encryptedFlag,
6686
+ now,
6687
+ restricted ? 1 : 0,
6688
+ data.exportToEnv === undefined ? null : data.exportToEnv ? 1 : 0,
6689
+ existing.id,
6690
+ ],
6648
6691
  );
6649
6692
  }
6650
6693
 
6651
6694
  const id = crypto.randomUUID();
6695
+ const exportToEnv = restricted ? 0 : (data.exportToEnv ?? defaultExportToEnv(data.key)) ? 1 : 0;
6652
6696
  return await getDbClient().get<SwarmConfigRow>(
6653
- `INSERT INTO swarm_config (id, scope, scopeId, key, value, isSecret, envPath, description, createdAt, lastUpdatedAt, encrypted)
6654
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
6697
+ `INSERT INTO swarm_config (id, scope, scopeId, key, value, isSecret, envPath, description, createdAt, lastUpdatedAt, encrypted, exportToEnv)
6698
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
6655
6699
  [
6656
6700
  id,
6657
6701
  data.scope,
@@ -6664,6 +6708,7 @@ export async function upsertSwarmConfig(data: {
6664
6708
  now,
6665
6709
  now,
6666
6710
  encryptedFlag,
6711
+ exportToEnv,
6667
6712
  ],
6668
6713
  );
6669
6714
  });
@@ -0,0 +1,34 @@
1
+ -- Per-row flag: does this swarm_config row reach an agent's process env?
2
+ -- Workers export a row into the harness env (and so into every agent shell)
3
+ -- only when exportToEnv = 1. Rows with 0 stay server-side and are used through
4
+ -- connections or script credential bindings.
5
+ --
6
+ -- Existing rows keep today's behaviour (exported), so nothing breaks at deploy.
7
+ ALTER TABLE swarm_config ADD COLUMN exportToEnv INTEGER NOT NULL DEFAULT 1;
8
+
9
+ -- Deny list: rows only the API server reads. The first block matches
10
+ -- ENV_EXPORT_RESTRICTED_KEYS in src/utils/config-env-export.ts (never
11
+ -- exportable); the second block (ENV_EXPORT_DEFAULT_OFF_KEYS, also the insert
12
+ -- default for new rows) is off by default but operators may turn it
13
+ -- back on per row.
14
+ UPDATE swarm_config SET exportToEnv = 0
15
+ WHERE upper(key) IN (
16
+ 'SLACK_APP_TOKEN',
17
+ 'SLACK_SIGNING_SECRET',
18
+ 'GITHUB_APP_PRIVATE_KEY',
19
+ 'GITHUB_WEBHOOK_SECRET',
20
+ 'GITLAB_WEBHOOK_SECRET',
21
+ 'LINEAR_CLIENT_SECRET',
22
+ 'LINEAR_SIGNING_SECRET',
23
+ 'JIRA_CLIENT_SECRET',
24
+ 'JIRA_WEBHOOK_TOKEN',
25
+ 'AZURE_DEVOPS_WEBHOOK_SECRET',
26
+ 'AGENTMAIL_WEBHOOK_SECRET',
27
+ 'API_AGENT_FS_API_KEY',
28
+ 'KAPSO_WEBHOOK_HMAC_SECRET',
29
+ 'SENTRY_TEST_APP_WEBHOOK_SECRET',
30
+ 'TELEMETRY_CH_AUTH',
31
+ 'HACK_AGENT_FS_ADMIN_KEY',
32
+ 'X_CLIENT_SECRET'
33
+ )
34
+ OR key GLOB 'connection.*.secret';
@@ -0,0 +1,5 @@
1
+ -- The reasoning effort a task's session actually ran at. `effort` stays the
2
+ -- requested value (a task-level pin); the effective one usually comes from the
3
+ -- agent's REASONING_EFFORT_OVERRIDE and was never recorded. NULL means the
4
+ -- harness default applied, or the row predates this column.
5
+ ALTER TABLE agent_tasks ADD COLUMN resolvedEffort TEXT;
@@ -0,0 +1,104 @@
1
+ -- Chat SDK (chat-sdk.dev) channel: StateAdapter tables + durable outbound relay.
2
+ --
3
+ -- The five chat_* state tables back `SqliteChatState` (src/integrations/chat-sdk/state.ts).
4
+ -- Keys and thread ids written by the SDK already carry the adapter prefix
5
+ -- (`telegram:...`, `slack:...`), so no adapter column is needed.
6
+ -- Expiry columns are epoch milliseconds; NULL means no expiry.
7
+
8
+ CREATE TABLE chat_state_kv (
9
+ key TEXT PRIMARY KEY,
10
+ value TEXT NOT NULL,
11
+ expires_at INTEGER
12
+ );
13
+
14
+ CREATE TABLE chat_subscriptions (
15
+ thread_id TEXT PRIMARY KEY,
16
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
17
+ );
18
+
19
+ CREATE TABLE chat_locks (
20
+ thread_id TEXT PRIMARY KEY,
21
+ token TEXT NOT NULL,
22
+ expires_at INTEGER NOT NULL
23
+ );
24
+
25
+ CREATE TABLE chat_lists (
26
+ key TEXT NOT NULL,
27
+ seq INTEGER NOT NULL,
28
+ value TEXT NOT NULL,
29
+ expires_at INTEGER,
30
+ PRIMARY KEY (key, seq)
31
+ );
32
+
33
+ CREATE TABLE chat_queue (
34
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
35
+ thread_id TEXT NOT NULL,
36
+ entry TEXT NOT NULL
37
+ );
38
+
39
+ CREATE INDEX idx_chat_queue_thread ON chat_queue(thread_id, id);
40
+
41
+ -- Persist the obligation to publish a terminal result for every Chat SDK-rooted
42
+ -- task. Mirrors 144_slack_relay_obligations.sql, plus an attempt cap: a poison
43
+ -- row is marked given up (with the reason) instead of retrying forever.
44
+ CREATE TABLE chat_relay_obligations (
45
+ task_id TEXT PRIMARY KEY REFERENCES agent_tasks(id) ON DELETE CASCADE,
46
+ delivered_at TEXT,
47
+ attempt_count INTEGER NOT NULL DEFAULT 0,
48
+ last_attempt_at TEXT,
49
+ given_up_at TEXT,
50
+ last_error TEXT,
51
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
52
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
53
+ created_by TEXT,
54
+ updated_by TEXT
55
+ );
56
+
57
+ CREATE INDEX idx_chat_relay_obligations_pending
58
+ ON chat_relay_obligations(last_attempt_at, created_at)
59
+ WHERE delivered_at IS NULL AND given_up_at IS NULL;
60
+
61
+ -- Lead follow-ups (`source='system'`, `taskType='follow-up'`) inherit the chat
62
+ -- contextKey and carry the lead's final answer, so they relay too. A resume
63
+ -- (`source='system'`, `taskType='resume'`, from `createResumeFollowUp` after a
64
+ -- graceful shutdown or crash recovery) inherits the contextKey too. It relays
65
+ -- only when a lead owns it: a worker task (resumed or not) reports back through
66
+ -- a lead follow-up, and the lead never gets one for its own tasks. Other system
67
+ -- tasks that inherit the key stay silent. GLOB, not LIKE: LIKE is
68
+ -- case-insensitive in SQLite.
69
+ CREATE TRIGGER enqueue_chat_relay_after_terminal_update
70
+ AFTER UPDATE OF status ON agent_tasks
71
+ WHEN OLD.status NOT IN ('completed', 'failed', 'cancelled', 'superseded')
72
+ AND NEW.status IN ('completed', 'failed', 'cancelled')
73
+ AND NEW.contextKey GLOB 'task:chat-sdk:*'
74
+ AND (
75
+ NEW.source = 'chat'
76
+ OR (NEW.source = 'system' AND NEW.taskType = 'follow-up')
77
+ OR (
78
+ NEW.source = 'system'
79
+ AND NEW.taskType = 'resume'
80
+ AND EXISTS (SELECT 1 FROM agents WHERE agents.id = NEW.agentId AND agents.isLead = 1)
81
+ )
82
+ )
83
+ BEGIN
84
+ INSERT OR IGNORE INTO chat_relay_obligations (task_id)
85
+ VALUES (NEW.id);
86
+ END;
87
+
88
+ CREATE TRIGGER enqueue_chat_relay_after_terminal_insert
89
+ AFTER INSERT ON agent_tasks
90
+ WHEN NEW.status IN ('completed', 'failed', 'cancelled')
91
+ AND NEW.contextKey GLOB 'task:chat-sdk:*'
92
+ AND (
93
+ NEW.source = 'chat'
94
+ OR (NEW.source = 'system' AND NEW.taskType = 'follow-up')
95
+ OR (
96
+ NEW.source = 'system'
97
+ AND NEW.taskType = 'resume'
98
+ AND EXISTS (SELECT 1 FROM agents WHERE agents.id = NEW.agentId AND agents.isLead = 1)
99
+ )
100
+ )
101
+ BEGIN
102
+ INSERT OR IGNORE INTO chat_relay_obligations (task_id)
103
+ VALUES (NEW.id);
104
+ END;
@@ -13,6 +13,7 @@
13
13
  * See runbooks/model-catalog.md.
14
14
  */
15
15
 
16
+ import { withAgentChatRegistrySections } from "@desplega/model-catalog";
16
17
  import { type RuntimeCatalog, setRuntimeModelCatalog } from "../utils/runtime-model-catalog";
17
18
  import {
18
19
  getActivePricingRow,
@@ -180,7 +181,10 @@ function pickNumber(value: unknown): number | undefined {
180
181
  }
181
182
 
182
183
  /** Project a models.dev payload into `model_catalog` rows for CATALOG_PROVIDER_IDS. */
183
- export function buildCatalogEntries(cache: ModelsDevCache, checkedAt: number): ModelCatalogEntry[] {
184
+ export function buildCatalogEntries(raw: ModelsDevCache, checkedAt: number): ModelCatalogEntry[] {
185
+ // A live models.dev payload still carries the embeddings and image models of
186
+ // the registry gateways (`vercel`); pi and opencode cannot run them.
187
+ const cache = withAgentChatRegistrySections(raw);
184
188
  const entries: ModelCatalogEntry[] = [];
185
189
  for (const providerId of CATALOG_PROVIDER_IDS) {
186
190
  const provider = cache[providerId];
@@ -509,6 +509,8 @@ export type ClaimModelFields = Partial<TaskModelResolution> & {
509
509
  /**
510
510
  * Resolve and record the model for a task the given agent is claiming. Runs
511
511
  * inside the claim transaction. Returns the fields to merge into the trigger.
512
+ * `task.model` must be the task's own pin (`taskModelPin`), never the model a
513
+ * previous session reported into the column.
512
514
  */
513
515
  export async function recordClaimModelResolution(
514
516
  task: { id: string; model?: string | null; modelTier?: string | null },
@@ -521,7 +523,16 @@ export async function recordClaimModelResolution(
521
523
  harnessProvider,
522
524
  workerOverrides: await getAgentModelTierOverrides(agent.id),
523
525
  });
524
- if (!resolved) return {};
526
+ if (!resolved) {
527
+ // A re-claimed row keeps the claim record of its previous run; drop it so
528
+ // the trigger and the row do not replay that run's model.
529
+ await getDbClient().run(
530
+ `UPDATE agent_tasks SET resolvedModel = NULL, modelSource = NULL, modelAlias = NULL
531
+ WHERE id = ? AND (resolvedModel IS NOT NULL OR modelSource IS NOT NULL OR modelAlias IS NOT NULL)`,
532
+ [task.id],
533
+ );
534
+ return {};
535
+ }
525
536
  if ("harnessMismatch" in resolved) return { modelUnsupported: resolved.harnessMismatch };
526
537
  const checked = await applyCliSupport(
527
538
  resolved,
@@ -29,6 +29,7 @@ import {
29
29
  type ModelsDevCatalog,
30
30
  parseAlias,
31
31
  } from "@desplega/model-catalog";
32
+ import { type TaskModelPinFields, taskModelPin } from "../tasks/model-pin";
32
33
  import { ampModelError, ampPinCatalogError, ampPinProviderError } from "../utils/amp-models";
33
34
  import { getAgentById, getAllAgents } from "./db";
34
35
  import { loadModelsCatalog } from "./model-catalog-store";
@@ -99,10 +100,12 @@ export async function harnessModelErrorFor(
99
100
  * stays sync and catalog-free; this runs next to it.
100
101
  */
101
102
  export async function poolTaskRunsOnHarness(
102
- task: { model?: string | null } | null | undefined,
103
+ task: TaskModelPinFields | null | undefined,
103
104
  harness: string | null | undefined,
104
105
  ): Promise<boolean> {
105
- const model = task?.model?.trim();
106
+ // Only the task's own pin restricts harnesses; a model a previous run
107
+ // reported into `model` does not.
108
+ const model = taskModelPin(task ?? {})?.trim();
106
109
  if (!model) return true;
107
110
  return (await harnessModelErrorFor(model, harness)) === null;
108
111
  }
@@ -1,3 +1,4 @@
1
+ import { openAICompatibleProviderIds, registryCatalogSections } from "@desplega/model-catalog";
1
2
  import { loadModelsDevCache, type ModelsDevCache, type ModelsDevModel } from "./modelsdev-cache";
2
3
 
3
4
  /**
@@ -15,13 +16,18 @@ import { loadModelsDevCache, type ModelsDevCache, type ModelsDevModel } from "./
15
16
  * same snapshot as its own fallback while the request is in flight.
16
17
  */
17
18
 
18
- /** Mirrors the provider groups used by the direct harness and ACP model pickers. */
19
+ /**
20
+ * Mirrors the provider groups used by the direct harness and ACP model
21
+ * pickers, plus every OpenAI-compatible registry provider
22
+ * (`@desplega/model-catalog`).
23
+ */
19
24
  export const CATALOG_PROVIDER_IDS = [
20
25
  "openrouter",
21
26
  "anthropic",
22
27
  "openai",
23
28
  "amazon-bedrock",
24
29
  "opencode",
30
+ ...openAICompatibleProviderIds(),
25
31
  ] as const;
26
32
 
27
33
  export type CatalogProviderId = (typeof CATALOG_PROVIDER_IDS)[number];
@@ -163,6 +169,24 @@ function mergePinnedEntries(catalog: ModelsCatalog): void {
163
169
  }
164
170
  }
165
171
 
172
+ /**
173
+ * Registry-synthesized sections (`catalog: "registry"` entries such as
174
+ * `helmcode`) are never on models.dev, so the live catalog built from it
175
+ * lacks them. Fill them from the bundled snapshot, which carries them
176
+ * (`loadModelsDevCache`); models already present (an overlay row) win.
177
+ */
178
+ function mergeRegistrySections(catalog: ModelsCatalog): void {
179
+ const snapshot = bundledSnapshotCatalog();
180
+ for (const providerId of Object.keys(registryCatalogSections()) as CatalogProviderId[]) {
181
+ const section = snapshot[providerId];
182
+ if (!section) continue;
183
+ catalog[providerId] ??= { ...section, models: {} };
184
+ for (const [modelId, model] of Object.entries(section.models)) {
185
+ catalog[providerId].models[modelId] ??= model;
186
+ }
187
+ }
188
+ }
189
+
166
190
  /**
167
191
  * Install a freshly built live catalog (already merged with the persistent
168
192
  * table + overlay by `src/be/model-catalog-store.ts`). Pinned snapshot entries
@@ -170,6 +194,7 @@ function mergePinnedEntries(catalog: ModelsCatalog): void {
170
194
  */
171
195
  export function setLiveModelsCatalog(catalog: ModelsCatalog, updatedAt: number | null): void {
172
196
  mergePinnedEntries(catalog);
197
+ mergeRegistrySections(catalog);
173
198
  liveCatalog = catalog;
174
199
  liveUpdatedAt = updatedAt;
175
200
  }