@desplega.ai/agent-swarm 1.172.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 (525) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
  3. package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
  4. package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
  6. package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
  7. package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
  8. package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
  9. package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
  10. package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
  11. package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
  12. package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
  13. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  14. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  15. package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
  16. package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
  17. package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
  18. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  19. package/dist/cli-2m1ktfzz.js +17795 -0
  20. package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
  21. package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
  22. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  23. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  24. package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
  25. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  26. package/dist/cli-6cvfxs8r.js +47 -0
  27. package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
  28. package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
  29. package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
  30. package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
  31. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  32. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  33. package/dist/cli-9traj3dn.js +638 -0
  34. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  35. package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
  36. package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
  37. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  38. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  39. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  40. package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  43. package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
  44. package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
  45. package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
  46. package/dist/cli-f527ce74.js +781 -0
  47. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  48. package/dist/cli-hjwmhcg1.js +10622 -0
  49. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  50. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  51. package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
  52. package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
  53. package/dist/cli-jta2eyzc.js +619 -0
  54. package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
  55. package/dist/cli-k3dp5tpf.js +263 -0
  56. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  57. package/dist/cli-kceah1eh.js +92 -0
  58. package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
  59. package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
  60. package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
  61. package/dist/cli-n2wq4j7m.js +6985 -0
  62. package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
  63. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  64. package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
  65. package/dist/cli-p0sg24zp.js +16 -0
  66. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  67. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  68. package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
  69. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  70. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  71. package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
  72. package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
  73. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  74. package/dist/cli-rhs9pz33.js +294 -0
  75. package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
  76. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  77. package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
  78. package/dist/cli-skxvvpap.js +10140 -0
  79. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  80. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  81. package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
  82. package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
  83. package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
  84. package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
  85. package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
  86. package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
  87. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  88. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  89. package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
  90. package/dist/cli-wmgrkscj.js +23254 -0
  91. package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
  92. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  93. package/dist/cli.js +32 -48
  94. package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
  95. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  96. package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
  97. package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
  98. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  99. package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
  100. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  101. package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
  102. package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
  103. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  104. package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
  105. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  106. package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
  107. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  108. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  109. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  110. package/dist/external-channel-h3359cwn.js +52 -0
  111. package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
  112. package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
  113. package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
  114. package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
  115. package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
  116. package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
  117. package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
  118. package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
  121. package/dist/index-9gw58n4k.js +193 -0
  122. package/dist/index-9j87mcm8.js +56305 -0
  123. package/dist/index-bsmcresk.js +79424 -0
  124. package/dist/index-mh85qhec.js +475 -0
  125. package/dist/{index-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
  126. package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
  127. package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
  128. package/dist/index-we27kd31.js +12810 -0
  129. package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
  130. package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
  131. package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
  132. package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
  133. package/dist/node-c9we95xf.js +1 -1
  134. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  135. package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
  136. package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
  137. package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
  138. package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
  139. package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
  140. package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
  141. package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
  142. package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
  143. package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
  144. package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
  145. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  146. package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
  147. package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
  148. package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
  149. package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
  150. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  151. package/openapi.json +951 -356
  152. package/package.json +12 -13
  153. package/src/apps/catalog.generated.json +1309 -53
  154. package/src/apps/page-validator.ts +93 -31
  155. package/src/azure-devops/api.ts +94 -18
  156. package/src/azure-devops/auth.ts +32 -0
  157. package/src/azure-devops/boards-sync.ts +708 -0
  158. package/src/azure-devops/handlers.ts +52 -8
  159. package/src/azure-devops/html.ts +26 -0
  160. package/src/azure-devops/index.ts +15 -0
  161. package/src/azure-devops/templates.ts +86 -0
  162. package/src/azure-devops/types.ts +65 -1
  163. package/src/be/config-refs.ts +60 -0
  164. package/src/be/db/page-versions.ts +15 -0
  165. package/src/be/db/runtime.ts +35 -8
  166. package/src/be/db/skill-name-resolution.ts +36 -0
  167. package/src/be/db/tasks/read.ts +230 -0
  168. package/src/be/db/tasks/write.ts +7 -0
  169. package/src/be/db.ts +74 -13
  170. package/src/be/migrations/213_script_connections_sql.sql +79 -0
  171. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  172. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  173. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  174. package/src/be/model-catalog-store.ts +5 -1
  175. package/src/be/model-tier-resolution.ts +12 -1
  176. package/src/be/model-validation.ts +5 -2
  177. package/src/be/models-catalog.ts +26 -1
  178. package/src/be/modelsdev-cache.json +198 -63
  179. package/src/be/modelsdev-cache.ts +9 -1
  180. package/src/be/script-connections.ts +47 -8
  181. package/src/be/script-credential-broker.ts +39 -2
  182. package/src/be/scripts/run-saved.ts +1 -0
  183. package/src/be/scripts/typecheck.ts +10 -8
  184. package/src/be/seed/runner.ts +13 -1
  185. package/src/be/seed/state-db.ts +5 -0
  186. package/src/be/seed/types.ts +6 -0
  187. package/src/be/seed-pricing.ts +19 -2
  188. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  189. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  190. package/src/be/seed-skills/bundled-files.generated.json +10 -18
  191. package/src/be/seed-skills/index.ts +107 -3
  192. package/src/be/sql-connections.ts +118 -0
  193. package/src/be/swarm-config-guard.ts +53 -0
  194. package/src/cli.tsx +0 -16
  195. package/src/commands/onboard/non-interactive.ts +4 -2
  196. package/src/commands/profile-sync.ts +5 -3
  197. package/src/commands/provider-credentials.ts +52 -6
  198. package/src/commands/runner.ts +196 -56
  199. package/src/e2b/env.ts +5 -0
  200. package/src/extensions/contract-types.generated.ts +1 -1
  201. package/src/extensions/contract.ts +45 -0
  202. package/src/extensions/dispatcher.ts +7 -0
  203. package/src/extensions/post-bridge.ts +40 -0
  204. package/src/github/handlers.ts +11 -4
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/all-routes.ts +0 -1
  208. package/src/http/config.ts +36 -17
  209. package/src/http/core.ts +4 -0
  210. package/src/http/index.ts +14 -2
  211. package/src/http/integrations.ts +88 -1
  212. package/src/http/mcp-oauth.ts +6 -13
  213. package/src/http/mcp.ts +15 -5
  214. package/src/http/page-proxy.ts +2 -4
  215. package/src/http/pages-public.ts +6 -5
  216. package/src/http/pages.ts +5 -14
  217. package/src/http/poll.ts +28 -68
  218. package/src/http/requested-by.ts +54 -0
  219. package/src/http/route-def.ts +7 -6
  220. package/src/http/script-connection-proxy.ts +51 -4
  221. package/src/http/script-connections.ts +5 -2
  222. package/src/http/scripts.ts +1 -0
  223. package/src/http/session-cost-recompute.ts +12 -2
  224. package/src/http/session-data.ts +4 -0
  225. package/src/http/stats.ts +1 -30
  226. package/src/http/tasks.ts +61 -5
  227. package/src/http/utils.ts +14 -0
  228. package/src/http/webhooks.ts +183 -2
  229. package/src/http/x.ts +1 -0
  230. package/src/integrations/chat-sdk/adapters.ts +129 -0
  231. package/src/integrations/chat-sdk/attachments.ts +232 -0
  232. package/src/integrations/chat-sdk/background.ts +36 -0
  233. package/src/integrations/chat-sdk/commands.ts +194 -0
  234. package/src/integrations/chat-sdk/config.ts +198 -0
  235. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  236. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  237. package/src/integrations/chat-sdk/handlers.ts +28 -0
  238. package/src/integrations/chat-sdk/inbound.ts +426 -0
  239. package/src/integrations/chat-sdk/limits.ts +48 -0
  240. package/src/integrations/chat-sdk/logger.ts +81 -0
  241. package/src/integrations/chat-sdk/outbound.ts +123 -0
  242. package/src/integrations/chat-sdk/relay.ts +172 -0
  243. package/src/integrations/chat-sdk/router.ts +169 -0
  244. package/src/integrations/chat-sdk/runtime.ts +351 -0
  245. package/src/integrations/chat-sdk/schema.ts +245 -0
  246. package/src/integrations/chat-sdk/state.ts +243 -0
  247. package/src/integrations/chat-sdk/status.ts +244 -0
  248. package/src/integrations/chat-sdk/steering.ts +58 -0
  249. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  250. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  251. package/src/integrations/chat-sdk/templates.ts +16 -0
  252. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  253. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  254. package/src/integrations/chat-sdk/typing.ts +65 -0
  255. package/src/jira/adf.ts +3 -1
  256. package/src/kv-reserved-namespaces.ts +2 -0
  257. package/src/oauth/mcp-wrapper.ts +10 -6
  258. package/src/otel-impl.ts +2 -1
  259. package/src/pages/version.ts +4 -5
  260. package/src/prompts/base-prompt.ts +111 -45
  261. package/src/providers/acp-target-catalog.ts +6 -0
  262. package/src/providers/acp-targets.ts +56 -3
  263. package/src/providers/amp-adapter.ts +1 -1
  264. package/src/providers/claude-adapter.ts +27 -2
  265. package/src/providers/claude-flag-settings.ts +133 -0
  266. package/src/providers/claude-managed-adapter.ts +1 -1
  267. package/src/providers/claude-sdk-session.ts +7 -0
  268. package/src/providers/claude-session-events.ts +6 -1
  269. package/src/providers/dsh-adapter.ts +1 -1
  270. package/src/providers/opencode-adapter.ts +268 -37
  271. package/src/providers/opencode-billing.ts +86 -0
  272. package/src/providers/opencode-swarm-plugin.ts +51 -0
  273. package/src/providers/pi-mono-adapter.ts +398 -153
  274. package/src/providers/pricing-sources.md +37 -3
  275. package/src/providers/reasoning-effort.ts +27 -0
  276. package/src/providers/types.ts +11 -2
  277. package/src/rbac/legacy-policy.ts +8 -2
  278. package/src/rbac/permissions.ts +21 -0
  279. package/src/scheduler/scheduler.ts +4 -2
  280. package/src/scripts-runtime/api-client.ts +15 -1
  281. package/src/scripts-runtime/api-types.ts +9 -1
  282. package/src/scripts-runtime/ctx.ts +1 -1
  283. package/src/scripts-runtime/loader.ts +19 -7
  284. package/src/scripts-runtime/mcp-client.ts +30 -19
  285. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  286. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  287. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  288. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  289. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  290. package/src/server.ts +52 -18
  291. package/src/slack/actions.ts +29 -1
  292. package/src/slack/app.ts +14 -2
  293. package/src/slack/assistant.ts +36 -2
  294. package/src/slack/channel-join.ts +3 -16
  295. package/src/slack/commands.ts +9 -1
  296. package/src/slack/event-dedup.ts +1 -1
  297. package/src/slack/external-channel-egress.ts +113 -0
  298. package/src/slack/external-channel.ts +309 -0
  299. package/src/slack/handlers.ts +61 -0
  300. package/src/slack/render-v2.ts +40 -47
  301. package/src/slack/work-objects.ts +5 -0
  302. package/src/tasks/additive-buffer.ts +4 -2
  303. package/src/tasks/context-key.ts +94 -2
  304. package/src/tasks/model-pin.ts +67 -0
  305. package/src/tasks/worker-follow-up.ts +4 -31
  306. package/src/telemetry.ts +2 -1
  307. package/src/tests/acp-adapter.test.ts +42 -0
  308. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  309. package/src/tests/apps-catalog-feedback.test.ts +310 -0
  310. package/src/tests/apps-catalog-inputs.test.ts +70 -0
  311. package/src/tests/apps-catalog-table.test.ts +113 -0
  312. package/src/tests/azure-devops-boards-sync.test.ts +584 -0
  313. package/src/tests/azure-devops-html.test.ts +13 -0
  314. package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
  315. package/src/tests/base-prompt.test.ts +58 -54
  316. package/src/tests/chat-sdk-commands.test.ts +191 -0
  317. package/src/tests/chat-sdk-config.test.ts +334 -0
  318. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  319. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  320. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  321. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  322. package/src/tests/chat-sdk-harness.ts +146 -0
  323. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  324. package/src/tests/chat-sdk-relay.test.ts +470 -0
  325. package/src/tests/chat-sdk-reload.test.ts +128 -0
  326. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  327. package/src/tests/chat-sdk-slack.test.ts +268 -0
  328. package/src/tests/chat-sdk-state.test.ts +163 -0
  329. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  330. package/src/tests/chat-sdk-teams.test.ts +277 -0
  331. package/src/tests/chat-sdk-tools.test.ts +520 -0
  332. package/src/tests/chat-sdk-typing.test.ts +120 -0
  333. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  334. package/src/tests/claude-adapter-binary.test.ts +144 -0
  335. package/src/tests/claude-flag-settings.test.ts +114 -0
  336. package/src/tests/claude-managed-adapter.test.ts +1 -1
  337. package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
  338. package/src/tests/claude-sdk-process.fixture.ts +7 -0
  339. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  340. package/src/tests/claude-worker-parity.test.ts +2 -7
  341. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  342. package/src/tests/config-refs.test.ts +66 -0
  343. package/src/tests/context-key.test.ts +51 -0
  344. package/src/tests/cors-allowlist.test.ts +25 -0
  345. package/src/tests/create-page-tool.test.ts +18 -0
  346. package/src/tests/credential-check.test.ts +139 -0
  347. package/src/tests/credentials.test.ts +21 -0
  348. package/src/tests/db-runtime.test.ts +61 -0
  349. package/src/tests/db-task-read-contract.test.ts +20 -0
  350. package/src/tests/db-task-write-contract.test.ts +10 -0
  351. package/src/tests/deferred-task-wake.test.ts +52 -4
  352. package/src/tests/docs-index-footprint.test.js +3 -3
  353. package/src/tests/dsh-adapter.test.ts +1 -1
  354. package/src/tests/enabled-capabilities.test.ts +20 -0
  355. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  356. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  357. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  358. package/src/tests/explicit-model-validation.test.ts +105 -1
  359. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  360. package/src/tests/extensions-post-bridge.test.ts +51 -0
  361. package/src/tests/fetch-resolved-env.test.ts +128 -0
  362. package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
  363. package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
  364. package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
  365. package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
  366. package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
  367. package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
  368. package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
  369. package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
  370. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  371. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  372. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  373. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  374. package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
  375. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  376. package/src/tests/github-handlers.test.ts +35 -0
  377. package/src/tests/harness-provider-resolution.test.ts +12 -0
  378. package/src/tests/heartbeat-checklist.test.ts +3 -2
  379. package/src/tests/hook-runtime-close.test.ts +0 -2
  380. package/src/tests/http-api-integration.test.ts +0 -25
  381. package/src/tests/migration-046-budgets.test.ts +17 -16
  382. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  383. package/src/tests/model-tier-resolution.test.ts +93 -0
  384. package/src/tests/models-catalog.test.ts +42 -1
  385. package/src/tests/node-env-runtime.test.ts +98 -0
  386. package/src/tests/openai-compatible-providers.test.ts +134 -0
  387. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  388. package/src/tests/opencode-adapter.test.ts +348 -3
  389. package/src/tests/opencode-billing.test.ts +28 -0
  390. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  391. package/src/tests/opencode-shell-env.test.ts +145 -0
  392. package/src/tests/openrouter-base-url.test.ts +101 -151
  393. package/src/tests/page-proxy.test.ts +1 -1
  394. package/src/tests/pages-browser-sdk.test.ts +76 -0
  395. package/src/tests/pages-feedback.test.ts +1 -1
  396. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  397. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  398. package/src/tests/pi-mono-adapter.test.ts +385 -5
  399. package/src/tests/pi-shell-env.test.ts +170 -0
  400. package/src/tests/prompt-template-remaining.test.ts +35 -0
  401. package/src/tests/rbac-engine.test.ts +11 -3
  402. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  403. package/src/tests/runner-identity-refresh.test.ts +3 -0
  404. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  405. package/src/tests/script-connections-sql.test.ts +675 -0
  406. package/src/tests/script-connections.test.ts +7 -1
  407. package/src/tests/scripts-http.test.ts +201 -1
  408. package/src/tests/scripts-only-gating.test.ts +2 -3
  409. package/src/tests/scripts-runtime.test.ts +58 -40
  410. package/src/tests/secret-scrubber.test.ts +86 -0
  411. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  412. package/src/tests/seed-skills-retire.test.ts +182 -0
  413. package/src/tests/send-task-requester-gate.test.ts +58 -0
  414. package/src/tests/session-cost-recompute-unit.test.ts +94 -0
  415. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  416. package/src/tests/slack-channel-join.test.ts +4 -1
  417. package/src/tests/slack-external-channel-config.test.ts +65 -0
  418. package/src/tests/slack-external-channel-egress.test.ts +237 -0
  419. package/src/tests/slack-external-channel-guard.test.ts +280 -0
  420. package/src/tests/slack-external-channel-tools.test.ts +173 -0
  421. package/src/tests/slack-external-channel.test.ts +370 -0
  422. package/src/tests/slack-render-v2.test.ts +86 -10
  423. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  424. package/src/tests/spec-base-url.test.ts +16 -1
  425. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  426. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  427. package/src/tests/swarm-diff.test.ts +1 -1
  428. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  429. package/src/tests/task-session-prompts.test.ts +132 -0
  430. package/src/tests/task-tool-manifest.test.ts +14 -0
  431. package/src/tests/task-tools-ctx.test.ts +2 -0
  432. package/src/tests/tool-annotations.test.ts +6 -6
  433. package/src/tests/ui-logs-parser.test.ts +43 -0
  434. package/src/tests/used-by-route.test.ts +6 -0
  435. package/src/tests/vendored-openapi.test.ts +16 -1
  436. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  437. package/src/tests/workflow-swarm-script.test.ts +38 -0
  438. package/src/tests/workflow-wait-filter.test.ts +5 -3
  439. package/src/tools/chat-access.ts +41 -0
  440. package/src/tools/chat-open-dm.ts +59 -0
  441. package/src/tools/chat-post.ts +74 -0
  442. package/src/tools/chat-read-thread.ts +100 -0
  443. package/src/tools/chat-reply.ts +75 -0
  444. package/src/tools/create-page.ts +3 -13
  445. package/src/tools/defer-task.ts +17 -0
  446. package/src/tools/model-catalog/index.ts +2 -1
  447. package/src/tools/register-chat-channel.ts +139 -0
  448. package/src/tools/send-task.ts +24 -0
  449. package/src/tools/skills/skill-get.ts +17 -9
  450. package/src/tools/slack-post.ts +6 -0
  451. package/src/tools/slack-read.ts +8 -0
  452. package/src/tools/slack-reply.ts +6 -0
  453. package/src/tools/slack-start-thread.ts +6 -0
  454. package/src/tools/slack-update.ts +6 -0
  455. package/src/tools/slack-upload-file.ts +6 -0
  456. package/src/tools/swarm-config/get-config.ts +2 -1
  457. package/src/tools/swarm-config/list-config.ts +2 -1
  458. package/src/tools/swarm-config/set-config.ts +16 -3
  459. package/src/tools/tool-config.ts +8 -6
  460. package/src/types.ts +12 -2
  461. package/src/utils/config-env-export.ts +74 -0
  462. package/src/utils/credentials.test.ts +92 -0
  463. package/src/utils/credentials.ts +52 -4
  464. package/src/utils/harness-provider.ts +15 -6
  465. package/src/utils/node-env.ts +24 -0
  466. package/src/utils/runtime-model-catalog.ts +11 -1
  467. package/src/utils/secret-scrubber.ts +71 -2
  468. package/src/utils/task-tool-manifest.ts +19 -2
  469. package/src/workflows/executors/swarm-script.ts +1 -0
  470. package/templates/skills/agent-browser/SKILL.md +1 -1
  471. package/templates/skills/agent-browser/content.md +1 -1
  472. package/templates/skills/apps/SKILL.md +749 -0
  473. package/templates/skills/apps/content.md +60 -22
  474. package/templates/skills/chat-sdk/config.json +14 -0
  475. package/templates/skills/chat-sdk/content.md +84 -0
  476. package/templates/skills/composio-gmail/content.md +7 -0
  477. package/templates/skills/composio-google-docs/content.md +1 -1
  478. package/templates/skills/email-domain-health/config.json +14 -0
  479. package/templates/skills/email-domain-health/content.md +131 -0
  480. package/templates/skills/kv-storage/content.md +2 -2
  481. package/templates/skills/pages/content.md +8 -10
  482. package/templates/skills/qa-loom/config.json +14 -0
  483. package/templates/skills/qa-loom/content.md +187 -0
  484. package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
  485. package/templates/skills/qa-loom/files/run-qa.sh +57 -0
  486. package/templates/skills/slack-interaction/content.md +4 -0
  487. package/templates/skills/swarm-extensions/content.md +2 -0
  488. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  489. package/templates/skills/swarm-scripts/config.json +1 -1
  490. package/templates/skills/swarm-scripts/content.md +4 -2
  491. package/templates/skills/workflow-iterate/content.md +38 -0
  492. package/dist/artifact-eczsknc3.js +0 -3843
  493. package/dist/cli-9xsmdpdt.js +0 -56377
  494. package/dist/cli-bd957dgb.js +0 -153
  495. package/dist/cli-q51yprfq.js +0 -1104
  496. package/dist/cli-t1ze64h3.js +0 -811
  497. package/dist/index-9ch1n761.js +0 -1102
  498. package/src/artifact-sdk/index.ts +0 -2
  499. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  500. package/src/artifact-sdk/port.ts +0 -12
  501. package/src/artifact-sdk/server.ts +0 -183
  502. package/src/artifact-sdk/tunnel.ts +0 -19
  503. package/src/commands/artifact.ts +0 -249
  504. package/src/http/ecosystem.ts +0 -77
  505. package/src/tests/artifact-commands.test.ts +0 -92
  506. package/src/tests/artifact-sdk.test.ts +0 -793
  507. package/src/tests/register-service-security.test.ts +0 -194
  508. package/src/tools/list-services.ts +0 -107
  509. package/src/tools/register-service.ts +0 -177
  510. package/src/tools/unregister-service.ts +0 -73
  511. package/src/tools/update-service-status.ts +0 -96
  512. package/templates/skills/artifacts/config.json +0 -14
  513. package/templates/skills/artifacts/content.md +0 -344
  514. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  515. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  516. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  517. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  518. package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
  519. package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
  520. package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
  521. package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
  522. package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
  523. package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
  524. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  525. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
@@ -14,9 +14,13 @@
14
14
  * Key schema:
15
15
  * task:slack:{channelId}:{threadTs}
16
16
  * task:agentmail:{threadId}
17
+ * task:chat-sdk:{adapter}:{encodeURIComponent(platformThreadId)}
18
+ * (Chat SDK thread ids carry `:`, so the
19
+ * part after the adapter is URI-encoded)
17
20
  * task:trackers:github:{owner}:{repo}:{issue|pr}:{number}
18
21
  * task:trackers:gitlab:{projectId}:{mr|issue}:{iid}
19
22
  * task:trackers:azure-devops:{repositoryId}:pr:{pullRequestId}
23
+ * task:trackers:azure-devops:{organization}:workitem:{workItemId}
20
24
  * task:trackers:linear:{issueIdentifier} (e.g. DES-42 — case preserved)
21
25
  * task:trackers:jira:{issueIdentifier} (e.g. PROJ-123 — case preserved)
22
26
  * task:schedule:{scheduleId}
@@ -38,13 +42,20 @@
38
42
 
39
43
  const SEPARATOR = ":";
40
44
 
41
- export type ContextKeyFamily = "slack" | "agentmail" | "trackers" | "schedule" | "workflow";
45
+ export type ContextKeyFamily =
46
+ | "slack"
47
+ | "agentmail"
48
+ | "chat-sdk"
49
+ | "trackers"
50
+ | "schedule"
51
+ | "workflow";
42
52
 
43
53
  export type TrackerProvider = "github" | "gitlab" | "azure-devops" | "linear" | "jira";
44
54
 
45
55
  export type ParsedContextKey =
46
56
  | { family: "slack"; parts: { channelId: string; threadTs: string } }
47
57
  | { family: "agentmail"; parts: { threadId: string } }
58
+ | { family: "chat-sdk"; parts: { adapter: string; threadId: string } }
48
59
  | {
49
60
  family: "trackers";
50
61
  subFamily: "github";
@@ -60,6 +71,11 @@ export type ParsedContextKey =
60
71
  subFamily: "azure-devops";
61
72
  parts: { repositoryId: string; kind: "pr"; pullRequestId: number };
62
73
  }
74
+ | {
75
+ family: "trackers";
76
+ subFamily: "azure-devops";
77
+ parts: { organization: string; kind: "workitem"; workItemId: number };
78
+ }
63
79
  | {
64
80
  family: "trackers";
65
81
  subFamily: "linear";
@@ -95,6 +111,42 @@ export function slackContextKey(input: { channelId: string; threadTs: string }):
95
111
  return ["task", "slack", channelId, threadTs].join(SEPARATOR);
96
112
  }
97
113
 
114
+ /**
115
+ * Chat SDK thread ids are `<adapter>:<platform id>` and the platform id itself
116
+ * may contain `:` (Telegram `telegram:<chatId>:<topicId>`, Slack
117
+ * `slack:<channel>:<ts>`). The adapter stays a plain key part; the rest is
118
+ * URI-encoded so the key keeps a fixed part count. `parseContextKey` returns
119
+ * the original thread id in `parts.threadId`.
120
+ */
121
+ export function chatSdkContextKey(threadId: string): string {
122
+ const raw = typeof threadId === "string" ? threadId : "";
123
+ const separatorIndex = raw.indexOf(SEPARATOR);
124
+ if (separatorIndex <= 0 || separatorIndex === raw.length - 1) {
125
+ throw new Error(
126
+ `context-key: chat-sdk thread id must be "<adapter>:<id>" (got ${JSON.stringify(threadId)})`,
127
+ );
128
+ }
129
+ const adapter = assertSafePart(raw.slice(0, separatorIndex), "adapter");
130
+ const rest = encodeURIComponent(raw.slice(separatorIndex + 1));
131
+ return ["task", "chat-sdk", adapter, rest].join(SEPARATOR);
132
+ }
133
+
134
+ /**
135
+ * The Chat SDK thread a contextKey points at, or null when the key is missing,
136
+ * malformed, or of another family. Never throws.
137
+ */
138
+ export function chatThreadOfContextKey(
139
+ key: string | null | undefined,
140
+ ): { adapter: string; threadId: string } | null {
141
+ if (!key) return null;
142
+ try {
143
+ const parsed = parseContextKey(key);
144
+ return parsed.family === "chat-sdk" ? parsed.parts : null;
145
+ } catch {
146
+ return null;
147
+ }
148
+ }
149
+
98
150
  export function agentmailContextKey(input: { threadId: string }): string {
99
151
  const threadId = assertSafePart(input.threadId, "threadId");
100
152
  return ["task", "agentmail", threadId].join(SEPARATOR);
@@ -158,6 +210,20 @@ export function azureDevOpsContextKey(input: {
158
210
  return ["task", "trackers", "azure-devops", repositoryId, "pr", pullRequestId].join(SEPARATOR);
159
211
  }
160
212
 
213
+ export function azureDevOpsWorkItemContextKey(input: {
214
+ organization: string;
215
+ workItemId: number;
216
+ }): string {
217
+ const organization = assertSafePart(input.organization, "organization");
218
+ const workItemId = assertSafePart(input.workItemId, "workItemId");
219
+ if (!/^\d+$/.test(workItemId)) {
220
+ throw new Error(
221
+ `context-key: azure-devops "workItemId" must be a positive integer (got ${JSON.stringify(workItemId)})`,
222
+ );
223
+ }
224
+ return ["task", "trackers", "azure-devops", organization, "workitem", workItemId].join(SEPARATOR);
225
+ }
226
+
161
227
  export function linearContextKey(input: { issueIdentifier: string }): string {
162
228
  const issueIdentifier = assertSafePart(input.issueIdentifier, "issueIdentifier");
163
229
  return ["task", "trackers", "linear", issueIdentifier].join(SEPARATOR);
@@ -235,6 +301,19 @@ export function parseContextKey(key: string): ParsedContextKey {
235
301
  }
236
302
  return { family: "agentmail", parts: { threadId: parts[2] as string } };
237
303
  }
304
+ case "chat-sdk": {
305
+ if (parts.length !== 4 || !parts[2] || !parts[3]) {
306
+ throw new Error(`context-key: malformed chat-sdk key: ${JSON.stringify(key)}`);
307
+ }
308
+ const adapter = parts[2];
309
+ let rest: string;
310
+ try {
311
+ rest = decodeURIComponent(parts[3]);
312
+ } catch {
313
+ throw new Error(`context-key: malformed chat-sdk key: ${JSON.stringify(key)}`);
314
+ }
315
+ return { family: "chat-sdk", parts: { adapter, threadId: `${adapter}:${rest}` } };
316
+ }
238
317
  case "schedule": {
239
318
  if (parts.length !== 3) {
240
319
  throw new Error(`context-key: malformed schedule key: ${JSON.stringify(key)}`);
@@ -293,10 +372,23 @@ export function parseContextKey(key: string): ParsedContextKey {
293
372
  };
294
373
  }
295
374
  if (subFamily === "azure-devops") {
296
- if (parts.length !== 6 || parts[4] !== "pr") {
375
+ if (parts.length !== 6 || (parts[4] !== "pr" && parts[4] !== "workitem")) {
297
376
  throw new Error(`context-key: malformed azure-devops key: ${JSON.stringify(key)}`);
298
377
  }
299
378
  const idStr = parts[5] as string;
379
+ if (parts[4] === "workitem") {
380
+ const workItemId = Number.parseInt(idStr, 10);
381
+ if (!/^\d+$/.test(idStr) || !Number.isFinite(workItemId)) {
382
+ throw new Error(
383
+ `context-key: malformed azure-devops workItemId "${idStr}": ${JSON.stringify(key)}`,
384
+ );
385
+ }
386
+ return {
387
+ family: "trackers",
388
+ subFamily: "azure-devops",
389
+ parts: { organization: parts[3] as string, kind: "workitem", workItemId },
390
+ };
391
+ }
300
392
  const pullRequestId = Number.parseInt(idStr, 10);
301
393
  if (!Number.isFinite(pullRequestId)) {
302
394
  throw new Error(
@@ -0,0 +1,67 @@
1
+ import type { AgentTask } from "../types";
2
+
3
+ /** Missing fields read as unset, so a bare `{ model }` is its own pin. */
4
+ export type TaskModelPinFields = {
5
+ [K in
6
+ | "model"
7
+ | "modelSource"
8
+ | "modelAlias"
9
+ | "modelTier"
10
+ | "resolvedModel"
11
+ | "claudeSessionId"]?: AgentTask[K] | null;
12
+ };
13
+
14
+ /**
15
+ * The task's own `model` pin, or undefined when the task has none.
16
+ *
17
+ * `agent_tasks.model` is not always the creator's pin: the worker reports the
18
+ * model it actually ran on `PUT /api/tasks/{id}/session`, which overwrites the
19
+ * column. So the pin is read from the claim-time record instead:
20
+ * - `modelSource = "model"`: the task's own `model` won at claim. A `latest:`
21
+ * alias survives only in `modelAlias` (the session report replaced `model`
22
+ * with the concrete id), so the alias is the pin.
23
+ * - `modelSource = "fallback:cli-unsupported:model"`: the task's own
24
+ * `latest:` alias won, then the claiming CLI rejected what it resolved to.
25
+ * The alias in `modelAlias` is the pin, with or without a `modelTier`.
26
+ * - `modelSource = "fallback:cli-unsupported"` (a tier layer's alias fell
27
+ * back) is not a pin. Rows written before the `:model` variant existed are
28
+ * ambiguous; one with a `modelAlias` and no `modelTier` can only have come
29
+ * from a `model` alias, so its alias is the pin. With a `modelTier` it stays
30
+ * ambiguous and only the tier counts.
31
+ * - no claim record and no session: `model` is still the creator's value.
32
+ * Anything else (a tier layer won, or `model` is just the session report) is
33
+ * not a pin: re-running the row must resolve the model again, from the agent's
34
+ * current config, instead of replaying the model of the previous run.
35
+ */
36
+ export function taskModelPin(task: TaskModelPinFields): string | undefined {
37
+ if (task.modelSource === "model") return task.modelAlias ?? task.model ?? undefined;
38
+ if (task.modelSource === "fallback:cli-unsupported:model" && task.modelAlias) {
39
+ return task.modelAlias;
40
+ }
41
+ if (task.modelSource === "fallback:cli-unsupported" && task.modelAlias && !task.modelTier) {
42
+ return task.modelAlias;
43
+ }
44
+ if (!task.modelSource && !task.resolvedModel && !task.claudeSessionId) {
45
+ return task.model ?? undefined;
46
+ }
47
+ return undefined;
48
+ }
49
+
50
+ /**
51
+ * The model fields a re-run of the SAME task row (paused-task resume) passes to
52
+ * the spawn: the pin and the claim record that resolved it, or nothing, so the
53
+ * worker resolves the model from the agent's current config.
54
+ */
55
+ export function resumedTaskModelSelection(task: TaskModelPinFields): {
56
+ model: string | undefined;
57
+ resolvedModel: string | undefined;
58
+ modelSource: string | undefined;
59
+ } {
60
+ const pin = taskModelPin(task);
61
+ if (!pin) return { model: undefined, resolvedModel: undefined, modelSource: undefined };
62
+ return {
63
+ model: pin,
64
+ resolvedModel: task.resolvedModel ?? undefined,
65
+ modelSource: task.modelSource ?? undefined,
66
+ };
67
+ }
@@ -32,6 +32,7 @@ import {
32
32
  } from "../types";
33
33
  import { isEnvFlagEnabled } from "../utils/env-flag";
34
34
  import { taskAttachmentDisplayUrl } from "../utils/task-attachment-links";
35
+ import { taskModelPin } from "./model-pin";
35
36
  import { createTaskWithSiblingAwareness } from "./sibling-awareness";
36
37
  // Side-effect import: registers task lifecycle templates in the in-memory registry.
37
38
  import "../tools/templates";
@@ -165,23 +166,8 @@ export function getNextResumeGeneration(parent: Pick<AgentTask, "tags">): number
165
166
  * reboot retry) must carry: the parent's portable `modelTier`, plus its
166
167
  * concrete `model` only when that `model` was a task-level pin.
167
168
  *
168
- * `agent_tasks.model` is not always the creator's pin: the worker reports the
169
- * model it actually ran on `POST /api/tasks/{id}/session`, which overwrites the
170
- * column. So the pin is read from the claim-time record instead:
171
- * - `modelSource = "model"`: the task's own `model` won at claim. A `latest:`
172
- * alias survives only in `modelAlias` (the session report replaced `model`
173
- * with the concrete id), so the alias is what travels.
174
- * - `modelSource = "fallback:cli-unsupported:model"`: the task's own
175
- * `latest:` alias won, then the claiming CLI rejected what it resolved to.
176
- * The alias in `modelAlias` travels, with or without a `modelTier`.
177
- * - `modelSource = "fallback:cli-unsupported"` (a tier layer's alias fell
178
- * back) is not a pin. Rows written before the `:model` variant existed are
179
- * ambiguous; one with a `modelAlias` and no `modelTier` can only have come
180
- * from a `model` alias, so its alias travels. With a `modelTier` it stays
181
- * ambiguous and only the tier travels.
182
- * - no claim record and no session: `model` is still the creator's value.
183
- * Anything else (a tier layer won, or `model` is just the session report) is
184
- * not a pin and is left off, so the resume resolves on its claiming worker.
169
+ * The pin rules live in `taskModelPin` (`./model-pin`); anything that is not
170
+ * a pin is left off, so the resume resolves on its claiming worker.
185
171
  *
186
172
  * `resolvedModel`, `modelSource` and `modelAlias` themselves are NOT copied:
187
173
  * claim time writes all three together for the task being claimed, and the
@@ -196,20 +182,7 @@ export function inheritedModelSelection(
196
182
  "model" | "modelTier" | "modelSource" | "modelAlias" | "resolvedModel" | "claudeSessionId"
197
183
  >,
198
184
  ): Pick<CreateTaskOptions, "model" | "modelTier"> {
199
- let model: string | undefined;
200
- if (parent.modelSource === "model") {
201
- model = parent.modelAlias ?? parent.model;
202
- } else if (parent.modelSource === "fallback:cli-unsupported:model" && parent.modelAlias) {
203
- model = parent.modelAlias;
204
- } else if (
205
- parent.modelSource === "fallback:cli-unsupported" &&
206
- parent.modelAlias &&
207
- !parent.modelTier
208
- ) {
209
- model = parent.modelAlias;
210
- } else if (!parent.modelSource && !parent.resolvedModel && !parent.claudeSessionId) {
211
- model = parent.model;
212
- }
185
+ const model = taskModelPin(parent);
213
186
  return {
214
187
  ...(model ? { model } : {}),
215
188
  ...(parent.modelTier ? { modelTier: parent.modelTier } : {}),
package/src/telemetry.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  } from "./telemetry-context";
25
25
  import type { PropsFor, TelemetryEventName } from "./telemetry-contract";
26
26
  import { isEnvFlagEnabled } from "./utils/env-flag";
27
+ import { getNodeEnv } from "./utils/node-env";
27
28
  import { normalizeOrgWebsite } from "./utils/org-website";
28
29
  import { getCurrentRequestUserId } from "./utils/request-auth-context";
29
30
 
@@ -588,7 +589,7 @@ function getTelemetryEnvironment(): string {
588
589
 
589
590
  // Do not default from NODE_ENV: shipped Bun/npm installs can report
590
591
  // "development" even when the operator did not choose a telemetry cohort.
591
- if (process.env.NODE_ENV === "test") return "test";
592
+ if (getNodeEnv() === "test") return "test";
592
593
  return "production";
593
594
  }
594
595
 
@@ -667,6 +667,48 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
667
667
  expect(resolveAcpTarget(config).env(config).OPENCODE_CONFIG_CONTENT).toBe(content);
668
668
  });
669
669
 
670
+ test("OpenCode preset adds the helmcode block with an {env:} key reference, never the key", () => {
671
+ const sentinel = "sk-helmcode-acp-sentinel-0123456789";
672
+ const config = baseConfig({
673
+ model: "helmcode/glm5.3",
674
+ env: {
675
+ ACP_TARGET: "opencode",
676
+ HELMCODE_API_KEY: sentinel,
677
+ OPENCODE_CONFIG_CONTENT: JSON.stringify({
678
+ provider: { helmcode: { options: { timeout: 1000 } } },
679
+ }),
680
+ },
681
+ });
682
+ const env = resolveAcpTarget(config).env(config);
683
+ expect(env.HELMCODE_API_KEY).toBe(sentinel);
684
+ expect(env.OPENCODE_CONFIG_CONTENT).not.toContain(sentinel);
685
+ const helmcode = JSON.parse(env.OPENCODE_CONFIG_CONTENT!).provider.helmcode;
686
+ expect(helmcode).toMatchObject({
687
+ npm: "@ai-sdk/openai-compatible",
688
+ name: "Helmcode",
689
+ env: [],
690
+ options: {
691
+ baseURL: "https://api.helmcode.com/v1",
692
+ apiKey: "{env:HELMCODE_API_KEY}",
693
+ timeout: 1000,
694
+ },
695
+ });
696
+ expect(helmcode.models["glm5.3"]).toMatchObject({
697
+ tool_call: true,
698
+ limit: { context: 1048576, output: 32768 },
699
+ });
700
+ });
701
+
702
+ test("OpenCode preset adds no custom block for a nan model", () => {
703
+ const config = baseConfig({
704
+ model: "nan/glm5.3-flash",
705
+ env: { ACP_TARGET: "opencode", NAN_API_KEY: "example-test-key" },
706
+ });
707
+ const env = resolveAcpTarget(config).env(config);
708
+ expect(env.NAN_API_KEY).toBe("example-test-key");
709
+ expect(JSON.parse(env.OPENCODE_CONFIG_CONTENT!).provider?.helmcode).toBeUndefined();
710
+ });
711
+
670
712
  test("OpenCode preset injects gateway even without a model fallback", () => {
671
713
  const config = baseConfig({
672
714
  model: "",
@@ -28,7 +28,6 @@ let sut: Sut;
28
28
  let api: ApiClient;
29
29
  let fixtureDir: string;
30
30
  let fixturePath: string;
31
- let pm2StubPath: string;
32
31
 
33
32
  /** A `claude` that initializes, accepts the prompt, and then never answers. */
34
33
  const hangingFixtureSource = `#!/usr/bin/env bun
@@ -87,12 +86,8 @@ describe("API drain with a real worker", () => {
87
86
  beforeAll(async () => {
88
87
  fixtureDir = await mkdtemp("/tmp/api-drain-worker-");
89
88
  fixturePath = join(fixtureDir, "claude-fixture");
90
- pm2StubPath = join(fixtureDir, "bin");
91
- await Bun.$`mkdir -p ${pm2StubPath}`.quiet();
92
89
  await Bun.write(fixturePath, hangingFixtureSource);
93
- await Bun.write(join(pm2StubPath, "pm2"), "#!/bin/sh\nexit 0\n");
94
90
  await Bun.$`chmod 755 ${fixturePath}`.quiet();
95
- await Bun.$`chmod 755 ${join(pm2StubPath, "pm2")}`.quiet();
96
91
  sut = await startSut(
97
92
  false,
98
93
  {},
@@ -138,7 +133,7 @@ describe("API drain with a real worker", () => {
138
133
  cwd: repoRoot,
139
134
  env: {
140
135
  ...minimalEnv(),
141
- PATH: `${pm2StubPath}:${process.env.PATH ?? "/usr/bin:/bin"}`,
136
+ PATH: process.env.PATH ?? "/usr/bin:/bin",
142
137
  HOME: home,
143
138
  AGENT_SWARM_API_KEY: sut.apiKey,
144
139
  API_KEY: sut.apiKey,