@desplega.ai/agent-swarm 1.173.0 → 2.1.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 (511) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-kr4abrsk.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
  7. package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
  8. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
  15. package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
  16. package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
  17. package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
  18. package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
  19. package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
  20. package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
  21. package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
  22. package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
  23. package/dist/cli-2m1ktfzz.js +17795 -0
  24. package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
  25. package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
  26. package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
  27. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  28. package/dist/cli-6cvfxs8r.js +47 -0
  29. package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
  30. package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
  31. package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
  32. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  33. package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
  34. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  35. package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
  36. package/dist/cli-9traj3dn.js +638 -0
  37. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  38. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  39. package/dist/cli-cvv9k0hh.js +10143 -0
  40. package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/cli-f527ce74.js +781 -0
  43. package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
  44. package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
  45. package/dist/cli-hjwmhcg1.js +10622 -0
  46. package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
  47. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  48. package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
  49. package/dist/cli-jta2eyzc.js +619 -0
  50. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  51. package/dist/cli-kceah1eh.js +92 -0
  52. package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
  53. package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
  54. package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
  55. package/dist/cli-n2wq4j7m.js +6985 -0
  56. package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
  57. package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
  58. package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
  59. package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
  60. package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
  61. package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
  62. package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
  63. package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
  64. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  65. package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
  66. package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
  67. package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
  68. package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
  69. package/dist/cli-rhs9pz33.js +294 -0
  70. package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
  71. package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
  72. package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
  73. package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
  74. package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
  75. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  76. package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
  77. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  78. package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
  79. package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
  80. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  81. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  82. package/dist/cli-wfnemr1t.js +86 -0
  83. package/dist/cli-wmgrkscj.js +23254 -0
  84. package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
  85. package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
  86. package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
  87. package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
  88. package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
  89. package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
  90. package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
  91. package/dist/cli.js +34 -49
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
  99. package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
  100. package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.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-s9ncp9vy.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
  117. package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
  118. package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
  121. package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
  122. package/dist/index-9gw58n4k.js +193 -0
  123. package/dist/index-9j87mcm8.js +56305 -0
  124. package/dist/index-bsmcresk.js +79424 -0
  125. package/dist/index-mh85qhec.js +475 -0
  126. package/dist/{index-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
  127. package/dist/index-we27kd31.js +12810 -0
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-2fp2pypp.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-6k0ywz3m.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
  148. package/openapi.json +1279 -329
  149. package/package.json +15 -15
  150. package/src/agentmail/handlers.ts +21 -11
  151. package/src/apps/definition.ts +16 -0
  152. package/src/azure-devops/api.ts +52 -2
  153. package/src/azure-devops/boards-sync.ts +50 -20
  154. package/src/azure-devops/index.ts +1 -0
  155. package/src/azure-devops/outbound.ts +95 -0
  156. package/src/be/boot-seeds.ts +11 -0
  157. package/src/be/config-refs.ts +60 -0
  158. package/src/be/db/model-profiles.ts +315 -0
  159. package/src/be/db/page-versions.ts +15 -0
  160. package/src/be/db/runtime.ts +35 -8
  161. package/src/be/db/skill-name-resolution.ts +36 -0
  162. package/src/be/db/tasks/read.ts +237 -0
  163. package/src/be/db/tasks/write.ts +7 -0
  164. package/src/be/db.ts +87 -36
  165. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  166. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  167. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  168. package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
  169. package/src/be/migrations/220_model_profiles.sql +137 -0
  170. package/src/be/model-catalog-store.ts +5 -1
  171. package/src/be/model-tier-resolution.ts +155 -10
  172. package/src/be/model-validation.ts +12 -2
  173. package/src/be/models-catalog.ts +26 -1
  174. package/src/be/modelsdev-cache.json +198 -63
  175. package/src/be/modelsdev-cache.ts +9 -1
  176. package/src/be/script-credential-broker.ts +39 -2
  177. package/src/be/scripts/run-saved.ts +1 -0
  178. package/src/be/scripts/typecheck.ts +22 -8
  179. package/src/be/secret-registry.ts +6 -2
  180. package/src/be/seed/runner.ts +13 -1
  181. package/src/be/seed/state-db.ts +5 -0
  182. package/src/be/seed/types.ts +6 -0
  183. package/src/be/seed-model-profiles.ts +41 -0
  184. package/src/be/seed-pricing.ts +19 -2
  185. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
  186. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  187. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  188. package/src/be/seed-scripts/index.ts +9 -0
  189. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  190. package/src/be/seed-skills/index.ts +104 -3
  191. package/src/be/swarm-config-guard.ts +53 -0
  192. package/src/cli.tsx +0 -16
  193. package/src/commands/onboard/non-interactive.ts +4 -2
  194. package/src/commands/provider-credentials.ts +52 -6
  195. package/src/commands/runner.ts +193 -71
  196. package/src/e2b/env.ts +5 -0
  197. package/src/extensions/catalog.generated.json +17 -0
  198. package/src/extensions/contract-types.generated.ts +1 -1
  199. package/src/extensions/contract.ts +45 -0
  200. package/src/extensions/dispatcher.ts +7 -0
  201. package/src/extensions/loader.ts +10 -5
  202. package/src/extensions/post-bridge.ts +40 -0
  203. package/src/github/handlers.ts +11 -4
  204. package/src/heartbeat/heartbeat.ts +2 -1
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/agents.ts +49 -2
  208. package/src/http/all-routes.ts +1 -1
  209. package/src/http/apps.ts +30 -3
  210. package/src/http/config.ts +62 -19
  211. package/src/http/core.ts +8 -0
  212. package/src/http/index.ts +25 -3
  213. package/src/http/integrations.ts +88 -1
  214. package/src/http/mcp.ts +15 -5
  215. package/src/http/model-profiles.ts +303 -0
  216. package/src/http/page-proxy.ts +2 -4
  217. package/src/http/pages-public.ts +13 -7
  218. package/src/http/pages.ts +3 -13
  219. package/src/http/poll.ts +42 -71
  220. package/src/http/requested-by.ts +54 -0
  221. package/src/http/script-runs.ts +1 -1
  222. package/src/http/scripts.ts +26 -2
  223. package/src/http/stats.ts +1 -30
  224. package/src/http/tasks.ts +79 -5
  225. package/src/http/utils.ts +14 -0
  226. package/src/http/webhooks.ts +160 -3
  227. package/src/http/x.ts +1 -0
  228. package/src/integrations/chat-sdk/adapters.ts +129 -0
  229. package/src/integrations/chat-sdk/attachments.ts +232 -0
  230. package/src/integrations/chat-sdk/background.ts +36 -0
  231. package/src/integrations/chat-sdk/commands.ts +194 -0
  232. package/src/integrations/chat-sdk/config.ts +198 -0
  233. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  234. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  235. package/src/integrations/chat-sdk/handlers.ts +28 -0
  236. package/src/integrations/chat-sdk/inbound.ts +426 -0
  237. package/src/integrations/chat-sdk/limits.ts +48 -0
  238. package/src/integrations/chat-sdk/logger.ts +81 -0
  239. package/src/integrations/chat-sdk/outbound.ts +123 -0
  240. package/src/integrations/chat-sdk/relay.ts +172 -0
  241. package/src/integrations/chat-sdk/router.ts +169 -0
  242. package/src/integrations/chat-sdk/runtime.ts +351 -0
  243. package/src/integrations/chat-sdk/schema.ts +245 -0
  244. package/src/integrations/chat-sdk/state.ts +243 -0
  245. package/src/integrations/chat-sdk/status.ts +244 -0
  246. package/src/integrations/chat-sdk/steering.ts +58 -0
  247. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  248. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  249. package/src/integrations/chat-sdk/templates.ts +16 -0
  250. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  251. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  252. package/src/integrations/chat-sdk/typing.ts +65 -0
  253. package/src/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
  254. package/src/pages/version.ts +4 -5
  255. package/src/prompts/base-prompt.ts +111 -45
  256. package/src/providers/acp-target-catalog.ts +6 -0
  257. package/src/providers/acp-targets.ts +56 -3
  258. package/src/providers/amp-adapter.ts +1 -1
  259. package/src/providers/claude-adapter.ts +1 -1
  260. package/src/providers/claude-flag-settings.ts +17 -5
  261. package/src/providers/claude-managed-adapter.ts +1 -1
  262. package/src/providers/claude-session-events.ts +6 -1
  263. package/src/providers/dsh-adapter.ts +1 -1
  264. package/src/providers/opencode-adapter.ts +243 -26
  265. package/src/providers/opencode-swarm-plugin.ts +31 -0
  266. package/src/providers/pi-mono-adapter.ts +398 -153
  267. package/src/providers/pi-mono-extension.ts +17 -3
  268. package/src/providers/pricing-sources.md +33 -2
  269. package/src/providers/reasoning-effort.ts +37 -0
  270. package/src/providers/types.ts +6 -2
  271. package/src/rbac/legacy-policy.ts +16 -2
  272. package/src/rbac/permissions.ts +26 -0
  273. package/src/scheduler/deferred-task-waits.ts +18 -5
  274. package/src/scheduler/scheduler.ts +11 -3
  275. package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
  276. package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
  277. package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
  278. package/src/scripts-runtime/extract-args-schema.ts +9 -8
  279. package/src/scripts-runtime/loader.ts +19 -7
  280. package/src/scripts-runtime/quickjs-compat.ts +464 -0
  281. package/src/scripts-runtime/sdk-allowlist.ts +12 -6
  282. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  283. package/src/scripts-runtime/types/stdlib.d.ts +39 -15
  284. package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
  285. package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
  286. package/src/server.ts +62 -19
  287. package/src/slack/blocks.ts +4 -2
  288. package/src/slack/event-dedup.ts +1 -1
  289. package/src/slack/reaction-shortcode.ts +14 -0
  290. package/src/slack/render-v2.ts +12 -7
  291. package/src/slack/responses.ts +5 -4
  292. package/src/slack/thread-buffer.ts +41 -22
  293. package/src/tasks/additive-buffer.ts +4 -2
  294. package/src/tasks/context-key.ts +60 -1
  295. package/src/tasks/model-pin.ts +67 -0
  296. package/src/tasks/worker-follow-up.ts +15 -33
  297. package/src/tests/acp-adapter.test.ts +42 -0
  298. package/src/tests/agentmail-filters.test.ts +47 -0
  299. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  300. package/src/tests/apps-spike2.test.ts +35 -0
  301. package/src/tests/azure-devops-outbound.test.ts +420 -0
  302. package/src/tests/base-prompt.test.ts +58 -54
  303. package/src/tests/chat-sdk-commands.test.ts +191 -0
  304. package/src/tests/chat-sdk-config.test.ts +334 -0
  305. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  306. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  307. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  308. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  309. package/src/tests/chat-sdk-harness.ts +146 -0
  310. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  311. package/src/tests/chat-sdk-relay.test.ts +470 -0
  312. package/src/tests/chat-sdk-reload.test.ts +128 -0
  313. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  314. package/src/tests/chat-sdk-slack.test.ts +268 -0
  315. package/src/tests/chat-sdk-state.test.ts +163 -0
  316. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  317. package/src/tests/chat-sdk-teams.test.ts +277 -0
  318. package/src/tests/chat-sdk-tools.test.ts +520 -0
  319. package/src/tests/chat-sdk-typing.test.ts +120 -0
  320. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  321. package/src/tests/claude-adapter-binary.test.ts +9 -4
  322. package/src/tests/claude-flag-settings.test.ts +11 -3
  323. package/src/tests/claude-managed-adapter.test.ts +1 -1
  324. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  325. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  326. package/src/tests/claude-worker-parity.test.ts +2 -7
  327. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  328. package/src/tests/config-refs.test.ts +66 -0
  329. package/src/tests/context-key.test.ts +19 -0
  330. package/src/tests/cors-allowlist.test.ts +25 -0
  331. package/src/tests/create-page-tool.test.ts +18 -0
  332. package/src/tests/credential-check.test.ts +139 -0
  333. package/src/tests/credentials.test.ts +21 -0
  334. package/src/tests/db-runtime.test.ts +61 -0
  335. package/src/tests/db-task-read-contract.test.ts +22 -0
  336. package/src/tests/db-task-write-contract.test.ts +11 -0
  337. package/src/tests/deferred-task-wake.test.ts +78 -1
  338. package/src/tests/docs-index-footprint.test.js +3 -3
  339. package/src/tests/dsh-adapter.test.ts +1 -1
  340. package/src/tests/enabled-capabilities.test.ts +20 -0
  341. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  342. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  343. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  344. package/src/tests/env-flag.test.ts +1 -0
  345. package/src/tests/explicit-model-validation.test.ts +105 -1
  346. package/src/tests/extensions-catalog.test.ts +1 -0
  347. package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
  348. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  349. package/src/tests/extensions-loader.test.ts +15 -0
  350. package/src/tests/extensions-post-bridge.test.ts +51 -0
  351. package/src/tests/fetch-resolved-env.test.ts +128 -0
  352. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  353. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  354. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  355. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  356. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  357. package/src/tests/github-handlers.test.ts +35 -0
  358. package/src/tests/harness-provider-resolution.test.ts +12 -0
  359. package/src/tests/heartbeat-checklist.test.ts +3 -2
  360. package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
  361. package/src/tests/heartbeat-jev-gate.test.ts +385 -0
  362. package/src/tests/hook-runtime-close.test.ts +0 -2
  363. package/src/tests/http-api-integration.test.ts +0 -25
  364. package/src/tests/migration-046-budgets.test.ts +17 -16
  365. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  366. package/src/tests/model-profile-backcompat.test.ts +327 -0
  367. package/src/tests/model-profile-providers.test.ts +302 -0
  368. package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
  369. package/src/tests/model-profiles-api.test.ts +614 -0
  370. package/src/tests/model-tier-resolution.test.ts +93 -0
  371. package/src/tests/models-catalog.test.ts +42 -1
  372. package/src/tests/openai-compatible-providers.test.ts +134 -0
  373. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  374. package/src/tests/opencode-adapter.test.ts +216 -2
  375. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  376. package/src/tests/opencode-shell-env.test.ts +145 -0
  377. package/src/tests/openrouter-base-url.test.ts +101 -151
  378. package/src/tests/page-proxy.test.ts +1 -1
  379. package/src/tests/pages-browser-sdk.test.ts +76 -0
  380. package/src/tests/pages-feedback-keys.test.ts +121 -0
  381. package/src/tests/pages-feedback.test.ts +4 -1
  382. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  383. package/src/tests/pi-context-compaction.test.ts +193 -0
  384. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  385. package/src/tests/pi-mono-adapter.test.ts +385 -5
  386. package/src/tests/pi-shell-env.test.ts +170 -0
  387. package/src/tests/profile-claim.test.ts +269 -0
  388. package/src/tests/prompt-template-remaining.test.ts +35 -0
  389. package/src/tests/quickjs-compat.test.ts +213 -0
  390. package/src/tests/rbac-engine.test.ts +32 -3
  391. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  392. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  393. package/src/tests/script-connections.test.ts +6 -0
  394. package/src/tests/script-executor-conformance.test.ts +252 -1
  395. package/src/tests/script-executor-quickjs.test.ts +96 -0
  396. package/src/tests/script-runs-http.test.ts +89 -0
  397. package/src/tests/scripts-http.test.ts +217 -1
  398. package/src/tests/scripts-only-gating.test.ts +2 -3
  399. package/src/tests/scripts-runtime.test.ts +58 -40
  400. package/src/tests/secret-scrubber.test.ts +96 -0
  401. package/src/tests/seed-model-profiles.test.ts +174 -0
  402. package/src/tests/seed-scripts.test.ts +2 -2
  403. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  404. package/src/tests/seed-skills-retire.test.ts +182 -0
  405. package/src/tests/send-task-requester-gate.test.ts +58 -0
  406. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  407. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  408. package/src/tests/skill-invocations.test.ts +4 -2
  409. package/src/tests/slack-blocks.test.ts +36 -0
  410. package/src/tests/slack-inline-output.test.ts +14 -0
  411. package/src/tests/slack-reaction-config.test.ts +20 -0
  412. package/src/tests/slack-render-v2.test.ts +37 -0
  413. package/src/tests/slack-thread-buffer.test.ts +98 -1
  414. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  415. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  416. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  417. package/src/tests/swarm-diff.test.ts +1 -1
  418. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  419. package/src/tests/task-session-prompts.test.ts +132 -0
  420. package/src/tests/task-tool-manifest.test.ts +14 -0
  421. package/src/tests/task-tools-ctx.test.ts +2 -0
  422. package/src/tests/tool-annotations.test.ts +6 -6
  423. package/src/tests/ui-logs-parser.test.ts +43 -0
  424. package/src/tests/used-by-route.test.ts +6 -0
  425. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  426. package/src/tests/workflow-llm.test.ts +61 -0
  427. package/src/tests/workflow-swarm-script.test.ts +38 -0
  428. package/src/tests/workflow-wait-filter.test.ts +5 -3
  429. package/src/tools/chat-access.ts +41 -0
  430. package/src/tools/chat-open-dm.ts +59 -0
  431. package/src/tools/chat-post.ts +74 -0
  432. package/src/tools/chat-read-thread.ts +100 -0
  433. package/src/tools/chat-reply.ts +75 -0
  434. package/src/tools/create-page.ts +3 -13
  435. package/src/tools/model-catalog/index.ts +2 -1
  436. package/src/tools/model-profiles/list-model-profiles.ts +54 -0
  437. package/src/tools/register-chat-channel.ts +139 -0
  438. package/src/tools/request-human-input.ts +11 -3
  439. package/src/tools/script-apis.ts +5 -1
  440. package/src/tools/script-upsert.ts +4 -1
  441. package/src/tools/send-task.ts +48 -1
  442. package/src/tools/skills/skill-get.ts +17 -9
  443. package/src/tools/swarm-config/get-config.ts +2 -1
  444. package/src/tools/swarm-config/list-config.ts +2 -1
  445. package/src/tools/swarm-config/set-config.ts +16 -3
  446. package/src/tools/system-one-decide.ts +104 -0
  447. package/src/tools/task-action.ts +22 -1
  448. package/src/tools/tool-config.ts +14 -6
  449. package/src/types.ts +48 -3
  450. package/src/utils/config-env-export.ts +74 -0
  451. package/src/utils/credentials.test.ts +92 -0
  452. package/src/utils/credentials.ts +52 -4
  453. package/src/utils/harness-provider.ts +15 -6
  454. package/src/utils/runtime-model-catalog.ts +11 -1
  455. package/src/utils/secret-scrubber.ts +86 -10
  456. package/src/utils/task-tool-manifest.ts +19 -2
  457. package/src/utils/vcs-repo-match.ts +29 -0
  458. package/src/workflows/executors/raw-llm.ts +8 -3
  459. package/src/workflows/executors/swarm-script.ts +1 -0
  460. package/src/workflows/executors/system-one-decision.ts +21 -11
  461. package/src/workflows/executors/workflow-llm.ts +22 -0
  462. package/src/workflows/index.ts +21 -12
  463. package/templates/extensions/README.md +1 -0
  464. package/templates/extensions/comms-adherence-gate/README.md +88 -0
  465. package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
  466. package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
  467. package/templates/skills/agent-browser/SKILL.md +1 -1
  468. package/templates/skills/agent-browser/content.md +1 -1
  469. package/templates/skills/apps/SKILL.md +8 -1
  470. package/templates/skills/apps/content.md +8 -1
  471. package/templates/skills/chat-sdk/config.json +14 -0
  472. package/templates/skills/chat-sdk/content.md +84 -0
  473. package/templates/skills/composio-gmail/content.md +7 -0
  474. package/templates/skills/composio-google-docs/content.md +1 -1
  475. package/templates/skills/email-domain-health/config.json +14 -0
  476. package/templates/skills/email-domain-health/content.md +131 -0
  477. package/templates/skills/kv-storage/content.md +2 -2
  478. package/templates/skills/pages/content.md +8 -10
  479. package/templates/skills/swarm-extensions/content.md +2 -0
  480. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  481. package/templates/skills/swarm-scripts/config.json +1 -1
  482. package/templates/skills/swarm-scripts/content.md +4 -2
  483. package/templates/skills/workflow-iterate/content.md +38 -0
  484. package/dist/artifact-eczsknc3.js +0 -3843
  485. package/dist/cli-42qhyvwx.js +0 -33
  486. package/dist/cli-bd957dgb.js +0 -153
  487. package/dist/cli-q51yprfq.js +0 -1104
  488. package/dist/cli-t1ze64h3.js +0 -811
  489. package/dist/cli-tcc4wd5d.js +0 -56471
  490. package/dist/index-9ch1n761.js +0 -1102
  491. package/src/artifact-sdk/index.ts +0 -2
  492. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  493. package/src/artifact-sdk/port.ts +0 -12
  494. package/src/artifact-sdk/server.ts +0 -183
  495. package/src/artifact-sdk/tunnel.ts +0 -19
  496. package/src/commands/artifact.ts +0 -249
  497. package/src/http/ecosystem.ts +0 -77
  498. package/src/tests/artifact-commands.test.ts +0 -92
  499. package/src/tests/artifact-sdk.test.ts +0 -793
  500. package/src/tests/register-service-security.test.ts +0 -194
  501. package/src/tools/list-services.ts +0 -107
  502. package/src/tools/register-service.ts +0 -177
  503. package/src/tools/unregister-service.ts +0 -73
  504. package/src/tools/update-service-status.ts +0 -96
  505. package/templates/skills/artifacts/config.json +0 -14
  506. package/templates/skills/artifacts/content.md +0 -344
  507. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  508. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  509. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  510. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  511. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
@@ -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;
@@ -0,0 +1,22 @@
1
+ -- The pi extension posted its per-LLM-call `context` usage snapshot as
2
+ -- eventType 'compaction', so every pi turn drew an AUTO COMPACTION divider and
3
+ -- bumped agent_tasks.compactionCount. Those rows never carry compactTrigger or
4
+ -- preCompactTokens (real compactions from every harness do). Relabel them as
5
+ -- 'progress' and recompute the counter for the pi tasks.
6
+
7
+ UPDATE task_context_snapshots
8
+ SET eventType = 'progress'
9
+ WHERE eventType = 'compaction'
10
+ AND compactTrigger IS NULL
11
+ AND preCompactTokens IS NULL
12
+ AND sessionId LIKE 'pi-%'
13
+ AND taskId IN (SELECT id FROM agent_tasks WHERE provider = 'pi');
14
+
15
+ UPDATE agent_tasks
16
+ SET compactionCount = (
17
+ SELECT COUNT(*)
18
+ FROM task_context_snapshots s
19
+ WHERE s.taskId = agent_tasks.id AND s.eventType = 'compaction'
20
+ )
21
+ WHERE provider = 'pi'
22
+ AND COALESCE(compactionCount, 0) > 0;
@@ -0,0 +1,137 @@
1
+ -- Model profiles (runbooks/model-tiers.md § Model profiles): a named
2
+ -- (harness, model, effort) that Lead picks per task or that applies as an
3
+ -- agent's default. Claim stamps the profile on the task. The tier seeds
4
+ -- (`<harness>-<tier>`) are written at boot by src/be/seed-model-profiles.ts.
5
+ CREATE TABLE IF NOT EXISTS model_profiles (
6
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
7
+ name TEXT NOT NULL UNIQUE,
8
+ harness TEXT NOT NULL,
9
+ model TEXT NOT NULL,
10
+ effort TEXT,
11
+ allowCustomModel INTEGER NOT NULL DEFAULT 0,
12
+ description TEXT,
13
+ -- `tier:<tier>` for a boot seed, `agent-config` for a profile this migration
14
+ -- made from an agent's MODEL_OVERRIDE, NULL for one an operator created.
15
+ seededFrom TEXT,
16
+ createdAt TEXT NOT NULL,
17
+ lastUpdatedAt TEXT NOT NULL,
18
+ created_by TEXT REFERENCES users(id),
19
+ updated_by TEXT REFERENCES users(id)
20
+ );
21
+
22
+ -- `profile` is the creator's ask; `resolvedProfile` is the name claim applied
23
+ -- (the task's ask or the agent's default), mirroring model / resolvedModel.
24
+ ALTER TABLE agent_tasks ADD COLUMN profile TEXT;
25
+ ALTER TABLE agent_tasks ADD COLUMN resolvedProfile TEXT;
26
+
27
+ -- A profile name a task asks for, or an agent has as its default, must exist
28
+ -- when the row is written. Enforced here so the check and the write are one
29
+ -- statement: an app-level check before a separate insert races a concurrent
30
+ -- delete. The delete side is the matching single-statement guard in
31
+ -- deleteModelProfile (src/be/db/model-profiles.ts). It is not a trigger on
32
+ -- model_profiles because one reading agent_tasks would break every later
33
+ -- migration that rebuilds agent_tasks (DROP + RENAME re-parses that trigger).
34
+ CREATE TRIGGER IF NOT EXISTS model_profiles_task_ref_insert
35
+ BEFORE INSERT ON agent_tasks
36
+ WHEN NEW.profile IS NOT NULL
37
+ AND NOT EXISTS (SELECT 1 FROM model_profiles WHERE name = NEW.profile)
38
+ BEGIN
39
+ SELECT RAISE(ABORT, 'model-profile-missing: the task''s model profile does not exist');
40
+ END;
41
+
42
+ CREATE TRIGGER IF NOT EXISTS model_profiles_task_ref_update
43
+ BEFORE UPDATE OF profile ON agent_tasks
44
+ WHEN NEW.profile IS NOT NULL
45
+ AND NOT EXISTS (SELECT 1 FROM model_profiles WHERE name = NEW.profile)
46
+ BEGIN
47
+ SELECT RAISE(ABORT, 'model-profile-missing: the task''s model profile does not exist');
48
+ END;
49
+
50
+ CREATE TRIGGER IF NOT EXISTS model_profiles_default_ref_insert
51
+ BEFORE INSERT ON swarm_config
52
+ WHEN NEW.scope = 'agent' AND NEW.key = 'MODEL_PROFILE'
53
+ AND NOT EXISTS (SELECT 1 FROM model_profiles WHERE name = trim(NEW.value))
54
+ BEGIN
55
+ SELECT RAISE(ABORT, 'model-profile-missing: the agent''s default model profile does not exist');
56
+ END;
57
+
58
+ CREATE TRIGGER IF NOT EXISTS model_profiles_default_ref_update
59
+ BEFORE UPDATE OF scope, key, value ON swarm_config
60
+ WHEN NEW.scope = 'agent' AND NEW.key = 'MODEL_PROFILE'
61
+ AND NOT EXISTS (SELECT 1 FROM model_profiles WHERE name = trim(NEW.value))
62
+ BEGIN
63
+ SELECT RAISE(ABORT, 'model-profile-missing: the agent''s default model profile does not exist');
64
+ END;
65
+
66
+ -- Each agent's MODEL_OVERRIDE + REASONING_EFFORT_OVERRIDE pair becomes a
67
+ -- profile, deduped by (harness, model, effort), and that agent's default
68
+ -- (agent-scoped MODEL_PROFILE, never exported to the worker env). Claim then
69
+ -- supplies the same model and effort the worker read from its env before.
70
+ -- A row with exportToEnv = 0 never reached the worker, so it is not carried
71
+ -- over: a withheld model makes no default, a withheld effort no profile effort.
72
+ -- ACP keeps MODEL_OVERRIDE (no portable mapping); `latest:` aliases are not
73
+ -- valid agent defaults, so they are left alone too.
74
+ CREATE TEMP TABLE _model_profile_overrides AS
75
+ SELECT
76
+ a.id AS agentId,
77
+ COALESCE(a.harness_provider, a.provider) AS harness,
78
+ trim(m.value) AS model,
79
+ CASE
80
+ WHEN lower(trim(e.value)) IN ('off', 'low', 'medium', 'high', 'xhigh', 'max')
81
+ THEN lower(trim(e.value))
82
+ END AS effort
83
+ FROM agents a
84
+ JOIN swarm_config m
85
+ ON m.scope = 'agent' AND m.scopeId = a.id AND m.key = 'MODEL_OVERRIDE'
86
+ AND m.isSecret = 0 AND m.encrypted = 0 AND m.exportToEnv = 1
87
+ LEFT JOIN swarm_config e
88
+ ON e.scope = 'agent' AND e.scopeId = a.id AND e.key = 'REASONING_EFFORT_OVERRIDE'
89
+ AND e.isSecret = 0 AND e.encrypted = 0 AND e.exportToEnv = 1
90
+ WHERE COALESCE(a.harness_provider, a.provider) IS NOT NULL
91
+ AND COALESCE(a.harness_provider, a.provider) <> 'acp'
92
+ AND trim(m.value) <> ''
93
+ AND lower(trim(m.value)) NOT LIKE 'latest:%';
94
+
95
+ -- Name: `<harness>-<model>[-<effort>]`, without repeating a harness prefix the
96
+ -- model already carries, e.g. `codex-gpt-6.1-sol-xhigh`, `claude-opus-5-5-high`.
97
+ INSERT OR IGNORE INTO model_profiles
98
+ (name, harness, model, effort, allowCustomModel, description, seededFrom, createdAt, lastUpdatedAt)
99
+ SELECT
100
+ lower(replace(replace(
101
+ CASE WHEN lower(model) LIKE lower(harness) || '-%' THEN model ELSE harness || '-' || model END,
102
+ '/', '-'), ':', '-')) || COALESCE('-' || effort, ''),
103
+ harness,
104
+ model,
105
+ effort,
106
+ 1,
107
+ 'Created from an agent''s MODEL_OVERRIDE and REASONING_EFFORT_OVERRIDE.',
108
+ 'agent-config',
109
+ strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
110
+ strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
111
+ FROM _model_profile_overrides
112
+ GROUP BY harness, model, effort;
113
+
114
+ INSERT OR IGNORE INTO swarm_config
115
+ (id, scope, scopeId, key, value, isSecret, envPath, description, createdAt, lastUpdatedAt, encrypted, exportToEnv)
116
+ SELECT
117
+ lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-4' ||
118
+ substr(lower(hex(randomblob(2))), 2) || '-' ||
119
+ substr('89ab', 1 + (abs(random()) % 4), 1) || substr(lower(hex(randomblob(2))), 2) || '-' ||
120
+ lower(hex(randomblob(6))),
121
+ 'agent',
122
+ o.agentId,
123
+ 'MODEL_PROFILE',
124
+ p.name,
125
+ 0,
126
+ NULL,
127
+ 'Default model profile, created from this agent''s MODEL_OVERRIDE.',
128
+ strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
129
+ strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
130
+ 0,
131
+ 0
132
+ FROM _model_profile_overrides o
133
+ JOIN model_profiles p
134
+ ON p.harness = o.harness AND p.model = o.model AND p.effort IS o.effort
135
+ AND p.seededFrom = 'agent-config';
136
+
137
+ DROP TABLE _model_profile_overrides;
@@ -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];
@@ -7,9 +7,12 @@
7
7
  *
8
8
  * Precedence (first hit wins):
9
9
  * 1. task `model` → modelSource "model"
10
- * 2. the claiming worker's MODEL_TIER_* → "worker-env" (agents.modelTierOverrides)
11
- * 3. swarm_config MODEL_TIER_<PROV>_<TIER> → "tier-config"
12
- * 4. DEFAULT_MODEL_TIER_MAP → "tier-default"
10
+ * 2. task `profile` → "profile:task"
11
+ * 3. the claiming worker's MODEL_TIER_* → "worker-env" (agents.modelTierOverrides)
12
+ * 4. swarm_config MODEL_TIER_<PROV>_<TIER> → "tier-config"
13
+ * 5. DEFAULT_MODEL_TIER_MAP → "tier-default"
14
+ * 6. the agent's default profile → "profile:agent-default" (no model, no tier,
15
+ * no repo-scoped MODEL_OVERRIDE on the task's repo)
13
16
  *
14
17
  * Any layer may hold a `latest:` alias. An alias that resolves to nothing
15
18
  * (empty catalog, everything filtered) falls through to the next layer.
@@ -45,8 +48,14 @@ import {
45
48
  type ProviderName,
46
49
  ProviderNameSchema,
47
50
  parseModelTier,
51
+ type ReasoningEffort,
48
52
  } from "../types";
49
53
  import { getDbClient } from "./db";
54
+ import {
55
+ getAgentDefaultProfileName,
56
+ getModelProfileByName,
57
+ repoModelOverrideKeys,
58
+ } from "./db/model-profiles";
50
59
  import {
51
60
  CLI_PINNED_HARNESSES,
52
61
  fallbackForUnsupportedModel,
@@ -74,7 +83,9 @@ export type ModelSource =
74
83
  | "tier-config"
75
84
  | "tier-default"
76
85
  | "fallback:cli-unsupported"
77
- | "fallback:cli-unsupported:model";
86
+ | "fallback:cli-unsupported:model"
87
+ | "profile:task"
88
+ | "profile:agent-default";
78
89
 
79
90
  export interface TaskModelResolution {
80
91
  resolvedModel: string;
@@ -490,15 +501,21 @@ async function applyCliSupport(
490
501
  if (!fallback) return resolution;
491
502
  noticeCliUnsupported(harness, cliVersion, resolution.resolvedModel, fallback);
492
503
  // Keep the winning layer in the source: a fallback from the task's own `latest:` alias is
493
- // still a task-level pin (a resume carries it), one from a tier layer is not.
494
- const modelSource =
495
- resolution.modelSource === "model"
504
+ // still a task-level pin (a resume carries it), one from a tier layer is not. A profile keeps
505
+ // its own source; `resolvedProfile` still names it and `resolvedModel` shows the swap.
506
+ const modelSource = resolution.modelSource.startsWith("profile:")
507
+ ? resolution.modelSource
508
+ : resolution.modelSource === "model"
496
509
  ? "fallback:cli-unsupported:model"
497
510
  : "fallback:cli-unsupported";
498
511
  return { ...resolution, resolvedModel: fallback, modelSource };
499
512
  }
500
513
 
501
514
  export type ClaimModelFields = Partial<TaskModelResolution> & {
515
+ /** The profile claim applied (`agent_tasks.resolvedProfile`). */
516
+ resolvedProfile?: string;
517
+ /** The profile's effort, when it has one and the task set none; the worker spawns with it. */
518
+ effort?: ReasoningEffort;
502
519
  /**
503
520
  * Set when the task's explicit model is rejected by this worker's CLI, or belongs to another
504
521
  * harness family (`[model-harness-mismatch]`); the worker fails the task without a spawn.
@@ -506,22 +523,150 @@ export type ClaimModelFields = Partial<TaskModelResolution> & {
506
523
  modelUnsupported?: string;
507
524
  };
508
525
 
526
+ /**
527
+ * Resolve a model profile for a claim. Null when the profile does not apply:
528
+ * an agent default that is missing or on another harness falls through to the
529
+ * tier chain. For a task's own `profile` both are a hard stop.
530
+ */
531
+ async function resolveClaimProfile(
532
+ name: string,
533
+ source: "profile:task" | "profile:agent-default",
534
+ harness: ProviderName | null,
535
+ ): Promise<
536
+ | { profile: { name: string; effort: ReasoningEffort | null }; resolution: TaskModelResolution }
537
+ | { modelUnsupported: string }
538
+ | null
539
+ > {
540
+ const isTask = source === "profile:task";
541
+ const profile = await getModelProfileByName(name);
542
+ if (!profile) {
543
+ return isTask
544
+ ? { modelUnsupported: `[model-profile-missing] Model profile "${name}" no longer exists.` }
545
+ : null;
546
+ }
547
+ if (profile.harness !== harness) {
548
+ if (!isTask) return null;
549
+ return {
550
+ modelUnsupported: `[model-harness-mismatch] Model profile "${name}" runs on the ${profile.harness} harness, not on the ${harness ?? "unknown"} harness of this worker. Re-create the task with a ${harness ?? "matching"} profile.`,
551
+ };
552
+ }
553
+ let resolution: TaskModelResolution = {
554
+ resolvedModel: profile.model,
555
+ modelSource: source,
556
+ modelAlias: null,
557
+ };
558
+ if (isAlias(profile.model)) {
559
+ const resolved = await resolveLatestAlias(profile.model);
560
+ if (!resolved) {
561
+ if (!isTask) return null;
562
+ return {
563
+ modelUnsupported: `[model-profile-unresolved] Model profile "${name}" names ${profile.model}, which resolves to no usable model.`,
564
+ };
565
+ }
566
+ resolution = {
567
+ resolvedModel: resolved,
568
+ modelSource: source,
569
+ modelAlias: profile.model.trim().toLowerCase(),
570
+ };
571
+ }
572
+ return { profile: { name: profile.name, effort: profile.effort }, resolution };
573
+ }
574
+
509
575
  /**
510
576
  * Resolve and record the model for a task the given agent is claiming. Runs
511
577
  * inside the claim transaction. Returns the fields to merge into the trigger.
578
+ * `task.model` must be the task's own pin (`taskModelPin`), never the model a
579
+ * previous session reported into the column.
512
580
  */
513
581
  export async function recordClaimModelResolution(
514
- task: { id: string; model?: string | null; modelTier?: string | null },
582
+ task: {
583
+ id: string;
584
+ model?: string | null;
585
+ modelTier?: string | null;
586
+ profile?: string | null;
587
+ effort?: string | null;
588
+ vcsRepo?: string | null;
589
+ },
515
590
  agent: { id: string; harnessProvider?: ProviderName | null; provider?: ProviderName | null },
591
+ /**
592
+ * Whether the claiming worker's config read includes secret repo rows
593
+ * (`readsRepoSecrets`). A secret repo override it never receives cannot
594
+ * beat its default profile. Defaults to true (an operator-key worker).
595
+ */
596
+ { includeRepoSecrets = true }: { includeRepoSecrets?: boolean } = {},
516
597
  ): Promise<ClaimModelFields> {
517
598
  const harnessProvider = agent.harnessProvider ?? agent.provider ?? null;
599
+
600
+ if (!task.model?.trim()) {
601
+ const taskProfile = task.profile?.trim();
602
+ const agentDefault =
603
+ taskProfile || parseModelTier(task.modelTier)
604
+ ? null
605
+ : await getAgentDefaultProfileName(agent.id);
606
+ // The agent default is agent-scoped config: a repo-scoped MODEL_OVERRIDE or
607
+ // REASONING_EFFORT_OVERRIDE on the task's repo still beats it on that axis
608
+ // (repo > agent), as it beats the agent's own override in the worker env.
609
+ // A task's own profile is the creator's pick and beats repo config.
610
+ const repoKeys = agentDefault
611
+ ? await repoModelOverrideKeys(task.vcsRepo, { includeSecrets: includeRepoSecrets })
612
+ : new Set<string>();
613
+ const defaultProfile = repoKeys.has("MODEL_OVERRIDE") ? null : agentDefault;
614
+ const picked = taskProfile
615
+ ? await resolveClaimProfile(taskProfile, "profile:task", harnessProvider)
616
+ : defaultProfile
617
+ ? await resolveClaimProfile(defaultProfile, "profile:agent-default", harnessProvider)
618
+ : null;
619
+ if (picked && "modelUnsupported" in picked)
620
+ return { modelUnsupported: picked.modelUnsupported };
621
+ if (picked) {
622
+ const checked = await applyCliSupport(
623
+ picked.resolution,
624
+ harnessProvider,
625
+ await getAgentHarnessCliVersion(agent.id),
626
+ );
627
+ // Profiles never fail fast on the CLI check (only a raw task pin does), so this is a resolution.
628
+ const resolution = "unsupported" in checked ? picked.resolution : checked;
629
+ await getDbClient().run(
630
+ "UPDATE agent_tasks SET resolvedModel = ?, modelSource = ?, modelAlias = ?, resolvedProfile = ? WHERE id = ?",
631
+ [
632
+ resolution.resolvedModel,
633
+ resolution.modelSource,
634
+ resolution.modelAlias,
635
+ picked.profile.name,
636
+ task.id,
637
+ ],
638
+ );
639
+ return {
640
+ resolvedModel: resolution.resolvedModel,
641
+ modelSource: resolution.modelSource,
642
+ ...(resolution.modelAlias ? { modelAlias: resolution.modelAlias } : {}),
643
+ resolvedProfile: picked.profile.name,
644
+ // A task's own effort stays the pin; the profile's fills only an unset one,
645
+ // and an agent default's yields to the repo's effort override.
646
+ ...(!task.effort && picked.profile.effort && !repoKeys.has("REASONING_EFFORT_OVERRIDE")
647
+ ? { effort: picked.profile.effort }
648
+ : {}),
649
+ };
650
+ }
651
+ }
652
+
518
653
  const resolved = await resolveTaskModel({
519
654
  model: task.model,
520
655
  modelTier: task.modelTier,
521
656
  harnessProvider,
522
657
  workerOverrides: await getAgentModelTierOverrides(agent.id),
523
658
  });
524
- if (!resolved) return {};
659
+ if (!resolved) {
660
+ // A re-claimed row keeps the claim record of its previous run; drop it so
661
+ // the trigger and the row do not replay that run's model.
662
+ await getDbClient().run(
663
+ `UPDATE agent_tasks SET resolvedModel = NULL, modelSource = NULL, modelAlias = NULL, resolvedProfile = NULL
664
+ WHERE id = ? AND (resolvedModel IS NOT NULL OR modelSource IS NOT NULL OR modelAlias IS NOT NULL
665
+ OR resolvedProfile IS NOT NULL)`,
666
+ [task.id],
667
+ );
668
+ return {};
669
+ }
525
670
  if ("harnessMismatch" in resolved) return { modelUnsupported: resolved.harnessMismatch };
526
671
  const checked = await applyCliSupport(
527
672
  resolved,
@@ -533,7 +678,7 @@ export async function recordClaimModelResolution(
533
678
  }
534
679
  const resolution = checked;
535
680
  await getDbClient().run(
536
- "UPDATE agent_tasks SET resolvedModel = ?, modelSource = ?, modelAlias = ? WHERE id = ?",
681
+ "UPDATE agent_tasks SET resolvedModel = ?, modelSource = ?, modelAlias = ?, resolvedProfile = NULL WHERE id = ?",
537
682
  [resolution.resolvedModel, resolution.modelSource, resolution.modelAlias, task.id],
538
683
  );
539
684
  return resolution.modelAlias
@@ -29,8 +29,10 @@ 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";
35
+ import { getModelProfileByName } from "./db/model-profiles";
34
36
  import { loadModelsCatalog } from "./model-catalog-store";
35
37
  import { resolveLatestAlias } from "./model-tier-resolution";
36
38
 
@@ -99,10 +101,18 @@ export async function harnessModelErrorFor(
99
101
  * stays sync and catalog-free; this runs next to it.
100
102
  */
101
103
  export async function poolTaskRunsOnHarness(
102
- task: { model?: string | null } | null | undefined,
104
+ task: (TaskModelPinFields & { profile?: string | null }) | null | undefined,
103
105
  harness: string | null | undefined,
104
106
  ): Promise<boolean> {
105
- const model = task?.model?.trim();
107
+ // A task's model profile runs on one harness only; other workers leave it in the pool.
108
+ const profileName = task?.profile?.trim();
109
+ if (profileName) {
110
+ const profile = await getModelProfileByName(profileName);
111
+ return !profile || !harness || profile.harness === harness;
112
+ }
113
+ // Only the task's own pin restricts harnesses; a model a previous run
114
+ // reported into `model` does not.
115
+ const model = taskModelPin(task ?? {})?.trim();
106
116
  if (!model) return true;
107
117
  return (await harnessModelErrorFor(model, harness)) === null;
108
118
  }
@@ -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
  }