@desplega.ai/agent-swarm 1.173.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-sj2g0m84.js} +17 -16
- package/dist/{actions-sgeyv08k.js → actions-fegk44gr.js} +39 -34
- package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{app-km9qnv2f.js → app-kfvgbvzy.js} +18 -14
- package/dist/{assistant-5r8tcvvd.js → assistant-z7zdy9ja.js} +40 -35
- package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-5c2z0mbe.js} +10 -9
- package/dist/{boot-reembed-16rv9843.js → boot-reembed-j8xa181e.js} +10 -9
- package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-hnkn3rgt.js} +11 -10
- package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-kwjq4d2z.js} +14 -13
- package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-9vmvpvgd.js} +19 -18
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
- package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-9jye6cxr.js} +11881 -11472
- package/dist/{cli-94b48jhk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-1w0vj3gw.js → cli-1e4b6bzh.js} +7 -7
- package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-x119kdba.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-srqq3gc5.js → cli-3fbmmawm.js} +5 -5
- package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
- package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
- package/dist/{cli-42qhyvwx.js → cli-5t4f29ez.js} +3 -3
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-0kxf81jj.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-w1apjecb.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-anzdk0z4.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-na2pxe4f.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-rfz2ve55.js → cli-bzszjf2p.js} +2855 -862
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
- package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
- package/dist/{cli-rfs4vddv.js → cli-d5f9ed5c.js} +5 -5
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
- package/dist/{cli-7a93cv8c.js → cli-ee9gtz70.js} +98 -23
- package/dist/{cli-3nxdmjrc.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-fmhj1ehj.js → cli-ef1hg1wv.js} +470 -51
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
- package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
- package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
- package/dist/{cli-s8z6x4b4.js → cli-j0pfptdp.js} +218 -102
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-5er5gjbm.js → cli-k382tshb.js} +10 -11
- package/dist/{cli-v3zhnxsb.js → cli-k3dp5tpf.js} +2 -2
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-ne7smj1b.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-xc7p7s3g.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-wrh08zjd.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-bv2etw2y.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-qm1448f9.js → cli-ne236afy.js} +8 -8
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-0a7mm3zp.js → cli-q0ke1yww.js} +25 -21
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-phcqp1b9.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-jpc4r224.js → cli-r62a35ea.js} +19 -3
- package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-r4fqfpwf.js → cli-s2sp957d.js} +50 -27
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-6thk4jz3.js → cli-se8w6wny.js} +6 -6
- package/dist/cli-skxvvpap.js +10140 -0
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
- package/dist/{cli-nwrdx840.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-r0byd61h.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
- package/dist/{cli-6r2f7edk.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-saqyage0.js → cli-vatyhshy.js} +179 -27
- package/dist/{cli-5wpw4rab.js → cli-vdach5a9.js} +5 -5
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/{cli-c3rk1v0x.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-9xf7fdtp.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +29 -45
- package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-y81sssk0.js} +15 -14
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-8vx4j6a9.js} +15 -14
- package/dist/{commands-z8fq9qna.js → commands-kcpvpcrr.js} +11 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-kwpvj3rf.js} +42 -37
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-yyhqqrbf.js → db-k8ankj20.js} +12 -11
- package/dist/{db-qfpq4bt7.js → db-ww5d7jq3.js} +28 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-x0x7qfcq.js → dispatcher-e8gq5m68.js} +38 -33
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-3epjm3af.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
- package/dist/{external-channel-h1fjecwe.js → external-channel-h3359cwn.js} +11 -10
- package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
- package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
- package/dist/{grok-adapter-e7mr287e.js → grok-adapter-0d4x7gkx.js} +18 -17
- package/dist/{handlers-znb9n7d4.js → handlers-an1gzv21.js} +41 -36
- package/dist/{heartbeat-bm4qkn8d.js → heartbeat-6dakeb61.js} +43 -38
- package/dist/{hook-254r4mza.js → hook-6v6cv6d5.js} +11 -23
- package/dist/{hook-xaa3q80s.js → hook-sa5xye4y.js} +12 -11
- package/dist/{http-3dgrgp8y.js → http-r7f3eky0.js} +1499 -251
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-fx3jqq1e.js → index-7ep4gzdk.js} +38 -33
- package/dist/index-9gw58n4k.js +193 -0
- package/dist/index-9j87mcm8.js +56305 -0
- package/dist/index-bsmcresk.js +79424 -0
- package/dist/index-mh85qhec.js +475 -0
- package/dist/{index-g2byveez.js → index-rmpw9a8q.js} +38 -33
- package/dist/{index-2ybk7khy.js → index-s2wxgzr0.js} +468 -683
- package/dist/{index-bdsqa799.js → index-v1v6n7hg.js} +43 -38
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-jd7sejm2.js → index-zk96aq1k.js} +10 -9
- package/dist/{keepalive-6ywhpja1.js → keepalive-be9vwy5h.js} +12 -11
- package/dist/{lead-cw45n21s.js → lead-0861cwrf.js} +61 -56
- package/dist/{maintenance-ss1a1ge9.js → maintenance-mzzgc8bn.js} +10 -9
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-cpdnfwdj.js} +11 -10
- package/dist/{onboard-8hzdhc1k.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-nm42wwj8.js} +18 -13
- package/dist/{otel-impl-e6mnvc4v.js → otel-impl-x6c1c9g4.js} +242 -868
- package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-9n2ya240.js} +244 -106
- package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-qb0rv0ap.js} +12 -11
- package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-1gzdwbh1.js} +11 -10
- package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-3mraey52.js} +12 -11
- package/dist/{render-v2-907cy6sa.js → render-v2-agpa45zz.js} +18 -14
- package/dist/{resume-42stcaz0.js → resume-x0ydy9s9.js} +25 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-adbc1c10.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
- package/dist/{work-objects-wpj8ck95.js → work-objects-y5g1y7ev.js} +41 -36
- package/dist/{worker-bzdra9rf.js → worker-860c3e38.js} +61 -56
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +523 -344
- package/package.json +10 -11
- package/src/be/config-refs.ts +60 -0
- package/src/be/db/page-versions.ts +15 -0
- package/src/be/db/runtime.ts +35 -8
- package/src/be/db/skill-name-resolution.ts +36 -0
- package/src/be/db/tasks/read.ts +230 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +52 -7
- package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
- package/src/be/migrations/216_task_resolved_effort.sql +5 -0
- package/src/be/migrations/217_chat_sdk_state.sql +104 -0
- package/src/be/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +12 -1
- package/src/be/model-validation.ts +5 -2
- package/src/be/models-catalog.ts +26 -1
- package/src/be/modelsdev-cache.json +198 -63
- package/src/be/modelsdev-cache.ts +9 -1
- package/src/be/script-credential-broker.ts +39 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -8
- package/src/be/seed/runner.ts +13 -1
- package/src/be/seed/state-db.ts +5 -0
- package/src/be/seed/types.ts +6 -0
- package/src/be/seed-pricing.ts +19 -2
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-skills/bundled-files.generated.json +0 -18
- package/src/be/seed-skills/index.ts +104 -3
- package/src/be/swarm-config-guard.ts +52 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +190 -54
- package/src/e2b/env.ts +5 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +45 -0
- package/src/extensions/dispatcher.ts +7 -0
- package/src/extensions/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/all-routes.ts +0 -1
- package/src/http/config.ts +36 -17
- package/src/http/core.ts +4 -0
- package/src/http/index.ts +14 -2
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +3 -3
- package/src/http/pages.ts +3 -13
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/scripts.ts +1 -0
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +61 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +159 -1
- package/src/http/x.ts +1 -0
- package/src/integrations/chat-sdk/adapters.ts +129 -0
- package/src/integrations/chat-sdk/attachments.ts +232 -0
- package/src/integrations/chat-sdk/background.ts +36 -0
- package/src/integrations/chat-sdk/commands.ts +194 -0
- package/src/integrations/chat-sdk/config.ts +198 -0
- package/src/integrations/chat-sdk/discord-api.ts +63 -0
- package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
- package/src/integrations/chat-sdk/handlers.ts +28 -0
- package/src/integrations/chat-sdk/inbound.ts +426 -0
- package/src/integrations/chat-sdk/limits.ts +48 -0
- package/src/integrations/chat-sdk/logger.ts +81 -0
- package/src/integrations/chat-sdk/outbound.ts +123 -0
- package/src/integrations/chat-sdk/relay.ts +172 -0
- package/src/integrations/chat-sdk/router.ts +169 -0
- package/src/integrations/chat-sdk/runtime.ts +351 -0
- package/src/integrations/chat-sdk/schema.ts +245 -0
- package/src/integrations/chat-sdk/state.ts +243 -0
- package/src/integrations/chat-sdk/status.ts +244 -0
- package/src/integrations/chat-sdk/steering.ts +58 -0
- package/src/integrations/chat-sdk/teams-origin.ts +77 -0
- package/src/integrations/chat-sdk/telegram-api.ts +56 -0
- package/src/integrations/chat-sdk/templates.ts +16 -0
- package/src/integrations/chat-sdk/test-hooks.ts +37 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
- package/src/integrations/chat-sdk/typing.ts +65 -0
- package/src/pages/version.ts +4 -5
- package/src/prompts/base-prompt.ts +111 -45
- package/src/providers/acp-target-catalog.ts +6 -0
- package/src/providers/acp-targets.ts +55 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +1 -1
- package/src/providers/claude-flag-settings.ts +17 -5
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +243 -26
- package/src/providers/opencode-swarm-plugin.ts +31 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +33 -2
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +6 -2
- package/src/rbac/legacy-policy.ts +8 -2
- package/src/rbac/permissions.ts +21 -0
- package/src/scheduler/scheduler.ts +4 -2
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/sdk-allowlist.ts +8 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +27 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
- package/src/server.ts +52 -18
- package/src/slack/event-dedup.ts +1 -1
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +60 -1
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +9 -4
- package/src/tests/claude-flag-settings.test.ts +11 -3
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
- package/src/tests/claude-thinking-tokens.test.ts +57 -0
- package/src/tests/claude-worker-parity.test.ts +2 -7
- package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
- package/src/tests/config-refs.test.ts +66 -0
- package/src/tests/context-key.test.ts +19 -0
- package/src/tests/cors-allowlist.test.ts +25 -0
- package/src/tests/create-page-tool.test.ts +18 -0
- package/src/tests/credential-check.test.ts +139 -0
- package/src/tests/credentials.test.ts +21 -0
- package/src/tests/db-runtime.test.ts +61 -0
- package/src/tests/db-task-read-contract.test.ts +20 -0
- package/src/tests/db-task-write-contract.test.ts +10 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/enabled-capabilities.test.ts +20 -0
- package/src/tests/entrypoint-api-readiness.test.ts +14 -8
- package/src/tests/entrypoint-config-env-export.test.ts +5 -2
- package/src/tests/entrypoint-export-to-env.test.ts +78 -0
- package/src/tests/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
- package/src/tests/extensions-post-bridge.test.ts +51 -0
- package/src/tests/fetch-resolved-env.test.ts +128 -0
- package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
- package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
- package/src/tests/github-handlers.test.ts +35 -0
- package/src/tests/harness-provider-resolution.test.ts +12 -0
- package/src/tests/heartbeat-checklist.test.ts +3 -2
- package/src/tests/hook-runtime-close.test.ts +0 -2
- package/src/tests/http-api-integration.test.ts +0 -25
- package/src/tests/migration-046-budgets.test.ts +17 -16
- package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
- package/src/tests/model-tier-resolution.test.ts +93 -0
- package/src/tests/models-catalog.test.ts +42 -1
- package/src/tests/openai-compatible-providers.test.ts +134 -0
- package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
- package/src/tests/opencode-adapter.test.ts +216 -2
- package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
- package/src/tests/opencode-shell-env.test.ts +145 -0
- package/src/tests/openrouter-base-url.test.ts +101 -151
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/pages-browser-sdk.test.ts +76 -0
- package/src/tests/pages-feedback.test.ts +1 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -0
- package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
- package/src/tests/pi-mono-adapter.test.ts +385 -5
- package/src/tests/pi-shell-env.test.ts +170 -0
- package/src/tests/prompt-template-remaining.test.ts +35 -0
- package/src/tests/rbac-engine.test.ts +11 -3
- package/src/tests/runner-exit-after-tasks.test.ts +0 -4
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/scripts-http.test.ts +201 -1
- package/src/tests/scripts-only-gating.test.ts +2 -3
- package/src/tests/scripts-runtime.test.ts +58 -40
- package/src/tests/secret-scrubber.test.ts +86 -0
- package/src/tests/seed-skills-bundled-files.test.ts +45 -53
- package/src/tests/seed-skills-retire.test.ts +182 -0
- package/src/tests/send-task-requester-gate.test.ts +58 -0
- package/src/tests/session-cost-recompute-unit.test.ts +46 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/swarm-config-export-to-env.test.ts +267 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
- package/src/tests/swarm-diff.test.ts +1 -1
- package/src/tests/task-model-effort-rerun.test.ts +164 -0
- package/src/tests/task-session-prompts.test.ts +132 -0
- package/src/tests/task-tool-manifest.test.ts +14 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-annotations.test.ts +6 -6
- package/src/tests/ui-logs-parser.test.ts +43 -0
- package/src/tests/used-by-route.test.ts +6 -0
- package/src/tests/vercel-ai-gateway.test.ts +149 -0
- package/src/tests/workflow-swarm-script.test.ts +38 -0
- package/src/tests/workflow-wait-filter.test.ts +5 -3
- package/src/tools/chat-access.ts +41 -0
- package/src/tools/chat-open-dm.ts +59 -0
- package/src/tools/chat-post.ts +74 -0
- package/src/tools/chat-read-thread.ts +100 -0
- package/src/tools/chat-reply.ts +75 -0
- package/src/tools/create-page.ts +3 -13
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/send-task.ts +24 -0
- package/src/tools/skills/skill-get.ts +17 -9
- package/src/tools/swarm-config/get-config.ts +2 -1
- package/src/tools/swarm-config/list-config.ts +2 -1
- package/src/tools/swarm-config/set-config.ts +16 -3
- package/src/tools/tool-config.ts +8 -6
- package/src/types.ts +12 -2
- package/src/utils/config-env-export.ts +74 -0
- package/src/utils/credentials.test.ts +92 -0
- package/src/utils/credentials.ts +52 -4
- package/src/utils/harness-provider.ts +15 -6
- package/src/utils/runtime-model-catalog.ts +11 -1
- package/src/utils/secret-scrubber.ts +71 -2
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/workflows/executors/swarm-script.ts +1 -0
- package/templates/skills/agent-browser/SKILL.md +1 -1
- package/templates/skills/agent-browser/content.md +1 -1
- package/templates/skills/apps/SKILL.md +8 -1
- package/templates/skills/apps/content.md +8 -1
- package/templates/skills/chat-sdk/config.json +14 -0
- package/templates/skills/chat-sdk/content.md +84 -0
- package/templates/skills/composio-gmail/content.md +7 -0
- package/templates/skills/composio-google-docs/content.md +1 -1
- package/templates/skills/email-domain-health/config.json +14 -0
- package/templates/skills/email-domain-health/content.md +131 -0
- package/templates/skills/kv-storage/content.md +2 -2
- package/templates/skills/pages/content.md +8 -10
- package/templates/skills/swarm-extensions/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +4 -2
- package/templates/skills/swarm-scripts/config.json +1 -1
- package/templates/skills/swarm-scripts/content.md +4 -2
- package/templates/skills/workflow-iterate/content.md +38 -0
- package/dist/artifact-eczsknc3.js +0 -3843
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- package/dist/cli-tcc4wd5d.js +0 -56471
- package/dist/index-9ch1n761.js +0 -1102
- package/src/artifact-sdk/index.ts +0 -2
- package/src/artifact-sdk/localtunnel.d.ts +0 -20
- package/src/artifact-sdk/port.ts +0 -12
- package/src/artifact-sdk/server.ts +0 -183
- package/src/artifact-sdk/tunnel.ts +0 -19
- package/src/commands/artifact.ts +0 -249
- package/src/http/ecosystem.ts +0 -77
- package/src/tests/artifact-commands.test.ts +0 -92
- package/src/tests/artifact-sdk.test.ts +0 -793
- package/src/tests/register-service-security.test.ts +0 -194
- package/src/tools/list-services.ts +0 -107
- package/src/tools/register-service.ts +0 -177
- package/src/tools/unregister-service.ts +0 -73
- package/src/tools/update-service-status.ts +0 -96
- package/templates/skills/artifacts/config.json +0 -14
- package/templates/skills/artifacts/content.md +0 -344
- package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
- package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
- package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
- package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
package/src/server.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { startPricingRefreshLoop } from "./be/pricing-refresh";
|
|
|
6
6
|
import { isSteeringEnabled } from "./be/steering";
|
|
7
7
|
import { registerGithubTaskReactions } from "./github/task-reactions";
|
|
8
8
|
import { loadGlobalConfigsIntoEnv } from "./http/core";
|
|
9
|
+
import { isChatSdkEnabled } from "./integrations/chat-sdk/config";
|
|
9
10
|
import { resolveTemplate } from "./prompts/resolver";
|
|
10
11
|
import { isRbacEnabled } from "./rbac";
|
|
11
12
|
import { getSlackConfiguration } from "./slack/config";
|
|
@@ -21,6 +22,10 @@ import { registerAppSyncTool } from "./tools/app-sync";
|
|
|
21
22
|
import { registerAppUpsertTool } from "./tools/app-upsert";
|
|
22
23
|
import { registerCancelApprovalRequestTool } from "./tools/cancel-approval-request";
|
|
23
24
|
import { registerCancelTaskTool } from "./tools/cancel-task";
|
|
25
|
+
import { registerChatOpenDmTool } from "./tools/chat-open-dm";
|
|
26
|
+
import { registerChatPostTool } from "./tools/chat-post";
|
|
27
|
+
import { registerChatReadThreadTool } from "./tools/chat-read-thread";
|
|
28
|
+
import { registerChatReplyTool } from "./tools/chat-reply";
|
|
24
29
|
import { registerContextDiffTool } from "./tools/context-diff";
|
|
25
30
|
import { registerContextHistoryTool } from "./tools/context-history";
|
|
26
31
|
import { registerCreateChannelTool } from "./tools/create-channel";
|
|
@@ -54,7 +59,6 @@ import {
|
|
|
54
59
|
} from "./tools/kv";
|
|
55
60
|
// Messaging capability
|
|
56
61
|
import { registerListChannelsTool } from "./tools/list-channels";
|
|
57
|
-
import { registerListServicesTool } from "./tools/list-services";
|
|
58
62
|
import { registerManageUserTool } from "./tools/manage-user";
|
|
59
63
|
// MCP Servers capability
|
|
60
64
|
import {
|
|
@@ -91,12 +95,15 @@ import {
|
|
|
91
95
|
} from "./tools/prompt-templates";
|
|
92
96
|
import { registerReadMessagesTool } from "./tools/read-messages";
|
|
93
97
|
import { registerRegisterAgentmailInboxTool } from "./tools/register-agentmail-inbox";
|
|
98
|
+
import {
|
|
99
|
+
registerRegisterChatChannelTool,
|
|
100
|
+
registerUnregisterChatChannelTool,
|
|
101
|
+
} from "./tools/register-chat-channel";
|
|
94
102
|
import {
|
|
95
103
|
registerRegisterKapsoNumberTool,
|
|
96
104
|
registerUnregisterKapsoNumberTool,
|
|
97
105
|
} from "./tools/register-kapso-number";
|
|
98
106
|
// Services capability
|
|
99
|
-
import { registerRegisterServiceTool } from "./tools/register-service";
|
|
100
107
|
// Repo management tools
|
|
101
108
|
import { registerGetReposTool, registerUpdateRepoTool } from "./tools/repos";
|
|
102
109
|
import { registerRequestHumanInputTool } from "./tools/request-human-input";
|
|
@@ -178,10 +185,8 @@ import {
|
|
|
178
185
|
registerTrackerSyncStatusTool,
|
|
179
186
|
registerTrackerUnlinkTool,
|
|
180
187
|
} from "./tools/tracker";
|
|
181
|
-
import { registerUnregisterServiceTool } from "./tools/unregister-service";
|
|
182
188
|
// Profiles capability
|
|
183
189
|
import { registerUpdateProfileTool } from "./tools/update-profile";
|
|
184
|
-
import { registerUpdateServiceStatusTool } from "./tools/update-service-status";
|
|
185
190
|
import { setPreloadedTools } from "./tools/utils";
|
|
186
191
|
import {
|
|
187
192
|
registerReplyWhatsappMessageTool,
|
|
@@ -216,7 +221,6 @@ export const ALL_CAPABILITIES = [
|
|
|
216
221
|
"prompt-templates",
|
|
217
222
|
"mcp",
|
|
218
223
|
"profiles",
|
|
219
|
-
"services",
|
|
220
224
|
"scheduling",
|
|
221
225
|
"memory",
|
|
222
226
|
"workflows",
|
|
@@ -230,6 +234,7 @@ export const ALL_CAPABILITIES = [
|
|
|
230
234
|
"repo",
|
|
231
235
|
"agentmail",
|
|
232
236
|
"kapso",
|
|
237
|
+
"chat-sdk",
|
|
233
238
|
"swarm-x",
|
|
234
239
|
] as const;
|
|
235
240
|
|
|
@@ -256,12 +261,12 @@ const DEFAULT_CAPABILITIES: string = [
|
|
|
256
261
|
//
|
|
257
262
|
// Disabled by default
|
|
258
263
|
//
|
|
259
|
-
// "services",
|
|
260
264
|
// "prompt-templates",
|
|
261
265
|
// "messaging",
|
|
262
266
|
// "swarm-x",
|
|
263
267
|
// "agentmail",
|
|
264
268
|
// "kapso",
|
|
269
|
+
// "chat-sdk", (added by getEnabledCapabilities when CHAT_SDK_ENABLED is true)
|
|
265
270
|
].join(",");
|
|
266
271
|
|
|
267
272
|
// Note: unknown names are kept (they never match hasCapability); workers
|
|
@@ -280,11 +285,22 @@ export function hasCapability(cap: CAPABILITIES_T): boolean {
|
|
|
280
285
|
return getCapabilities().has(cap);
|
|
281
286
|
}
|
|
282
287
|
|
|
288
|
+
const KNOWN_CAPABILITIES: ReadonlySet<string> = new Set(ALL_CAPABILITIES);
|
|
289
|
+
|
|
283
290
|
export function getEnabledCapabilities(): CAPABILITIES_T[] {
|
|
284
|
-
|
|
291
|
+
// Only known flags: the register response validates against ALL_CAPABILITIES,
|
|
292
|
+
// so a retired name still listed in CAPABILITIES (e.g. `services`) would
|
|
293
|
+
// otherwise turn every agent registration into a 500.
|
|
294
|
+
const capabilities: CAPABILITIES_T[] = Array.from(getCapabilities()).filter(
|
|
295
|
+
(capability) => KNOWN_CAPABILITIES.has(capability) && capability !== "chat-sdk",
|
|
296
|
+
);
|
|
297
|
+
// The Chat SDK channel follows CHAT_SDK_ENABLED, not the CAPABILITIES list.
|
|
298
|
+
if (isChatSdkEnabled()) capabilities.push("chat-sdk");
|
|
285
299
|
// Phase 1 has no HTTP receiver. Do not advertise usable Slack tools to
|
|
286
|
-
// workers when HTTP (or an invalid transport) was selected
|
|
287
|
-
|
|
300
|
+
// workers when HTTP (or an invalid transport) was selected, or when the
|
|
301
|
+
// built-in Slack app is off (SLACK_DISABLE, required by the Chat SDK Slack adapter).
|
|
302
|
+
const slack = getSlackConfiguration();
|
|
303
|
+
return slack.mode === "socket" && !slack.disabled
|
|
288
304
|
? capabilities
|
|
289
305
|
: capabilities.filter((capability) => capability !== "slack");
|
|
290
306
|
}
|
|
@@ -344,6 +360,13 @@ function applyToolAllowlist(server: McpServer, allowlist: readonly string[]): vo
|
|
|
344
360
|
}
|
|
345
361
|
}
|
|
346
362
|
|
|
363
|
+
function removeTools(server: McpServer, names: readonly string[]): void {
|
|
364
|
+
// oxlint-disable-next-line anti-slop/no-chained-type-assertions -- the MCP SDK keeps its tool registry private.
|
|
365
|
+
const tools = (server as unknown as { _registeredTools: Record<string, { remove(): void }> })
|
|
366
|
+
._registeredTools;
|
|
367
|
+
for (const name of names) tools[name]?.remove();
|
|
368
|
+
}
|
|
369
|
+
|
|
347
370
|
export async function createServer(
|
|
348
371
|
opts: {
|
|
349
372
|
scriptsOnly?: boolean;
|
|
@@ -351,6 +374,8 @@ export async function createServer(
|
|
|
351
374
|
preloadedTools?: readonly string[];
|
|
352
375
|
/** Raw SWARM_ENABLED_TOOLS value for this session; defaults to the env. */
|
|
353
376
|
enabledTools?: string;
|
|
377
|
+
/** Tool names removed from this session after registration (task-context filters). */
|
|
378
|
+
excludedTools?: readonly string[];
|
|
354
379
|
} = {},
|
|
355
380
|
) {
|
|
356
381
|
// Reload env
|
|
@@ -368,8 +393,12 @@ export async function createServer(
|
|
|
368
393
|
// fullSurface to register every tool group regardless of CAPABILITIES.
|
|
369
394
|
// An allowlist also registers every group, then prunes to the listed names.
|
|
370
395
|
// This shadows the module-level hasCapability for the registrations below.
|
|
396
|
+
// `chat-sdk` follows CHAT_SDK_ENABLED (as in getEnabledCapabilities), not
|
|
397
|
+
// the CAPABILITIES list.
|
|
371
398
|
const hasCapability = (cap: CAPABILITIES_T): boolean =>
|
|
372
|
-
opts.fullSurface === true ||
|
|
399
|
+
opts.fullSurface === true ||
|
|
400
|
+
toolAllowlist !== undefined ||
|
|
401
|
+
(cap === "chat-sdk" ? isChatSdkEnabled() : getCapabilities().has(cap));
|
|
373
402
|
|
|
374
403
|
// Initialize database with WAL mode
|
|
375
404
|
// Uses DATABASE_PATH env var for Docker volume compatibility (WAL needs .sqlite, .sqlite-wal, .sqlite-shm on same filesystem)
|
|
@@ -677,6 +706,16 @@ export async function createServer(
|
|
|
677
706
|
registerReplyWhatsappMessageTool(server);
|
|
678
707
|
}
|
|
679
708
|
|
|
709
|
+
// Chat SDK capability - Telegram/Slack/Discord/Teams through the Chat SDK channel (reply, post, DM, read, channel routes)
|
|
710
|
+
if (hasCapability("chat-sdk")) {
|
|
711
|
+
registerChatReplyTool(server);
|
|
712
|
+
registerChatPostTool(server);
|
|
713
|
+
registerChatOpenDmTool(server);
|
|
714
|
+
registerChatReadThreadTool(server);
|
|
715
|
+
registerRegisterChatChannelTool(server);
|
|
716
|
+
registerUnregisterChatChannelTool(server);
|
|
717
|
+
}
|
|
718
|
+
|
|
680
719
|
// Swarm-x capability - external command routes mirroring the `agent-swarm x ...` CLI surface
|
|
681
720
|
if (hasCapability("swarm-x")) {
|
|
682
721
|
registerSwarmXTool(server);
|
|
@@ -693,15 +732,10 @@ export async function createServer(
|
|
|
693
732
|
registerDeleteChannelTool(server);
|
|
694
733
|
}
|
|
695
734
|
|
|
696
|
-
// Services capability - PM2/background service registry
|
|
697
|
-
if (hasCapability("services")) {
|
|
698
|
-
registerRegisterServiceTool(server);
|
|
699
|
-
registerUnregisterServiceTool(server);
|
|
700
|
-
registerListServicesTool(server);
|
|
701
|
-
registerUpdateServiceStatusTool(server);
|
|
702
|
-
}
|
|
703
|
-
|
|
704
735
|
if (toolAllowlist) applyToolAllowlist(server, toolAllowlist);
|
|
736
|
+
if (opts.fullSurface !== true && opts.excludedTools?.length) {
|
|
737
|
+
removeTools(server, opts.excludedTools);
|
|
738
|
+
}
|
|
705
739
|
|
|
706
740
|
return server;
|
|
707
741
|
}
|
package/src/slack/event-dedup.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* safe-but-tight bound.
|
|
19
19
|
*
|
|
20
20
|
* Single-pod-only. The API server (which owns the Slack socket) runs as a
|
|
21
|
-
* single
|
|
21
|
+
* single API process; if that ever changes, swap this for a DB-backed table.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
const DEFAULT_TTL_MS = 300_000; // 5 minutes
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
* the underlying context becomes irrelevant — e.g. user cancels).
|
|
23
23
|
*
|
|
24
24
|
* Concurrency: single-process, single-event-loop. No cross-instance locking.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* The buffer is cleared BEFORE the callback fires, so re-enqueues during
|
|
26
|
+
* `onFlush` create a fresh buffer, and its flush can start while the earlier
|
|
27
|
+
* `onFlush` for the same key still runs. A caller that needs per-key order
|
|
28
|
+
* must serialize inside `onFlush`.
|
|
27
29
|
*/
|
|
28
30
|
|
|
29
31
|
export type BufferFlushReason = "timer" | "manual";
|
package/src/tasks/context-key.ts
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
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}
|
|
@@ -39,13 +42,20 @@
|
|
|
39
42
|
|
|
40
43
|
const SEPARATOR = ":";
|
|
41
44
|
|
|
42
|
-
export type ContextKeyFamily =
|
|
45
|
+
export type ContextKeyFamily =
|
|
46
|
+
| "slack"
|
|
47
|
+
| "agentmail"
|
|
48
|
+
| "chat-sdk"
|
|
49
|
+
| "trackers"
|
|
50
|
+
| "schedule"
|
|
51
|
+
| "workflow";
|
|
43
52
|
|
|
44
53
|
export type TrackerProvider = "github" | "gitlab" | "azure-devops" | "linear" | "jira";
|
|
45
54
|
|
|
46
55
|
export type ParsedContextKey =
|
|
47
56
|
| { family: "slack"; parts: { channelId: string; threadTs: string } }
|
|
48
57
|
| { family: "agentmail"; parts: { threadId: string } }
|
|
58
|
+
| { family: "chat-sdk"; parts: { adapter: string; threadId: string } }
|
|
49
59
|
| {
|
|
50
60
|
family: "trackers";
|
|
51
61
|
subFamily: "github";
|
|
@@ -101,6 +111,42 @@ export function slackContextKey(input: { channelId: string; threadTs: string }):
|
|
|
101
111
|
return ["task", "slack", channelId, threadTs].join(SEPARATOR);
|
|
102
112
|
}
|
|
103
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
|
+
|
|
104
150
|
export function agentmailContextKey(input: { threadId: string }): string {
|
|
105
151
|
const threadId = assertSafePart(input.threadId, "threadId");
|
|
106
152
|
return ["task", "agentmail", threadId].join(SEPARATOR);
|
|
@@ -255,6 +301,19 @@ export function parseContextKey(key: string): ParsedContextKey {
|
|
|
255
301
|
}
|
|
256
302
|
return { family: "agentmail", parts: { threadId: parts[2] as string } };
|
|
257
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
|
+
}
|
|
258
317
|
case "schedule": {
|
|
259
318
|
if (parts.length !== 3) {
|
|
260
319
|
throw new Error(`context-key: malformed schedule key: ${JSON.stringify(key)}`);
|
|
@@ -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
|
-
*
|
|
169
|
-
*
|
|
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
|
-
|
|
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 } : {}),
|
|
@@ -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:
|
|
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,
|