@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
|
@@ -95,6 +95,7 @@ type:McpServerFilters
|
|
|
95
95
|
type:McpServerInsert
|
|
96
96
|
type:MentionPreview
|
|
97
97
|
type:PageListOptions
|
|
98
|
+
type:PendingChatRelay
|
|
98
99
|
type:PlanSource
|
|
99
100
|
type:RecordBudgetRefusalNotificationInput
|
|
100
101
|
type:ScheduledTaskFilters
|
|
@@ -260,6 +261,7 @@ value:getAgentMcpServers
|
|
|
260
261
|
value:getAgentSkills
|
|
261
262
|
value:getAgentStatusCounts
|
|
262
263
|
value:getAgentWithTasks
|
|
264
|
+
value:getAgentWorkingOnContextKey
|
|
263
265
|
value:getAgentWorkingOnThread
|
|
264
266
|
value:getAllAgentMailInboxMappings
|
|
265
267
|
value:getAllAgents
|
|
@@ -321,8 +323,10 @@ value:getKv
|
|
|
321
323
|
value:getLastReadAt
|
|
322
324
|
value:getLastRunStart
|
|
323
325
|
value:getLastSuccessfulRun
|
|
326
|
+
value:getLatestActiveTaskByContextKey
|
|
324
327
|
value:getLatestActiveTaskInThread
|
|
325
328
|
value:getLatestContextVersion
|
|
329
|
+
value:getLatestLeadTaskByContextKey
|
|
326
330
|
value:getLatestLeadTaskInThread
|
|
327
331
|
value:getLatestPageBySlug
|
|
328
332
|
value:getLatestScriptRunStepTaskByContextKey
|
|
@@ -352,6 +356,7 @@ value:getPageVersion
|
|
|
352
356
|
value:getPageVersions
|
|
353
357
|
value:getPausedTasksForAgent
|
|
354
358
|
value:getPendingApprovalVoteState
|
|
359
|
+
value:getPendingChatRelayTasks
|
|
355
360
|
value:getPendingEventWaitNames
|
|
356
361
|
value:getPendingSlackRelayTasks
|
|
357
362
|
value:getPendingSteeringForAgent
|
|
@@ -449,6 +454,7 @@ value:getWorkflowRunStepsByRunId
|
|
|
449
454
|
value:getWorkflowVersion
|
|
450
455
|
value:getWorkflowVersions
|
|
451
456
|
value:getWorkflowsByScheduleId
|
|
457
|
+
value:giveUpStaleChatRelays
|
|
452
458
|
value:hasBudgetRefusalNotificationToday
|
|
453
459
|
value:hasCapacity
|
|
454
460
|
value:hasFirstCompletedTask
|
|
@@ -500,6 +506,9 @@ value:listUserFavorites
|
|
|
500
506
|
value:listWorkflowRuns
|
|
501
507
|
value:listWorkflowRunsPage
|
|
502
508
|
value:listWorkflows
|
|
509
|
+
value:markChatRelayAttempted
|
|
510
|
+
value:markChatRelayDelivered
|
|
511
|
+
value:markChatRelayGivenUp
|
|
503
512
|
value:markFinalizedSlackRelaysDelivered
|
|
504
513
|
value:markInboxMessageDelegated
|
|
505
514
|
value:markInboxMessageRead
|
|
@@ -528,6 +537,7 @@ value:promoteDraftTask
|
|
|
528
537
|
value:reassociateSessionLogs
|
|
529
538
|
value:recordApprovalVotes
|
|
530
539
|
value:recordBudgetRefusalNotification
|
|
540
|
+
value:recordChatRelayError
|
|
531
541
|
value:recordInlineScriptRun
|
|
532
542
|
value:recordKeyAuthFailure
|
|
533
543
|
value:recordKeyRateLimitWindows
|
|
@@ -76,9 +76,9 @@ afterAll(async () => {
|
|
|
76
76
|
await rm(dir, { recursive: true, force: true });
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
async function activeTask() {
|
|
79
|
+
async function activeTask(owner = agentId) {
|
|
80
80
|
const task = await createTaskExtended("work in progress", {
|
|
81
|
-
agentId,
|
|
81
|
+
agentId: owner,
|
|
82
82
|
modelTier: "smart",
|
|
83
83
|
priority: 70,
|
|
84
84
|
});
|
|
@@ -90,6 +90,7 @@ async function defer(
|
|
|
90
90
|
watchedId: string,
|
|
91
91
|
event: TaskWakeEvent = "settled",
|
|
92
92
|
extra: Record<string, unknown> = {},
|
|
93
|
+
caller = agentId,
|
|
93
94
|
) {
|
|
94
95
|
return tool.handler(
|
|
95
96
|
{
|
|
@@ -101,7 +102,7 @@ async function defer(
|
|
|
101
102
|
checks: ["verify output"],
|
|
102
103
|
...extra,
|
|
103
104
|
},
|
|
104
|
-
{ sessionId: crypto.randomUUID(), requestInfo: { headers: { "x-agent-id":
|
|
105
|
+
{ sessionId: crypto.randomUUID(), requestInfo: { headers: { "x-agent-id": caller } } },
|
|
105
106
|
);
|
|
106
107
|
}
|
|
107
108
|
async function fixture(event: TaskWakeEvent = "settled") {
|
|
@@ -364,10 +365,57 @@ describe("defer-task wakeOn", () => {
|
|
|
364
365
|
expect(await children(schedule.id)).toHaveLength(1);
|
|
365
366
|
});
|
|
366
367
|
|
|
368
|
+
test("duplicate watcher admission is atomic, agent-scoped, and permits the fired chain to re-defer", async () => {
|
|
369
|
+
const producer = await activeTask();
|
|
370
|
+
const sibling = await activeTask();
|
|
371
|
+
const first = await activeTask();
|
|
372
|
+
const second = await activeTask();
|
|
373
|
+
const results = await Promise.all([
|
|
374
|
+
defer(first.id, producer.id, "settled", {
|
|
375
|
+
wakeOn: { event: "settled", taskIds: [producer.id, sibling.id] },
|
|
376
|
+
}),
|
|
377
|
+
defer(second.id, producer.id),
|
|
378
|
+
]);
|
|
379
|
+
const accepted = results.find((result) => result.structuredContent.success)!;
|
|
380
|
+
const rejected = results.find((result) => !result.structuredContent.success)!;
|
|
381
|
+
expect(accepted).toBeDefined();
|
|
382
|
+
expect(rejected).toBeDefined();
|
|
383
|
+
expect(rejected.structuredContent.message).toContain(accepted.structuredContent.scheduleId!);
|
|
384
|
+
const rejectedTask = results[0] === rejected ? first : second;
|
|
385
|
+
expect((await getTaskById(rejectedTask.id))?.status).toBe("in_progress");
|
|
386
|
+
expect(
|
|
387
|
+
await getDbClient().query("SELECT id FROM scheduled_tasks WHERE parentTaskId = ?", [
|
|
388
|
+
rejectedTask.id,
|
|
389
|
+
]),
|
|
390
|
+
).toHaveLength(0);
|
|
391
|
+
|
|
392
|
+
const other = await createAgent({ name: "Independent watcher", isLead: false, status: "idle" });
|
|
393
|
+
const otherWatcher = await activeTask(other.id);
|
|
394
|
+
expect(
|
|
395
|
+
(await defer(otherWatcher.id, producer.id, "settled", {}, other.id)).structuredContent
|
|
396
|
+
.success,
|
|
397
|
+
).toBe(true);
|
|
398
|
+
const dispatched = await dispatchDeferredTaskWait(
|
|
399
|
+
accepted.structuredContent.scheduleId!,
|
|
400
|
+
"ceiling",
|
|
401
|
+
);
|
|
402
|
+
expect(dispatched?.task).toBeDefined();
|
|
403
|
+
await startTask(dispatched!.task!.id);
|
|
404
|
+
expect((await defer(dispatched!.task!.id, producer.id)).structuredContent.success).toBe(true);
|
|
405
|
+
});
|
|
406
|
+
|
|
367
407
|
test("two waiters follow a time-based deferral and fire once on the resume task's completion", async () => {
|
|
368
408
|
await initDeferredTaskWaits();
|
|
369
409
|
const { producer, schedule } = await fixture();
|
|
370
|
-
const
|
|
410
|
+
const secondAgent = await createAgent({ name: "Second waiter", isLead: false, status: "idle" });
|
|
411
|
+
const second = await defer(
|
|
412
|
+
(await activeTask(secondAgent.id)).id,
|
|
413
|
+
producer.id,
|
|
414
|
+
"task.completed",
|
|
415
|
+
{},
|
|
416
|
+
secondAgent.id,
|
|
417
|
+
);
|
|
418
|
+
expect(second.structuredContent.success).toBe(true);
|
|
371
419
|
const secondSchedule = (await getScheduledTaskById(second.structuredContent.scheduleId!))!;
|
|
372
420
|
const deferred = await defer(producer.id, producer.id, "settled", { wakeOn: undefined });
|
|
373
421
|
expect(deferred.structuredContent.success).toBe(true);
|
|
@@ -78,7 +78,7 @@ describe("docs API index footprint", () => {
|
|
|
78
78
|
expect(tasks).toContain('"path":"/api/task-templates","method":"get"');
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
test("OpenAPI and generated pages keep all
|
|
81
|
+
test("OpenAPI and generated pages keep all 425 operations", async () => {
|
|
82
82
|
const spec = await Bun.file(resolve(repoRoot, "openapi.json")).json();
|
|
83
83
|
const operationKeys = [];
|
|
84
84
|
const tags = new Set();
|
|
@@ -103,8 +103,8 @@ describe("docs API index footprint", () => {
|
|
|
103
103
|
expect(spec.paths["/api/agents/{id}/runtime"]?.get).toBeDefined();
|
|
104
104
|
|
|
105
105
|
const generatedKeys = await generatedOperationKeys();
|
|
106
|
-
expect(operationKeys).toHaveLength(
|
|
107
|
-
expect(generatedKeys).toHaveLength(
|
|
106
|
+
expect(operationKeys).toHaveLength(425);
|
|
107
|
+
expect(generatedKeys).toHaveLength(425);
|
|
108
108
|
expect(new Set(generatedKeys)).toEqual(new Set(operationKeys));
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -376,7 +376,7 @@ describe("dsh harness", () => {
|
|
|
376
376
|
await rename(join(config.cwd, "dsh"), join(config.cwd, "npx"));
|
|
377
377
|
config.env = { ...config.env, DSH_BINARY: "", PATH: config.cwd };
|
|
378
378
|
await expect(new DshAdapter().createSession(config)).rejects.toThrow(
|
|
379
|
-
"dsh CLI not found. Install @deepseek-ai/dsh@0.2.1-alpha.
|
|
379
|
+
"dsh CLI not found. Install @deepseek-ai/dsh@0.2.1-alpha.4",
|
|
380
380
|
);
|
|
381
381
|
expect(await Bun.file(join(config.cwd, "invocation.json")).exists()).toBe(false);
|
|
382
382
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { afterEach, expect, test } from "bun:test";
|
|
2
|
+
import { ALL_CAPABILITIES, getEnabledCapabilities, hasCapability } from "../server";
|
|
3
|
+
|
|
4
|
+
const originalCapabilities = process.env.CAPABILITIES;
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
if (originalCapabilities === undefined) delete process.env.CAPABILITIES;
|
|
8
|
+
else process.env.CAPABILITIES = originalCapabilities;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// `services` was a real capability until the PM2 service registry was removed.
|
|
12
|
+
// A deployment that still lists it must keep registering agents: the register
|
|
13
|
+
// response validates enabledCapabilities against ALL_CAPABILITIES.
|
|
14
|
+
test("enabledCapabilities drops retired and free-form names", () => {
|
|
15
|
+
process.env.CAPABILITIES = "core,services,artifacts,pages";
|
|
16
|
+
|
|
17
|
+
expect(ALL_CAPABILITIES as readonly string[]).not.toContain("services");
|
|
18
|
+
expect(getEnabledCapabilities()).toEqual(["core", "pages"]);
|
|
19
|
+
expect(hasCapability("pages")).toBe(true);
|
|
20
|
+
});
|
|
@@ -221,28 +221,34 @@ describe("wait_for_api_ready: immediate success", () => {
|
|
|
221
221
|
|
|
222
222
|
describe("wait_for_api_ready: transient failure then success", () => {
|
|
223
223
|
test("retries roughly once per second until the server recovers", async () => {
|
|
224
|
-
|
|
224
|
+
// A per-test path prefix: an ephemeral port can be reused from another test
|
|
225
|
+
// process whose poller still hits /health, and those stray requests used
|
|
226
|
+
// to count as retries (3 requests in 1033 ms on CI).
|
|
227
|
+
const prefix = `/${crypto.randomUUID()}`;
|
|
228
|
+
const requestTimes: number[] = [];
|
|
225
229
|
server = Bun.serve({
|
|
226
230
|
port: 0,
|
|
227
231
|
hostname: "127.0.0.1",
|
|
228
232
|
fetch(req) {
|
|
229
233
|
const url = new URL(req.url);
|
|
230
|
-
if (url.pathname !==
|
|
231
|
-
|
|
232
|
-
if (
|
|
234
|
+
if (url.pathname !== `${prefix}/health`) return new Response("not found", { status: 404 });
|
|
235
|
+
requestTimes.push(performance.now());
|
|
236
|
+
if (requestTimes.length < 3) return new Response("unavailable", { status: 503 });
|
|
233
237
|
return new Response("ok", { status: 200 });
|
|
234
238
|
},
|
|
235
239
|
});
|
|
236
240
|
|
|
237
|
-
const result = await runWaitForApiReady(server.url.
|
|
241
|
+
const result = await runWaitForApiReady(`${server.url.origin}${prefix}/`, {
|
|
238
242
|
WORKER_API_READY_TIMEOUT_SECONDS: "10",
|
|
239
243
|
});
|
|
240
244
|
|
|
241
245
|
expect(result.exitCode).toBe(0);
|
|
242
|
-
expect(
|
|
246
|
+
expect(requestTimes).toHaveLength(3);
|
|
243
247
|
expect(result.stdout).toContain("API ready at");
|
|
244
|
-
//
|
|
245
|
-
|
|
248
|
+
// Each retry waits out `sleep 1` after the previous response, so the
|
|
249
|
+
// server-side gap cannot shrink under load: paced, not a hot loop.
|
|
250
|
+
expect(requestTimes[1]! - requestTimes[0]!).toBeGreaterThanOrEqual(900);
|
|
251
|
+
expect(requestTimes[2]! - requestTimes[1]!).toBeGreaterThanOrEqual(900);
|
|
246
252
|
expect(result.durationMs).toBeLessThan(15000);
|
|
247
253
|
}, 20000);
|
|
248
254
|
});
|
|
@@ -93,7 +93,10 @@ function extractExportFilter(lineMarker: string): string {
|
|
|
93
93
|
const line = script.split("\n").find((l) => l.includes(lineMarker) && l.includes("jq -r '"));
|
|
94
94
|
if (!line) throw new Error(`Could not locate the jq line containing ${lineMarker}`);
|
|
95
95
|
const start = line.indexOf("jq -r '") + "jq -r '".length;
|
|
96
|
-
|
|
96
|
+
// Inline programs read /tmp/swarm_config.json; the swarm_config_env_lines
|
|
97
|
+
// function reads its "$1" argument.
|
|
98
|
+
const ends = ["' /tmp/swarm_config.json", '\' "$1"'].map((tail) => line.indexOf(tail, start));
|
|
99
|
+
const end = ends.find((index) => index !== -1) ?? -1;
|
|
97
100
|
if (end === -1) throw new Error(`Could not locate the end of the jq program for ${lineMarker}`);
|
|
98
101
|
return line.slice(start, end);
|
|
99
102
|
}
|
|
@@ -127,7 +130,7 @@ describe("entrypoint config env export: real jq filter", () => {
|
|
|
127
130
|
test(
|
|
128
131
|
"never exports codex_oauth or codex_oauth_<n>, nor the runner-resolved keys",
|
|
129
132
|
async () => {
|
|
130
|
-
const lines = await runJq(extractExportFilter("
|
|
133
|
+
const lines = await runJq(extractExportFilter("(.value | @sh)"), configs);
|
|
131
134
|
const keys = lines.map((l) => l.slice(0, l.indexOf("=")));
|
|
132
135
|
expect(keys).toEqual(["NORMAL", "codex_oauth_extra"]);
|
|
133
136
|
expect(lines.join("\n")).not.toContain("rt.secret");
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CHILD_PROCESS_TEST_BUDGET_MS, expectChildOk, runChild } from "./test-proc";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Runs the real swarm_config_env block from docker-entrypoint.sh (extracted
|
|
9
|
+
* between its BEGIN/END markers) against a /api/config/resolved fixture, the
|
|
10
|
+
* same way the entrypoint sources it, and reads the resulting env.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const entrypoint = readFileSync("docker-entrypoint.sh", "utf8");
|
|
14
|
+
const block = entrypoint.slice(
|
|
15
|
+
entrypoint.indexOf("# BEGIN swarm_config_env"),
|
|
16
|
+
entrypoint.indexOf("# END swarm_config_env"),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
let dir = "";
|
|
20
|
+
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
dir = mkdtempSync(join(tmpdir(), "entrypoint-export-"));
|
|
23
|
+
});
|
|
24
|
+
afterAll(() => {
|
|
25
|
+
rmSync(dir, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
async function exportedEnv(configs: unknown[], containerEnv: Record<string, string> = {}) {
|
|
29
|
+
const fixture = join(dir, `${crypto.randomUUID()}.json`);
|
|
30
|
+
writeFileSync(fixture, JSON.stringify({ configs }));
|
|
31
|
+
const script = `${block}
|
|
32
|
+
swarm_config_env_lines "$1" > "$1.env"
|
|
33
|
+
set -a; . "$1.env"; set +a
|
|
34
|
+
for withheld_key in $(swarm_config_withheld_keys "$1"); do unset "$withheld_key"; done
|
|
35
|
+
env
|
|
36
|
+
`;
|
|
37
|
+
const result = await runChild(["bash", "-c", script, "bash", fixture], {
|
|
38
|
+
env: { PATH: process.env.PATH ?? "/usr/bin:/bin", ...containerEnv },
|
|
39
|
+
timeoutMs: CHILD_PROCESS_TEST_BUDGET_MS,
|
|
40
|
+
});
|
|
41
|
+
expectChildOk(result, "entrypoint export block");
|
|
42
|
+
return Object.fromEntries(
|
|
43
|
+
result.stdout
|
|
44
|
+
.split("\n")
|
|
45
|
+
.filter((line) => line.includes("="))
|
|
46
|
+
.map((line) => [line.slice(0, line.indexOf("=")), line.slice(line.indexOf("=") + 1)]),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("docker-entrypoint.sh swarm_config_env", () => {
|
|
51
|
+
test("markers are present", () => {
|
|
52
|
+
expect(block).toContain("swarm_config_env_lines()");
|
|
53
|
+
expect(block).toContain("swarm_config_withheld_keys()");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("exports exportToEnv rows and drops withheld ones, including container copies", async () => {
|
|
57
|
+
const env = await exportedEnv(
|
|
58
|
+
[
|
|
59
|
+
{ key: "GITHUB_TOKEN", value: "row-github", isSecret: true, exportToEnv: true },
|
|
60
|
+
{ key: "VERCEL_TOKEN", value: "row-vercel", isSecret: true, exportToEnv: false },
|
|
61
|
+
{ key: "QUOTED", value: "it's $HOME", isSecret: false, exportToEnv: true },
|
|
62
|
+
// A pre-215 API sends no flag: the row keeps exporting.
|
|
63
|
+
{ key: "LEGACY", value: "row-legacy", isSecret: true },
|
|
64
|
+
{ key: "CF-Access-Client-Id", value: "x", isSecret: true, exportToEnv: true },
|
|
65
|
+
{ key: "codex_oauth_1", value: "x", isSecret: true, exportToEnv: true },
|
|
66
|
+
{ key: "HARNESS_PROVIDER", value: "pi", isSecret: false, exportToEnv: true },
|
|
67
|
+
],
|
|
68
|
+
{ VERCEL_TOKEN: "container-vercel" },
|
|
69
|
+
);
|
|
70
|
+
expect(env.GITHUB_TOKEN).toBe("row-github");
|
|
71
|
+
expect(env.QUOTED).toBe("it's $HOME");
|
|
72
|
+
expect(env.LEGACY).toBe("row-legacy");
|
|
73
|
+
expect(env.VERCEL_TOKEN).toBeUndefined();
|
|
74
|
+
expect(env.codex_oauth_1).toBeUndefined();
|
|
75
|
+
expect(env.HARNESS_PROVIDER).toBeUndefined();
|
|
76
|
+
expect(Object.values(env)).not.toContain("row-vercel");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -542,7 +542,12 @@ describe("harness compatibility at every create entry point", () => {
|
|
|
542
542
|
});
|
|
543
543
|
|
|
544
544
|
test("send-task: the parent auto-route target is judged", async () => {
|
|
545
|
-
|
|
545
|
+
// The worker created the parent, so it may continue it (task.parent.attach).
|
|
546
|
+
const parent = await createTaskExtended("codex parent", {
|
|
547
|
+
agentId: codexId,
|
|
548
|
+
creatorAgentId: workerId,
|
|
549
|
+
source: "mcp",
|
|
550
|
+
});
|
|
546
551
|
const refused = await sendTaskHandler(ownerCtx({ agentId: workerId }), {
|
|
547
552
|
task: "child of a codex task",
|
|
548
553
|
parentTaskId: parent.id,
|
|
@@ -662,3 +667,102 @@ describe("harness compatibility at every create entry point", () => {
|
|
|
662
667
|
expect(String(res.body.error)).toContain("does not run on the codex harness");
|
|
663
668
|
});
|
|
664
669
|
});
|
|
670
|
+
|
|
671
|
+
describe("nan and helmcode catalog models", () => {
|
|
672
|
+
let piId = "";
|
|
673
|
+
let opencodeId = "";
|
|
674
|
+
|
|
675
|
+
beforeAll(async () => {
|
|
676
|
+
piId = (
|
|
677
|
+
await createAgent({
|
|
678
|
+
name: "validation-pi",
|
|
679
|
+
isLead: false,
|
|
680
|
+
status: "idle",
|
|
681
|
+
harnessProvider: "pi",
|
|
682
|
+
})
|
|
683
|
+
).id;
|
|
684
|
+
opencodeId = (
|
|
685
|
+
await createAgent({
|
|
686
|
+
name: "validation-opencode",
|
|
687
|
+
isLead: false,
|
|
688
|
+
status: "idle",
|
|
689
|
+
harnessProvider: "opencode",
|
|
690
|
+
})
|
|
691
|
+
).id;
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
const ids = [
|
|
695
|
+
"nan/glm5.3-flash",
|
|
696
|
+
"nan/glm5.3",
|
|
697
|
+
"nan/mimo-v2.6-flash",
|
|
698
|
+
"helmcode/glm5.3",
|
|
699
|
+
"helmcode/qwen3.6",
|
|
700
|
+
"helmcode/deepseek-v4-flash",
|
|
701
|
+
];
|
|
702
|
+
|
|
703
|
+
test("pi and opencode accept the ids without allowCustomModel", async () => {
|
|
704
|
+
for (const harnessProvider of ["pi", "opencode"]) {
|
|
705
|
+
for (const model of ids) {
|
|
706
|
+
expect(await explicitModelError({ model, harnessProvider })).toBeNull();
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
test("claude and codex reject them with the harness mismatch, even with allowCustomModel", async () => {
|
|
712
|
+
for (const harnessProvider of ["claude", "codex"]) {
|
|
713
|
+
for (const allowCustomModel of [false, true]) {
|
|
714
|
+
for (const model of ["nan/glm5.3-flash", "helmcode/glm5.3"]) {
|
|
715
|
+
expect(await explicitModelError({ model, harnessProvider, allowCustomModel })).toContain(
|
|
716
|
+
`does not run on the ${harnessProvider} harness`,
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
test("a misspelt helmcode id is unknown", async () => {
|
|
724
|
+
expect(
|
|
725
|
+
await explicitModelError({ model: "helmcode/glm-5.3", harnessProvider: "pi" }),
|
|
726
|
+
).toContain("Unknown model");
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
test("send-task: pi and opencode agents take the ids, a claude agent gets the mismatch", async () => {
|
|
730
|
+
const sender = ownerCtx({ agentId: leadId });
|
|
731
|
+
const args = {
|
|
732
|
+
task: "nan route",
|
|
733
|
+
offerMode: false,
|
|
734
|
+
allowDuplicate: false,
|
|
735
|
+
routingReason: "human_pinned" as const,
|
|
736
|
+
routingNote: "pinned to check the nan/helmcode catalog ids",
|
|
737
|
+
};
|
|
738
|
+
for (const agentId of [piId, opencodeId]) {
|
|
739
|
+
for (const model of ["nan/mimo-v2.6-flash", "helmcode/glm5.3"]) {
|
|
740
|
+
const accepted = await sendTaskHandler(sender, {
|
|
741
|
+
...args,
|
|
742
|
+
task: `nan route ${model} to ${agentId}`,
|
|
743
|
+
agentId,
|
|
744
|
+
model,
|
|
745
|
+
});
|
|
746
|
+
expect({ ok: accepted.ok, message: accepted.message }).toEqual({
|
|
747
|
+
ok: true,
|
|
748
|
+
message: expect.any(String),
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const refused = await sendTaskHandler(sender, {
|
|
753
|
+
...args,
|
|
754
|
+
agentId: workerId,
|
|
755
|
+
model: "helmcode/glm5.3",
|
|
756
|
+
});
|
|
757
|
+
expect(refused.ok).toBe(false);
|
|
758
|
+
expect(refused.message).toContain("does not run on the claude harness");
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
test("PATCH /api/agents/:id/runtime stores a helmcode model on a pi agent", async () => {
|
|
762
|
+
const res = await api("PATCH", `/api/agents/${piId}/runtime`, {
|
|
763
|
+
harness_provider: "pi",
|
|
764
|
+
model: "helmcode/glm5.3",
|
|
765
|
+
});
|
|
766
|
+
expect(res.status).toBe(200);
|
|
767
|
+
});
|
|
768
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import { closeDb, createAgent, getDbClient, getKv, initDb } from "../be/db";
|
|
4
|
+
import { installExtension, listExtensionRuns } from "../be/extensions/db";
|
|
5
|
+
import { enableExtension, stopExtensionRuntime } from "../extensions/lifecycle";
|
|
6
|
+
import { chatSdkContextKey } from "../tasks/context-key";
|
|
7
|
+
import type { Agent } from "../types";
|
|
8
|
+
import {
|
|
9
|
+
flushChatBuffers,
|
|
10
|
+
postTelegramUpdate,
|
|
11
|
+
startTelegramHarness,
|
|
12
|
+
type TelegramHarness,
|
|
13
|
+
telegramUpdate,
|
|
14
|
+
} from "./chat-sdk-harness";
|
|
15
|
+
import { loadBundleFixture } from "./fixtures/extensions/load";
|
|
16
|
+
|
|
17
|
+
const TEST_DB_PATH = "./test-extensions-example-route-chat-channel.sqlite";
|
|
18
|
+
|
|
19
|
+
let harness: TelegramHarness;
|
|
20
|
+
let lead: Agent;
|
|
21
|
+
let worker: Agent;
|
|
22
|
+
|
|
23
|
+
async function removeDbFiles(): Promise<void> {
|
|
24
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
25
|
+
await unlink(`${TEST_DB_PATH}${suffix}`).catch(() => {});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function chatTask(chatId: number) {
|
|
30
|
+
return getDbClient().get<{ agentId: string | null }>(
|
|
31
|
+
"SELECT agentId FROM agent_tasks WHERE source = 'chat' AND contextKey = ? ORDER BY createdAt DESC LIMIT 1",
|
|
32
|
+
[chatSdkContextKey(`telegram:${chatId}`)],
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A private-chat message, flushed out of the thread buffer. */
|
|
37
|
+
async function sendDm(chatId: number, text: string): Promise<void> {
|
|
38
|
+
await postTelegramUpdate(telegramUpdate({ id: chatId, type: "private" }, text));
|
|
39
|
+
await flushChatBuffers();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function installRouteFixture(channelId: string, agentId: string) {
|
|
43
|
+
const bundle = await loadBundleFixture("route-chat-channel-to-agent");
|
|
44
|
+
const { extension } = await installExtension({
|
|
45
|
+
...bundle,
|
|
46
|
+
config: { adapter: "telegram", channelId, agentId },
|
|
47
|
+
});
|
|
48
|
+
return { extension, enabled: await enableExtension(extension.id) };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe("extension Chat SDK channel routing", () => {
|
|
52
|
+
beforeAll(async () => {
|
|
53
|
+
await removeDbFiles();
|
|
54
|
+
initDb(TEST_DB_PATH);
|
|
55
|
+
lead = await createAgent({
|
|
56
|
+
id: crypto.randomUUID(),
|
|
57
|
+
name: "chat-route-lead",
|
|
58
|
+
isLead: true,
|
|
59
|
+
status: "idle",
|
|
60
|
+
});
|
|
61
|
+
worker = await createAgent({
|
|
62
|
+
id: crypto.randomUUID(),
|
|
63
|
+
name: "chat-route-worker",
|
|
64
|
+
isLead: false,
|
|
65
|
+
status: "idle",
|
|
66
|
+
});
|
|
67
|
+
harness = await startTelegramHarness();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterAll(async () => {
|
|
71
|
+
await harness.stop();
|
|
72
|
+
await stopExtensionRuntime();
|
|
73
|
+
closeDb();
|
|
74
|
+
await removeDbFiles();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
beforeEach(async () => {
|
|
78
|
+
await stopExtensionRuntime();
|
|
79
|
+
await getDbClient().run("DELETE FROM extensions");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("routes the configured channel to its agent and leaves other channels with the lead", async () => {
|
|
83
|
+
const { extension } = await installRouteFixture("telegram:3001", worker.id);
|
|
84
|
+
|
|
85
|
+
await sendDm(3001, "route this to the worker");
|
|
86
|
+
expect(await chatTask(3001)).toEqual({ agentId: worker.id });
|
|
87
|
+
expect(
|
|
88
|
+
(await listExtensionRuns(extension.id)).some(
|
|
89
|
+
(run) => run.event === "pre.chat.route" && run.action === "modify",
|
|
90
|
+
),
|
|
91
|
+
).toBe(true);
|
|
92
|
+
|
|
93
|
+
await sendDm(3002, "use the normal route");
|
|
94
|
+
expect(await chatTask(3002)).toEqual({ agentId: lead.id });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("a block creates no task", async () => {
|
|
98
|
+
const bundle = await loadBundleFixture("minimal");
|
|
99
|
+
const { extension } = await installExtension({
|
|
100
|
+
manifest: { ...bundle.manifest, name: "block-chat-route", description: "blocks chat" },
|
|
101
|
+
files: {
|
|
102
|
+
"hooks.ts": `import { block, type SwarmExtension } from "swarm-extension";
|
|
103
|
+
const extension: SwarmExtension = (api) => {
|
|
104
|
+
api.on("pre.chat.route", () => block("chat is muted"));
|
|
105
|
+
};
|
|
106
|
+
export default extension;
|
|
107
|
+
`,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
await enableExtension(extension.id);
|
|
111
|
+
|
|
112
|
+
await sendDm(3003, "this must not become a task");
|
|
113
|
+
expect(await chatTask(3003)).toBeNull();
|
|
114
|
+
const runs = await listExtensionRuns(extension.id);
|
|
115
|
+
expect(runs.some((run) => run.event === "pre.chat.route" && run.action === "block")).toBe(true);
|
|
116
|
+
// Ids only in the run subject: never the message text.
|
|
117
|
+
expect(runs.every((run) => !run.subject?.includes("must not"))).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("falls back to the built-in router when the extension names an unknown agent", async () => {
|
|
121
|
+
await installRouteFixture("telegram:3004", "missing-agent");
|
|
122
|
+
const warn = spyOn(console, "warn").mockImplementation(() => {});
|
|
123
|
+
try {
|
|
124
|
+
await sendDm(3004, "use the fallback");
|
|
125
|
+
expect(await chatTask(3004)).toEqual({ agentId: lead.id });
|
|
126
|
+
expect(warn).toHaveBeenCalledWith(
|
|
127
|
+
"[chat-sdk] Extension selected an unknown agent missing-agent. Using the router.",
|
|
128
|
+
);
|
|
129
|
+
} finally {
|
|
130
|
+
warn.mockRestore();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("post.chat.message carries the inbound sender", async () => {
|
|
135
|
+
const { extension, enabled } = await installRouteFixture("telegram:3005", worker.id);
|
|
136
|
+
await sendDm(3005, "record this message");
|
|
137
|
+
|
|
138
|
+
const deadline = Date.now() + 5_000;
|
|
139
|
+
while (
|
|
140
|
+
!(await listExtensionRuns(extension.id)).some(
|
|
141
|
+
(run) => run.event === "post.chat.message" && run.action === "continue",
|
|
142
|
+
) &&
|
|
143
|
+
Date.now() < deadline
|
|
144
|
+
) {
|
|
145
|
+
await Bun.sleep(20);
|
|
146
|
+
}
|
|
147
|
+
expect(
|
|
148
|
+
await getKv(
|
|
149
|
+
`task:agent:${enabled.agentId}`,
|
|
150
|
+
"ext:route-chat-channel-to-agent:chat:telegram:3005",
|
|
151
|
+
),
|
|
152
|
+
).toMatchObject({ value: "777001" });
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -33,6 +33,7 @@ const NEW_EVENTS = [
|
|
|
33
33
|
"post.task.budgetRefused",
|
|
34
34
|
"post.email.received",
|
|
35
35
|
"post.kapso.message",
|
|
36
|
+
"post.chat.message",
|
|
36
37
|
"post.vcs.event",
|
|
37
38
|
] as const satisfies readonly (keyof SwarmEventMap)[];
|
|
38
39
|
|
|
@@ -358,6 +359,56 @@ describe("extension post bridge: new events", () => {
|
|
|
358
359
|
});
|
|
359
360
|
});
|
|
360
361
|
|
|
362
|
+
describe("post.chat.message", () => {
|
|
363
|
+
test("chat.message.received dispatches an inbound event", async () => {
|
|
364
|
+
await registerCapture("capture");
|
|
365
|
+
workflowEventBus.emit("chat.message.received", {
|
|
366
|
+
adapter: "telegram",
|
|
367
|
+
channelId: "telegram:555001",
|
|
368
|
+
threadId: "telegram:555001",
|
|
369
|
+
userId: "555001",
|
|
370
|
+
text: "hello swarm",
|
|
371
|
+
messageId: "555001:11",
|
|
372
|
+
});
|
|
373
|
+
await waitForEvents(1);
|
|
374
|
+
expect(received).toEqual([
|
|
375
|
+
{
|
|
376
|
+
extension: "capture",
|
|
377
|
+
event: "post.chat.message",
|
|
378
|
+
payload: {
|
|
379
|
+
adapter: "telegram",
|
|
380
|
+
channelId: "telegram:555001",
|
|
381
|
+
threadId: "telegram:555001",
|
|
382
|
+
userId: "555001",
|
|
383
|
+
text: "hello swarm",
|
|
384
|
+
direction: "inbound",
|
|
385
|
+
messageId: "555001:11",
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
]);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test("chat.message.sent dispatches an outbound event", async () => {
|
|
392
|
+
await registerCapture("capture");
|
|
393
|
+
workflowEventBus.emit("chat.message.sent", {
|
|
394
|
+
adapter: "telegram",
|
|
395
|
+
channelId: "telegram:555001",
|
|
396
|
+
threadId: "telegram:555001",
|
|
397
|
+
text: "done",
|
|
398
|
+
taskId: "task-1",
|
|
399
|
+
});
|
|
400
|
+
await waitForEvents(1);
|
|
401
|
+
expect(received[0]?.payload).toEqual({
|
|
402
|
+
adapter: "telegram",
|
|
403
|
+
channelId: "telegram:555001",
|
|
404
|
+
threadId: "telegram:555001",
|
|
405
|
+
text: "done",
|
|
406
|
+
direction: "outbound",
|
|
407
|
+
taskId: "task-1",
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
361
412
|
describe("post.kapso.message", () => {
|
|
362
413
|
test("a bus emit dispatches the typed payload", async () => {
|
|
363
414
|
await registerCapture("capture");
|