@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.
- package/README.md +1 -1
- package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
- package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
- package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
- package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
- package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
- package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
- package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
- package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
- package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
- package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
- 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-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
- package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-kb4ehzx5.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-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-zxm9p3x4.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-6jb2rf77.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-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
- 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-bf7485pm.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
- 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-1hgat6pa.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-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
- package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
- 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-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
- package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
- package/dist/cli-k3dp5tpf.js +263 -0
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
- package/dist/cli-p0sg24zp.js +16 -0
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-r8smj8b8.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-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-xczpdp9e.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-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
- package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
- package/dist/{cli-04emfe2q.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-hwwvy36w.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +32 -48
- package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
- package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
- package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-2h8m4cab.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-h3359cwn.js +52 -0
- package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
- package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
- package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
- package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
- package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
- package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
- package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
- package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
- 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-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
- package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
- package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
- package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
- package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
- package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
- package/dist/node-c9we95xf.js +1 -1
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
- package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
- package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
- package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
- package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
- package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
- package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
- package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
- package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
- package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
- package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +951 -356
- package/package.json +12 -13
- package/src/apps/catalog.generated.json +1309 -53
- package/src/apps/page-validator.ts +93 -31
- package/src/azure-devops/api.ts +94 -18
- package/src/azure-devops/auth.ts +32 -0
- package/src/azure-devops/boards-sync.ts +708 -0
- package/src/azure-devops/handlers.ts +52 -8
- package/src/azure-devops/html.ts +26 -0
- package/src/azure-devops/index.ts +15 -0
- package/src/azure-devops/templates.ts +86 -0
- package/src/azure-devops/types.ts +65 -1
- 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 +74 -13
- package/src/be/migrations/213_script_connections_sql.sql +79 -0
- 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-connections.ts +47 -8
- 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 +10 -18
- package/src/be/seed-skills/index.ts +107 -3
- package/src/be/sql-connections.ts +118 -0
- package/src/be/swarm-config-guard.ts +53 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/profile-sync.ts +5 -3
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +196 -56
- 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-oauth.ts +6 -13
- package/src/http/mcp.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +6 -5
- package/src/http/pages.ts +5 -14
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/route-def.ts +7 -6
- package/src/http/script-connection-proxy.ts +51 -4
- package/src/http/script-connections.ts +5 -2
- package/src/http/scripts.ts +1 -0
- package/src/http/session-cost-recompute.ts +12 -2
- package/src/http/session-data.ts +4 -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 +183 -2
- 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/jira/adf.ts +3 -1
- package/src/kv-reserved-namespaces.ts +2 -0
- package/src/oauth/mcp-wrapper.ts +10 -6
- package/src/otel-impl.ts +2 -1
- 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 +56 -3
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +27 -2
- package/src/providers/claude-flag-settings.ts +133 -0
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-sdk-session.ts +7 -0
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +268 -37
- package/src/providers/opencode-billing.ts +86 -0
- package/src/providers/opencode-swarm-plugin.ts +51 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +37 -3
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +11 -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/api-client.ts +15 -1
- package/src/scripts-runtime/api-types.ts +9 -1
- package/src/scripts-runtime/ctx.ts +1 -1
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/mcp-client.ts +30 -19
- 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/actions.ts +29 -1
- package/src/slack/app.ts +14 -2
- package/src/slack/assistant.ts +36 -2
- package/src/slack/channel-join.ts +3 -16
- package/src/slack/commands.ts +9 -1
- package/src/slack/event-dedup.ts +1 -1
- package/src/slack/external-channel-egress.ts +113 -0
- package/src/slack/external-channel.ts +309 -0
- package/src/slack/handlers.ts +61 -0
- package/src/slack/render-v2.ts +40 -47
- package/src/slack/work-objects.ts +5 -0
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +94 -2
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/telemetry.ts +2 -1
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/apps-catalog-feedback.test.ts +310 -0
- package/src/tests/apps-catalog-inputs.test.ts +70 -0
- package/src/tests/apps-catalog-table.test.ts +113 -0
- package/src/tests/azure-devops-boards-sync.test.ts +584 -0
- package/src/tests/azure-devops-html.test.ts +13 -0
- package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
- 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 +144 -0
- package/src/tests/claude-flag-settings.test.ts +114 -0
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
- package/src/tests/claude-sdk-process.fixture.ts +7 -0
- 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 +51 -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/deferred-task-wake.test.ts +52 -4
- 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/azure-boards/workitem.commented.json +89 -0
- package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
- package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
- package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
- package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
- package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
- package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
- package/src/tests/fixtures/catalog-table-definition.json.txt +468 -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-identity-refresh.ts +3 -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/node-env-runtime.test.ts +98 -0
- 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 +348 -3
- package/src/tests/opencode-billing.test.ts +28 -0
- 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-identity-refresh.test.ts +3 -0
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections-sql.test.ts +675 -0
- package/src/tests/script-connections.test.ts +7 -1
- 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 +94 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/slack-channel-join.test.ts +4 -1
- package/src/tests/slack-external-channel-config.test.ts +65 -0
- package/src/tests/slack-external-channel-egress.test.ts +237 -0
- package/src/tests/slack-external-channel-guard.test.ts +280 -0
- package/src/tests/slack-external-channel-tools.test.ts +173 -0
- package/src/tests/slack-external-channel.test.ts +370 -0
- package/src/tests/slack-render-v2.test.ts +86 -10
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/spec-base-url.test.ts +16 -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/vendored-openapi.test.ts +16 -1
- 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/defer-task.ts +17 -0
- 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/slack-post.ts +6 -0
- package/src/tools/slack-read.ts +8 -0
- package/src/tools/slack-reply.ts +6 -0
- package/src/tools/slack-start-thread.ts +6 -0
- package/src/tools/slack-update.ts +6 -0
- package/src/tools/slack-upload-file.ts +6 -0
- 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/node-env.ts +24 -0
- 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 +749 -0
- package/templates/skills/apps/content.md +60 -22
- 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/qa-loom/config.json +14 -0
- package/templates/skills/qa-loom/content.md +187 -0
- package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
- package/templates/skills/qa-loom/files/run-qa.sh +57 -0
- package/templates/skills/slack-interaction/content.md +4 -0
- 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-9xsmdpdt.js +0 -56377
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- 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/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
- package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
- package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
- package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
- package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
- package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { unlink } from "node:fs/promises";
|
|
5
|
+
import { createServer as createHttpServer, type Server } from "node:http";
|
|
6
|
+
import { closeDb, createAgent, getSwarmConfigs, initDb, upsertSwarmConfig } from "../be/db";
|
|
7
|
+
import { handleConfig } from "../http/config";
|
|
8
|
+
import { getPathSegments, parseQueryParams } from "../http/utils";
|
|
9
|
+
import { registerSetConfigTool } from "../tools/swarm-config/set-config";
|
|
10
|
+
import { ENV_EXPORT_RESTRICTED_KEYS, envExportRestrictedError } from "../utils/config-env-export";
|
|
11
|
+
import { setRequestAuth } from "../utils/request-auth-context";
|
|
12
|
+
import { clearVolatileSecretsForTesting } from "../utils/secret-scrubber";
|
|
13
|
+
import { listenOnFreePort } from "./test-net";
|
|
14
|
+
|
|
15
|
+
const TEST_DB_PATH = "./test-swarm-config-export-to-env.sqlite";
|
|
16
|
+
const LEAD_ID = "21111111-1111-1111-1111-111111111111";
|
|
17
|
+
const MIGRATION = "src/be/migrations/215_swarm_config_export_to_env.sql";
|
|
18
|
+
|
|
19
|
+
type ToolHandler = (args: unknown, meta: unknown) => Promise<unknown> | unknown;
|
|
20
|
+
|
|
21
|
+
class MockMcpServer {
|
|
22
|
+
handlers = new Map<string, ToolHandler>();
|
|
23
|
+
registerTool(name: string, _config: unknown, handler: ToolHandler) {
|
|
24
|
+
this.handlers.set(name, handler);
|
|
25
|
+
return { name };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const requestInfo = {
|
|
30
|
+
sessionId: "test-session",
|
|
31
|
+
requestInfo: { headers: { "x-agent-id": LEAD_ID } },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
describe("swarm_config exportToEnv", () => {
|
|
35
|
+
let server: Server;
|
|
36
|
+
let baseUrl = "";
|
|
37
|
+
const mcpServer = new MockMcpServer();
|
|
38
|
+
|
|
39
|
+
beforeAll(async () => {
|
|
40
|
+
initDb(TEST_DB_PATH);
|
|
41
|
+
await createAgent({
|
|
42
|
+
id: LEAD_ID,
|
|
43
|
+
name: "export-to-env-test-lead",
|
|
44
|
+
isLead: true,
|
|
45
|
+
status: "idle",
|
|
46
|
+
capabilities: [],
|
|
47
|
+
});
|
|
48
|
+
registerSetConfigTool(mcpServer as unknown as Parameters<typeof registerSetConfigTool>[0]);
|
|
49
|
+
server = createHttpServer(async (req, res) => {
|
|
50
|
+
setRequestAuth(req, { kind: "operator", fingerprint: "test" });
|
|
51
|
+
const handled = await handleConfig(
|
|
52
|
+
req,
|
|
53
|
+
res,
|
|
54
|
+
getPathSegments(req.url || ""),
|
|
55
|
+
parseQueryParams(req.url || ""),
|
|
56
|
+
);
|
|
57
|
+
if (!handled) {
|
|
58
|
+
res.writeHead(404);
|
|
59
|
+
res.end();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
baseUrl = `http://localhost:${await listenOnFreePort(server)}`;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
afterAll(async () => {
|
|
66
|
+
clearVolatileSecretsForTesting();
|
|
67
|
+
server.close();
|
|
68
|
+
closeDb();
|
|
69
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
70
|
+
await unlink(`${TEST_DB_PATH}${suffix}`).catch(() => {});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("new rows export by default; an update without the flag keeps it", async () => {
|
|
75
|
+
const created = await upsertSwarmConfig({ scope: "global", key: "EXPORT_A", value: "1" });
|
|
76
|
+
expect(created.exportToEnv).toBe(true);
|
|
77
|
+
|
|
78
|
+
const off = await upsertSwarmConfig({
|
|
79
|
+
scope: "global",
|
|
80
|
+
key: "EXPORT_A",
|
|
81
|
+
value: "2",
|
|
82
|
+
isSecret: true,
|
|
83
|
+
exportToEnv: false,
|
|
84
|
+
});
|
|
85
|
+
expect(off.exportToEnv).toBe(false);
|
|
86
|
+
|
|
87
|
+
const kept = await upsertSwarmConfig({
|
|
88
|
+
scope: "global",
|
|
89
|
+
key: "EXPORT_A",
|
|
90
|
+
value: "3",
|
|
91
|
+
isSecret: true,
|
|
92
|
+
});
|
|
93
|
+
expect(kept.exportToEnv).toBe(false);
|
|
94
|
+
|
|
95
|
+
const on = await upsertSwarmConfig({
|
|
96
|
+
scope: "global",
|
|
97
|
+
key: "EXPORT_A",
|
|
98
|
+
value: "4",
|
|
99
|
+
exportToEnv: true,
|
|
100
|
+
});
|
|
101
|
+
expect(on.exportToEnv).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("default-off keys start off on create but accept an explicit true", async () => {
|
|
105
|
+
const created = await upsertSwarmConfig({
|
|
106
|
+
scope: "global",
|
|
107
|
+
key: "KAPSO_WEBHOOK_HMAC_SECRET",
|
|
108
|
+
value: "k",
|
|
109
|
+
isSecret: true,
|
|
110
|
+
});
|
|
111
|
+
expect(created.exportToEnv).toBe(false);
|
|
112
|
+
|
|
113
|
+
const optedIn = await upsertSwarmConfig({
|
|
114
|
+
scope: "global",
|
|
115
|
+
key: "X_CLIENT_SECRET",
|
|
116
|
+
value: "x",
|
|
117
|
+
isSecret: true,
|
|
118
|
+
exportToEnv: true,
|
|
119
|
+
});
|
|
120
|
+
expect(optedIn.exportToEnv).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("restricted keys store false and reject true through DB, HTTP, and MCP", async () => {
|
|
124
|
+
const key = "SLACK_SIGNING_SECRET";
|
|
125
|
+
const stored = await upsertSwarmConfig({ scope: "global", key, value: "s", isSecret: true });
|
|
126
|
+
expect(stored.exportToEnv).toBe(false);
|
|
127
|
+
const connection = await upsertSwarmConfig({
|
|
128
|
+
scope: "global",
|
|
129
|
+
key: "connection.example.secret",
|
|
130
|
+
value: "s",
|
|
131
|
+
isSecret: true,
|
|
132
|
+
});
|
|
133
|
+
expect(connection.exportToEnv).toBe(false);
|
|
134
|
+
|
|
135
|
+
const body = { scope: "global" as const, key, value: "s", isSecret: true, exportToEnv: true };
|
|
136
|
+
await expect(upsertSwarmConfig(body)).rejects.toThrow(envExportRestrictedError(key));
|
|
137
|
+
|
|
138
|
+
const res = await fetch(`${baseUrl}/api/config`, {
|
|
139
|
+
method: "PUT",
|
|
140
|
+
headers: { "Content-Type": "application/json" },
|
|
141
|
+
body: JSON.stringify(body),
|
|
142
|
+
});
|
|
143
|
+
expect(res.status).toBe(400);
|
|
144
|
+
expect(await res.json()).toMatchObject({ error: envExportRestrictedError(key) });
|
|
145
|
+
|
|
146
|
+
const result = (await mcpServer.handlers.get("set-config")!(body, requestInfo)) as {
|
|
147
|
+
structuredContent: { success: boolean; message: string };
|
|
148
|
+
};
|
|
149
|
+
expect(result.structuredContent.success).toBe(false);
|
|
150
|
+
expect(result.structuredContent.message).toBe(envExportRestrictedError(key));
|
|
151
|
+
|
|
152
|
+
const [row] = await getSwarmConfigs({ key });
|
|
153
|
+
expect(row?.exportToEnv).toBe(false);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("the config API and /api/config/resolved carry the flag", async () => {
|
|
157
|
+
const put = await fetch(`${baseUrl}/api/config`, {
|
|
158
|
+
method: "PUT",
|
|
159
|
+
headers: { "Content-Type": "application/json" },
|
|
160
|
+
body: JSON.stringify({
|
|
161
|
+
scope: "global",
|
|
162
|
+
key: "EXPORT_B",
|
|
163
|
+
value: "b",
|
|
164
|
+
isSecret: true,
|
|
165
|
+
exportToEnv: false,
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
expect(put.status).toBe(200);
|
|
169
|
+
expect(await put.json()).toMatchObject({ key: "EXPORT_B", exportToEnv: false });
|
|
170
|
+
|
|
171
|
+
const resolved = await fetch(`${baseUrl}/api/config/resolved?key=EXPORT_B`);
|
|
172
|
+
const { configs } = (await resolved.json()) as {
|
|
173
|
+
configs: Array<{ key: string; exportToEnv: boolean }>;
|
|
174
|
+
};
|
|
175
|
+
expect(configs).toEqual([expect.objectContaining({ key: "EXPORT_B", exportToEnv: false })]);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("set-config accepts the flag and keeps it on a later write", async () => {
|
|
179
|
+
const handler = mcpServer.handlers.get("set-config")!;
|
|
180
|
+
await handler(
|
|
181
|
+
{ scope: "global", key: "EXPORT_C", value: "c", isSecret: true, exportToEnv: false },
|
|
182
|
+
requestInfo,
|
|
183
|
+
);
|
|
184
|
+
await handler({ scope: "global", key: "EXPORT_C", value: "c2", isSecret: true }, requestInfo);
|
|
185
|
+
const [row] = await getSwarmConfigs({ key: "EXPORT_C" });
|
|
186
|
+
expect(row?.exportToEnv).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe("migration 215", () => {
|
|
191
|
+
// Keys agents read from their own env today (PR #2156 review audit, plus
|
|
192
|
+
// harness, git and agent-fs credentials). None may land on the deny list.
|
|
193
|
+
const MUST_STAY_EXPORTED = [
|
|
194
|
+
"AGENTMAIL_API_KEY",
|
|
195
|
+
"ATTIO_API_KEY",
|
|
196
|
+
"DOKPLOY_API_KEY",
|
|
197
|
+
"ELEVENLABS_API_KEY",
|
|
198
|
+
"EXA_API_KEY",
|
|
199
|
+
"GSC_SERVICE_ACCOUNT_BASE64",
|
|
200
|
+
"HETZNER_API_KEY",
|
|
201
|
+
"IMGFLIP_PASSWORD",
|
|
202
|
+
"IMGFLIP_USERNAME",
|
|
203
|
+
"KAPSO_API_KEY",
|
|
204
|
+
"PLAUSIBLE_API_KEY",
|
|
205
|
+
"SPRITES_API_KEY",
|
|
206
|
+
"SUPERAGENT_API_KEY",
|
|
207
|
+
"TURSO_API_TOKEN",
|
|
208
|
+
"TURSO_DB_TOKEN",
|
|
209
|
+
"TURSO_X_POSTS_DB_TOKEN",
|
|
210
|
+
"WORKDIR_API_KEY",
|
|
211
|
+
"X_ACCESS_TOKEN",
|
|
212
|
+
"X_ACCESS_TOKEN_SECRET",
|
|
213
|
+
"X_API_KEY",
|
|
214
|
+
"X_API_SECRET",
|
|
215
|
+
"X_BEARER_TOKEN",
|
|
216
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
217
|
+
"OPENROUTER_API_KEY",
|
|
218
|
+
"GITHUB_TOKEN",
|
|
219
|
+
"AGENT_FS_API_KEY",
|
|
220
|
+
"SLACK_BOT_TOKEN",
|
|
221
|
+
"SELF_DRIVING_WEBHOOK_SECRET",
|
|
222
|
+
"DESPLEGA_PROD_DATABASE_URL",
|
|
223
|
+
"GWS_CREDS_BASE64",
|
|
224
|
+
"codex_oauth_1",
|
|
225
|
+
];
|
|
226
|
+
const DENY_ONLY = [
|
|
227
|
+
"KAPSO_WEBHOOK_HMAC_SECRET",
|
|
228
|
+
"SENTRY_TEST_APP_WEBHOOK_SECRET",
|
|
229
|
+
"TELEMETRY_CH_AUTH",
|
|
230
|
+
"HACK_AGENT_FS_ADMIN_KEY",
|
|
231
|
+
"X_CLIENT_SECRET",
|
|
232
|
+
"connection.example.secret",
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
test("backfills true and turns off only the deny list", () => {
|
|
236
|
+
const db = new Database(":memory:");
|
|
237
|
+
try {
|
|
238
|
+
db.exec(`CREATE TABLE swarm_config (
|
|
239
|
+
id TEXT PRIMARY KEY, scope TEXT NOT NULL, scopeId TEXT, key TEXT NOT NULL,
|
|
240
|
+
value TEXT NOT NULL, isSecret INTEGER NOT NULL DEFAULT 0, envPath TEXT,
|
|
241
|
+
description TEXT, createdAt TEXT NOT NULL, lastUpdatedAt TEXT NOT NULL,
|
|
242
|
+
encrypted INTEGER NOT NULL DEFAULT 0)`);
|
|
243
|
+
const insert = db.prepare(
|
|
244
|
+
"INSERT INTO swarm_config (id, scope, key, value, isSecret, createdAt, lastUpdatedAt) VALUES (?, 'global', ?, 'v', 1, 'now', 'now')",
|
|
245
|
+
);
|
|
246
|
+
const keys = [...MUST_STAY_EXPORTED, ...DENY_ONLY, ...ENV_EXPORT_RESTRICTED_KEYS];
|
|
247
|
+
for (const key of keys) insert.run(crypto.randomUUID(), key);
|
|
248
|
+
|
|
249
|
+
db.exec(readFileSync(MIGRATION, "utf8"));
|
|
250
|
+
|
|
251
|
+
const flags = Object.fromEntries(
|
|
252
|
+
db
|
|
253
|
+
.query<{ key: string; exportToEnv: number }, []>(
|
|
254
|
+
"SELECT key, exportToEnv FROM swarm_config",
|
|
255
|
+
)
|
|
256
|
+
.all()
|
|
257
|
+
.map((row) => [row.key, row.exportToEnv]),
|
|
258
|
+
);
|
|
259
|
+
for (const key of MUST_STAY_EXPORTED) expect([key, flags[key]]).toEqual([key, 1]);
|
|
260
|
+
for (const key of [...DENY_ONLY, ...ENV_EXPORT_RESTRICTED_KEYS]) {
|
|
261
|
+
expect([key, flags[key]]).toEqual([key, 0]);
|
|
262
|
+
}
|
|
263
|
+
} finally {
|
|
264
|
+
db.close();
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
createAgent,
|
|
7
7
|
deleteSwarmConfig,
|
|
8
8
|
getDbClient,
|
|
9
|
+
getInjectableGlobalConfigs,
|
|
9
10
|
getSwarmConfigById,
|
|
10
11
|
getSwarmConfigs,
|
|
11
12
|
initDb,
|
|
@@ -94,6 +95,20 @@ function createTestServer(): Server {
|
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
describe("Teams SDK env fallbacks", () => {
|
|
99
|
+
test("a global SERVICE_URL row is storable but never injected into env", async () => {
|
|
100
|
+
await upsertSwarmConfig({ scope: "global", key: "SERVICE_URL", value: "https://evil.example" });
|
|
101
|
+
try {
|
|
102
|
+
expect((await getSwarmConfigs({ scope: "global", key: "SERVICE_URL" })).length).toBe(1);
|
|
103
|
+
const injectable = await getInjectableGlobalConfigs();
|
|
104
|
+
expect(injectable.some((config) => config.key === "SERVICE_URL")).toBe(false);
|
|
105
|
+
} finally {
|
|
106
|
+
const rows = await getSwarmConfigs({ scope: "global", key: "SERVICE_URL" });
|
|
107
|
+
for (const row of rows) await deleteSwarmConfig(row.id);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
97
112
|
describe("swarm-config reserved keys guard", () => {
|
|
98
113
|
let server: Server;
|
|
99
114
|
let baseUrl = "";
|
|
@@ -139,6 +154,7 @@ describe("swarm-config reserved keys guard", () => {
|
|
|
139
154
|
"cors_allow_any_origin",
|
|
140
155
|
"EXTENSION_ALLOW_LEAD_ACTIVATION",
|
|
141
156
|
"extension_allow_lead_activation",
|
|
157
|
+
"CHAT_SDK_API_URL_OVERRIDES",
|
|
142
158
|
]) {
|
|
143
159
|
test(`rejects deployment-only ${key} through DB, HTTP, and MCP`, async () => {
|
|
144
160
|
const config = { scope: "global" as const, key, value: "true" };
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* anchor ids, severity badges) without dragging in a real DOM lib.
|
|
9
9
|
*/
|
|
10
10
|
import { describe, expect, test } from "bun:test";
|
|
11
|
-
import { SWARM_UI_JS } from "../
|
|
11
|
+
import { SWARM_UI_JS } from "../pages/browser-sdk";
|
|
12
12
|
|
|
13
13
|
const EXAMPLE_HUNK = {
|
|
14
14
|
hunks: [
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// What a task records about the model and effort it ran on, and what a re-run
|
|
2
|
+
// of the same row carries over. Regression for: an agent's model/effort changed
|
|
3
|
+
// in the dashboard, and the next run of a task kept the previous values.
|
|
4
|
+
|
|
5
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
6
|
+
import { unlink } from "node:fs/promises";
|
|
7
|
+
import {
|
|
8
|
+
closeDb,
|
|
9
|
+
createAgent,
|
|
10
|
+
createTaskExtended,
|
|
11
|
+
getTaskById,
|
|
12
|
+
initDb,
|
|
13
|
+
updateTaskClaudeSessionId,
|
|
14
|
+
} from "../be/db";
|
|
15
|
+
import { effectiveReasoningEffort } from "../providers/reasoning-effort";
|
|
16
|
+
import { resumedTaskModelSelection, taskModelPin } from "../tasks/model-pin";
|
|
17
|
+
|
|
18
|
+
const TEST_DB_PATH = "./test-task-model-effort-rerun.sqlite";
|
|
19
|
+
|
|
20
|
+
async function removeDbFiles(path: string): Promise<void> {
|
|
21
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
22
|
+
try {
|
|
23
|
+
await unlink(path + suffix);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
beforeAll(async () => {
|
|
31
|
+
await removeDbFiles(TEST_DB_PATH);
|
|
32
|
+
initDb(TEST_DB_PATH);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterAll(async () => {
|
|
36
|
+
closeDb();
|
|
37
|
+
await removeDbFiles(TEST_DB_PATH);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("taskModelPin", () => {
|
|
41
|
+
test("a model reported by a previous session is not a pin", () => {
|
|
42
|
+
expect(taskModelPin({ model: "claude-opus-5-5", claudeSessionId: "s1" })).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("a model a tier layer chose is not a pin", () => {
|
|
46
|
+
expect(
|
|
47
|
+
taskModelPin({
|
|
48
|
+
model: "claude-opus-5-5",
|
|
49
|
+
modelTier: "smart",
|
|
50
|
+
resolvedModel: "claude-opus-5-5",
|
|
51
|
+
modelSource: "tier-default",
|
|
52
|
+
}),
|
|
53
|
+
).toBeUndefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("the creator's model on an unclaimed row is the pin", () => {
|
|
57
|
+
expect(taskModelPin({ model: "claude-sonnet-5-5" })).toBe("claude-sonnet-5-5");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("a claimed pin keeps its alias", () => {
|
|
61
|
+
expect(
|
|
62
|
+
taskModelPin({
|
|
63
|
+
model: "claude-opus-5-5",
|
|
64
|
+
modelSource: "model",
|
|
65
|
+
modelAlias: "latest:anthropic/opus",
|
|
66
|
+
claudeSessionId: "s1",
|
|
67
|
+
}),
|
|
68
|
+
).toBe("latest:anthropic/opus");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("resumedTaskModelSelection", () => {
|
|
73
|
+
test("a paused unpinned task resumes without the previous run's model or claim record", () => {
|
|
74
|
+
expect(
|
|
75
|
+
resumedTaskModelSelection({
|
|
76
|
+
model: "claude-opus-5-5",
|
|
77
|
+
resolvedModel: "claude-opus-5-5",
|
|
78
|
+
modelSource: "tier-config",
|
|
79
|
+
modelTier: "smart",
|
|
80
|
+
claudeSessionId: "s1",
|
|
81
|
+
}),
|
|
82
|
+
).toEqual({ model: undefined, resolvedModel: undefined, modelSource: undefined });
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("a paused pinned task resumes on its pin", () => {
|
|
86
|
+
expect(
|
|
87
|
+
resumedTaskModelSelection({
|
|
88
|
+
model: "claude-sonnet-5-5",
|
|
89
|
+
resolvedModel: "claude-sonnet-5-5",
|
|
90
|
+
modelSource: "model",
|
|
91
|
+
claudeSessionId: "s1",
|
|
92
|
+
}),
|
|
93
|
+
).toEqual({
|
|
94
|
+
model: "claude-sonnet-5-5",
|
|
95
|
+
resolvedModel: "claude-sonnet-5-5",
|
|
96
|
+
modelSource: "model",
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("effectiveReasoningEffort", () => {
|
|
102
|
+
test("unset effort records nothing", () => {
|
|
103
|
+
expect(effectiveReasoningEffort("claude", "claude-opus-5-5", undefined)).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("harnesses without effort support record nothing", () => {
|
|
107
|
+
expect(effectiveReasoningEffort("devin", "", "high")).toBeNull();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("a level the model cannot take is dropped, the same as the adapter does", () => {
|
|
111
|
+
expect(effectiveReasoningEffort("claude", "not-a-reasoning-model", "high")).toBeNull();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("session report records the effort", () => {
|
|
116
|
+
test("the effort the session ran at lands on resolvedEffort, and a re-run replaces it", async () => {
|
|
117
|
+
const agent = await createAgent({ name: "effort-rerun", isLead: false, status: "idle" });
|
|
118
|
+
const task = await createTaskExtended("work", { agentId: agent.id });
|
|
119
|
+
|
|
120
|
+
// First run: the agent's REASONING_EFFORT_OVERRIDE was high.
|
|
121
|
+
await updateTaskClaudeSessionId(
|
|
122
|
+
task.id,
|
|
123
|
+
"run-1",
|
|
124
|
+
"claude",
|
|
125
|
+
undefined,
|
|
126
|
+
"claude-opus-5-5",
|
|
127
|
+
undefined,
|
|
128
|
+
undefined,
|
|
129
|
+
"high",
|
|
130
|
+
);
|
|
131
|
+
let row = await getTaskById(task.id);
|
|
132
|
+
expect(row?.resolvedEffort).toBe("high");
|
|
133
|
+
// The requested-effort column stays the creator's value, not a pin.
|
|
134
|
+
expect(row?.effort).toBeUndefined();
|
|
135
|
+
|
|
136
|
+
// Effort changed to low in the dashboard; the next run records low.
|
|
137
|
+
await updateTaskClaudeSessionId(
|
|
138
|
+
task.id,
|
|
139
|
+
"run-2",
|
|
140
|
+
"claude",
|
|
141
|
+
undefined,
|
|
142
|
+
"claude-opus-5-5",
|
|
143
|
+
undefined,
|
|
144
|
+
undefined,
|
|
145
|
+
"low",
|
|
146
|
+
);
|
|
147
|
+
row = await getTaskById(task.id);
|
|
148
|
+
expect(row?.resolvedEffort).toBe("low");
|
|
149
|
+
|
|
150
|
+
// Effort set back to Auto: the harness default applied, nothing to show.
|
|
151
|
+
await updateTaskClaudeSessionId(
|
|
152
|
+
task.id,
|
|
153
|
+
"run-3",
|
|
154
|
+
"claude",
|
|
155
|
+
undefined,
|
|
156
|
+
"claude-opus-5-5",
|
|
157
|
+
undefined,
|
|
158
|
+
undefined,
|
|
159
|
+
null,
|
|
160
|
+
);
|
|
161
|
+
row = await getTaskById(task.id);
|
|
162
|
+
expect(row?.resolvedEffort).toBeUndefined();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
buildRequesterProfilePrompt,
|
|
4
|
+
buildTaskSessionPrompts,
|
|
5
|
+
type TaskSessionContext,
|
|
6
|
+
} from "../commands/runner";
|
|
7
|
+
import { type BasePromptArgs, getTaskContextPrompt } from "../prompts/base-prompt";
|
|
8
|
+
import type { ProviderName } from "../types";
|
|
9
|
+
|
|
10
|
+
// The provider caches the system prompt as a prefix, so any per-task byte in it
|
|
11
|
+
// re-bills the whole prompt on the first call of every session. These tests pin
|
|
12
|
+
// the split: one agent, different tasks, requesters and repos, same system
|
|
13
|
+
// prompt; the per-task context still reaches the model, in the task prompt.
|
|
14
|
+
|
|
15
|
+
const agentArgs = (
|
|
16
|
+
provider: ProviderName,
|
|
17
|
+
extra: Partial<BasePromptArgs> = {},
|
|
18
|
+
): BasePromptArgs => ({
|
|
19
|
+
role: "worker",
|
|
20
|
+
agentId: "11111111-2222-3333-4444-555555555555",
|
|
21
|
+
name: "Ada",
|
|
22
|
+
provider,
|
|
23
|
+
traits: { hasMcp: true, hasLocalEnvironment: true, nativeSkillDiscovery: provider !== "codex" },
|
|
24
|
+
soulMd: "You are Ada.",
|
|
25
|
+
claudeMd: "# Agent: Ada\n\nAlways run the tests before you push.",
|
|
26
|
+
skillsSummary: [{ name: "commit", description: "Create a commit" }],
|
|
27
|
+
mcpServers: ["linear"],
|
|
28
|
+
...extra,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const sessionA: TaskSessionContext = {
|
|
32
|
+
repoContext: {
|
|
33
|
+
clonePath: "/workspace/personal/repos/alpha",
|
|
34
|
+
claudeMd: "Alpha repo rules.",
|
|
35
|
+
warning: "Alpha is behind origin",
|
|
36
|
+
autoStashes: [{ ref: "stash@{0}", message: "WIP alpha" }],
|
|
37
|
+
guidelines: {
|
|
38
|
+
prChecks: ["bun run lint"],
|
|
39
|
+
mergeChecks: ["CI green"],
|
|
40
|
+
allowMerge: false,
|
|
41
|
+
review: ["Check the db boundary"],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
slackContext: { channelId: "C0ALPHA", threadTs: "111.222" },
|
|
45
|
+
requestedBy: {
|
|
46
|
+
name: "Taras",
|
|
47
|
+
role: "CTO",
|
|
48
|
+
notes: "Lead with the answer.",
|
|
49
|
+
comms: { verbosity: "terse" },
|
|
50
|
+
},
|
|
51
|
+
cwdWarning: 'Note: The task requested working directory "/nope" but it does not exist.',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const sessionB: TaskSessionContext = {
|
|
55
|
+
repoContext: { clonePath: "/workspace/personal/repos/beta", guidelines: null },
|
|
56
|
+
requestedBy: { name: "Eze", role: "CEO", comms: { language: "Spanish" } },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// A heartbeat: no repository, no requester, no working directory.
|
|
60
|
+
const sessionC: TaskSessionContext = {};
|
|
61
|
+
|
|
62
|
+
async function build(args: BasePromptArgs, context: TaskSessionContext, taskPrompt: string) {
|
|
63
|
+
return buildTaskSessionPrompts({
|
|
64
|
+
basePromptArgs: args,
|
|
65
|
+
additionalSystemPrompt: "Operator note: be careful.",
|
|
66
|
+
taskPrompt,
|
|
67
|
+
context,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe("buildTaskSessionPrompts", () => {
|
|
72
|
+
for (const provider of ["claude", "codex", "opencode", "pi"] as const) {
|
|
73
|
+
test(`${provider}: the system prompt is byte-identical across tasks, requesters and repos`, async () => {
|
|
74
|
+
const a = await build(agentArgs(provider), sessionA, "/work-on-task aaa\n\nTask: alpha");
|
|
75
|
+
const b = await build(agentArgs(provider), sessionB, "/work-on-task bbb\n\nTask: beta");
|
|
76
|
+
const c = await build(agentArgs(provider), sessionC, "/work-on-task ccc\n\nTask: heartbeat");
|
|
77
|
+
|
|
78
|
+
expect(a.systemPrompt).toBe(b.systemPrompt);
|
|
79
|
+
expect(a.systemPrompt).toBe(c.systemPrompt);
|
|
80
|
+
expect(a.systemPrompt).toEndWith("\n\nOperator note: be careful.");
|
|
81
|
+
for (const perTask of ["## Repository", "## Requester Profile", "Taras", "Eze", "/nope"]) {
|
|
82
|
+
expect(a.systemPrompt).not.toContain(perTask);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
test("a scripts-only worker keeps the system prompt stable across Slack and non-Slack tasks", async () => {
|
|
88
|
+
const keys = ["SLACK_DISABLE", "SLACK_BOT_TOKEN", "SLACK_APP_TOKEN"] as const;
|
|
89
|
+
const saved = keys.map((key) => [key, process.env[key]] as const);
|
|
90
|
+
delete process.env.SLACK_DISABLE;
|
|
91
|
+
process.env.SLACK_BOT_TOKEN = "xoxb-test-token";
|
|
92
|
+
process.env.SLACK_APP_TOKEN = "xapp-test-token";
|
|
93
|
+
try {
|
|
94
|
+
const args = agentArgs("claude", { scriptsOnly: true });
|
|
95
|
+
const a = await build(args, sessionA, "task a");
|
|
96
|
+
const c = await build(args, sessionC, "task c");
|
|
97
|
+
expect(a.systemPrompt).toBe(c.systemPrompt);
|
|
98
|
+
expect(a.systemPrompt).not.toContain("C0ALPHA");
|
|
99
|
+
expect(a.prompt).toContain("## Slack (scripts-only)");
|
|
100
|
+
expect(a.prompt).toContain("C0ALPHA");
|
|
101
|
+
} finally {
|
|
102
|
+
for (const [key, value] of saved) {
|
|
103
|
+
if (value === undefined) delete process.env[key];
|
|
104
|
+
else process.env[key] = value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("the per-task context reaches the task prompt with the same text, after the task", async () => {
|
|
110
|
+
const args = agentArgs("opencode");
|
|
111
|
+
const taskPrompt = "/work-on-task aaa\n\nTask: alpha";
|
|
112
|
+
const { prompt } = await build(args, sessionA, taskPrompt);
|
|
113
|
+
|
|
114
|
+
const repoBlock = await getTaskContextPrompt({ ...args, repoContext: sessionA.repoContext });
|
|
115
|
+
const profile = await buildRequesterProfilePrompt(sessionA.requestedBy);
|
|
116
|
+
expect(repoBlock).toContain("## Repository");
|
|
117
|
+
expect(repoBlock).toContain("Alpha repo rules.");
|
|
118
|
+
expect(profile).toContain("This task was requested by Taras (CTO).");
|
|
119
|
+
|
|
120
|
+
expect(prompt).toStartWith(`${taskPrompt}\n\n`);
|
|
121
|
+
expect(prompt).toContain(repoBlock);
|
|
122
|
+
expect(prompt).toContain(profile);
|
|
123
|
+
expect(prompt).toEndWith(sessionA.cwdWarning ?? "");
|
|
124
|
+
expect(prompt.indexOf(repoBlock)).toBeLessThan(prompt.indexOf(profile));
|
|
125
|
+
expect(prompt).not.toMatch(/\n{3,}/);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("a task with no per-task context keeps its prompt unchanged", async () => {
|
|
129
|
+
const { prompt } = await build(agentArgs("claude"), sessionC, "/work-on-task ccc");
|
|
130
|
+
expect(prompt).toBe("/work-on-task ccc");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -27,6 +27,20 @@ describe("task tool manifests", () => {
|
|
|
27
27
|
]);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
+
test("chat-reply only preloads for a task carrying a chat-sdk contextKey", () => {
|
|
31
|
+
const manifest = parseTaskToolManifest('{"taskTypes":{"review":["chat-reply","script-run"]}}');
|
|
32
|
+
expect(selectTaskTools(manifest, { taskType: "review" })).toEqual(["script-run"]);
|
|
33
|
+
expect(
|
|
34
|
+
selectTaskTools(manifest, { taskType: "review", contextKey: "task:slack:C123:1700.1" }),
|
|
35
|
+
).toEqual(["script-run"]);
|
|
36
|
+
expect(
|
|
37
|
+
selectTaskTools(manifest, {
|
|
38
|
+
taskType: "review",
|
|
39
|
+
contextKey: "task:chat-sdk:telegram:555001",
|
|
40
|
+
}),
|
|
41
|
+
).toEqual(["chat-reply", "script-run"]);
|
|
42
|
+
});
|
|
43
|
+
|
|
30
44
|
test("config writes reject unknown tools, invalid shapes, and oversized selections", () => {
|
|
31
45
|
for (const value of [
|
|
32
46
|
"not json",
|
|
@@ -137,8 +137,10 @@ describe("task tool ctx", () => {
|
|
|
137
137
|
});
|
|
138
138
|
await updateAgentProfile(lead.id, { capabilities: ["merge"] });
|
|
139
139
|
await updateAgentProfile(underprivilegedLead.id, { capabilities: ["typescript"] });
|
|
140
|
+
// The sender created the parent, so it may continue it (task.parent.attach).
|
|
140
141
|
const parent = await createTaskExtended("privileged parent", {
|
|
141
142
|
agentId: lead.id,
|
|
143
|
+
creatorAgentId: sender.id,
|
|
142
144
|
routingAffinity: { capabilities: ["merge"], leadOnly: true },
|
|
143
145
|
});
|
|
144
146
|
|
|
@@ -116,7 +116,6 @@ describe("Tool Annotations & Classification", () => {
|
|
|
116
116
|
"delete-config",
|
|
117
117
|
"delete-workflow",
|
|
118
118
|
"delete-page",
|
|
119
|
-
"unregister-service",
|
|
120
119
|
"slack-delete",
|
|
121
120
|
"slack-archive-channel",
|
|
122
121
|
];
|
|
@@ -135,7 +134,6 @@ describe("Tool Annotations & Classification", () => {
|
|
|
135
134
|
"get-tasks",
|
|
136
135
|
"get-config",
|
|
137
136
|
"list-channels",
|
|
138
|
-
"list-services",
|
|
139
137
|
"list-schedules",
|
|
140
138
|
"list-config",
|
|
141
139
|
"memory-get",
|
|
@@ -350,7 +348,7 @@ describe("Tool Annotations & Classification", () => {
|
|
|
350
348
|
expect(missing).toEqual([]);
|
|
351
349
|
});
|
|
352
350
|
|
|
353
|
-
test("service tools
|
|
351
|
+
test("the removed PM2 service registry tools stay gone", () => {
|
|
354
352
|
const serviceTools = [
|
|
355
353
|
"register-service",
|
|
356
354
|
"unregister-service",
|
|
@@ -358,7 +356,8 @@ describe("Tool Annotations & Classification", () => {
|
|
|
358
356
|
"update-service-status",
|
|
359
357
|
];
|
|
360
358
|
for (const tool of serviceTools) {
|
|
361
|
-
expect(DEFERRED_TOOLS.has(tool)).toBe(
|
|
359
|
+
expect(DEFERRED_TOOLS.has(tool)).toBe(false);
|
|
360
|
+
expect(tools[tool]).toBeUndefined();
|
|
362
361
|
}
|
|
363
362
|
});
|
|
364
363
|
|
|
@@ -376,9 +375,10 @@ describe("Tool Annotations & Classification", () => {
|
|
|
376
375
|
// We expect all tools to be registered when all capabilities are enabled
|
|
377
376
|
// (this suite forces ALL_CAPABILITIES, including default-disabled ones).
|
|
378
377
|
// Includes 11 skill tools, 7 MCP server tools, reusable script tools, and the
|
|
379
|
-
// native Kapso/WhatsApp tools (register/unregister number + send/reply message)
|
|
378
|
+
// native Kapso/WhatsApp tools (register/unregister number + send/reply message),
|
|
379
|
+
// and the six Chat SDK tools (chat-* + register/unregister-chat-channel).
|
|
380
380
|
expect(count).toBeGreaterThanOrEqual(45);
|
|
381
|
-
expect(count).toBeLessThanOrEqual(
|
|
381
|
+
expect(count).toBeLessThanOrEqual(163);
|
|
382
382
|
});
|
|
383
383
|
|
|
384
384
|
test("core tools are fewer than deferred tools", () => {
|