@desplega.ai/agent-swarm 1.173.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-sj2g0m84.js} +17 -16
- package/dist/{actions-sgeyv08k.js → actions-fegk44gr.js} +39 -34
- package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{app-km9qnv2f.js → app-kfvgbvzy.js} +18 -14
- package/dist/{assistant-5r8tcvvd.js → assistant-z7zdy9ja.js} +40 -35
- package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-5c2z0mbe.js} +10 -9
- package/dist/{boot-reembed-16rv9843.js → boot-reembed-j8xa181e.js} +10 -9
- package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-hnkn3rgt.js} +11 -10
- package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-kwjq4d2z.js} +14 -13
- package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-9vmvpvgd.js} +19 -18
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
- package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-9jye6cxr.js} +11881 -11472
- package/dist/{cli-94b48jhk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-1w0vj3gw.js → cli-1e4b6bzh.js} +7 -7
- package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-x119kdba.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-srqq3gc5.js → cli-3fbmmawm.js} +5 -5
- package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
- package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
- package/dist/{cli-42qhyvwx.js → cli-5t4f29ez.js} +3 -3
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-0kxf81jj.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-w1apjecb.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-anzdk0z4.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-na2pxe4f.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-rfz2ve55.js → cli-bzszjf2p.js} +2855 -862
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
- package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
- package/dist/{cli-rfs4vddv.js → cli-d5f9ed5c.js} +5 -5
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
- package/dist/{cli-7a93cv8c.js → cli-ee9gtz70.js} +98 -23
- package/dist/{cli-3nxdmjrc.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-fmhj1ehj.js → cli-ef1hg1wv.js} +470 -51
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
- package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
- package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
- package/dist/{cli-s8z6x4b4.js → cli-j0pfptdp.js} +218 -102
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-5er5gjbm.js → cli-k382tshb.js} +10 -11
- package/dist/{cli-v3zhnxsb.js → cli-k3dp5tpf.js} +2 -2
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-ne7smj1b.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-xc7p7s3g.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-wrh08zjd.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-bv2etw2y.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-qm1448f9.js → cli-ne236afy.js} +8 -8
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-0a7mm3zp.js → cli-q0ke1yww.js} +25 -21
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-phcqp1b9.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-jpc4r224.js → cli-r62a35ea.js} +19 -3
- package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-r4fqfpwf.js → cli-s2sp957d.js} +50 -27
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-6thk4jz3.js → cli-se8w6wny.js} +6 -6
- package/dist/cli-skxvvpap.js +10140 -0
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
- package/dist/{cli-nwrdx840.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-r0byd61h.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
- package/dist/{cli-6r2f7edk.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-saqyage0.js → cli-vatyhshy.js} +179 -27
- package/dist/{cli-5wpw4rab.js → cli-vdach5a9.js} +5 -5
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/{cli-c3rk1v0x.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-9xf7fdtp.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +29 -45
- package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-y81sssk0.js} +15 -14
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-8vx4j6a9.js} +15 -14
- package/dist/{commands-z8fq9qna.js → commands-kcpvpcrr.js} +11 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-kwpvj3rf.js} +42 -37
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-yyhqqrbf.js → db-k8ankj20.js} +12 -11
- package/dist/{db-qfpq4bt7.js → db-ww5d7jq3.js} +28 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-x0x7qfcq.js → dispatcher-e8gq5m68.js} +38 -33
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-3epjm3af.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
- package/dist/{external-channel-h1fjecwe.js → external-channel-h3359cwn.js} +11 -10
- package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
- package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
- package/dist/{grok-adapter-e7mr287e.js → grok-adapter-0d4x7gkx.js} +18 -17
- package/dist/{handlers-znb9n7d4.js → handlers-an1gzv21.js} +41 -36
- package/dist/{heartbeat-bm4qkn8d.js → heartbeat-6dakeb61.js} +43 -38
- package/dist/{hook-254r4mza.js → hook-6v6cv6d5.js} +11 -23
- package/dist/{hook-xaa3q80s.js → hook-sa5xye4y.js} +12 -11
- package/dist/{http-3dgrgp8y.js → http-r7f3eky0.js} +1499 -251
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-fx3jqq1e.js → index-7ep4gzdk.js} +38 -33
- package/dist/index-9gw58n4k.js +193 -0
- package/dist/index-9j87mcm8.js +56305 -0
- package/dist/index-bsmcresk.js +79424 -0
- package/dist/index-mh85qhec.js +475 -0
- package/dist/{index-g2byveez.js → index-rmpw9a8q.js} +38 -33
- package/dist/{index-2ybk7khy.js → index-s2wxgzr0.js} +468 -683
- package/dist/{index-bdsqa799.js → index-v1v6n7hg.js} +43 -38
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-jd7sejm2.js → index-zk96aq1k.js} +10 -9
- package/dist/{keepalive-6ywhpja1.js → keepalive-be9vwy5h.js} +12 -11
- package/dist/{lead-cw45n21s.js → lead-0861cwrf.js} +61 -56
- package/dist/{maintenance-ss1a1ge9.js → maintenance-mzzgc8bn.js} +10 -9
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-cpdnfwdj.js} +11 -10
- package/dist/{onboard-8hzdhc1k.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-nm42wwj8.js} +18 -13
- package/dist/{otel-impl-e6mnvc4v.js → otel-impl-x6c1c9g4.js} +242 -868
- package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-9n2ya240.js} +244 -106
- package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-qb0rv0ap.js} +12 -11
- package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-1gzdwbh1.js} +11 -10
- package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-3mraey52.js} +12 -11
- package/dist/{render-v2-907cy6sa.js → render-v2-agpa45zz.js} +18 -14
- package/dist/{resume-42stcaz0.js → resume-x0ydy9s9.js} +25 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-adbc1c10.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
- package/dist/{work-objects-wpj8ck95.js → work-objects-y5g1y7ev.js} +41 -36
- package/dist/{worker-bzdra9rf.js → worker-860c3e38.js} +61 -56
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +523 -344
- package/package.json +10 -11
- package/src/be/config-refs.ts +60 -0
- package/src/be/db/page-versions.ts +15 -0
- package/src/be/db/runtime.ts +35 -8
- package/src/be/db/skill-name-resolution.ts +36 -0
- package/src/be/db/tasks/read.ts +230 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +52 -7
- package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
- package/src/be/migrations/216_task_resolved_effort.sql +5 -0
- package/src/be/migrations/217_chat_sdk_state.sql +104 -0
- package/src/be/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +12 -1
- package/src/be/model-validation.ts +5 -2
- package/src/be/models-catalog.ts +26 -1
- package/src/be/modelsdev-cache.json +198 -63
- package/src/be/modelsdev-cache.ts +9 -1
- package/src/be/script-credential-broker.ts +39 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -8
- package/src/be/seed/runner.ts +13 -1
- package/src/be/seed/state-db.ts +5 -0
- package/src/be/seed/types.ts +6 -0
- package/src/be/seed-pricing.ts +19 -2
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-skills/bundled-files.generated.json +0 -18
- package/src/be/seed-skills/index.ts +104 -3
- package/src/be/swarm-config-guard.ts +52 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +190 -54
- package/src/e2b/env.ts +5 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +45 -0
- package/src/extensions/dispatcher.ts +7 -0
- package/src/extensions/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/all-routes.ts +0 -1
- package/src/http/config.ts +36 -17
- package/src/http/core.ts +4 -0
- package/src/http/index.ts +14 -2
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +3 -3
- package/src/http/pages.ts +3 -13
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/scripts.ts +1 -0
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +61 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +159 -1
- package/src/http/x.ts +1 -0
- package/src/integrations/chat-sdk/adapters.ts +129 -0
- package/src/integrations/chat-sdk/attachments.ts +232 -0
- package/src/integrations/chat-sdk/background.ts +36 -0
- package/src/integrations/chat-sdk/commands.ts +194 -0
- package/src/integrations/chat-sdk/config.ts +198 -0
- package/src/integrations/chat-sdk/discord-api.ts +63 -0
- package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
- package/src/integrations/chat-sdk/handlers.ts +28 -0
- package/src/integrations/chat-sdk/inbound.ts +426 -0
- package/src/integrations/chat-sdk/limits.ts +48 -0
- package/src/integrations/chat-sdk/logger.ts +81 -0
- package/src/integrations/chat-sdk/outbound.ts +123 -0
- package/src/integrations/chat-sdk/relay.ts +172 -0
- package/src/integrations/chat-sdk/router.ts +169 -0
- package/src/integrations/chat-sdk/runtime.ts +351 -0
- package/src/integrations/chat-sdk/schema.ts +245 -0
- package/src/integrations/chat-sdk/state.ts +243 -0
- package/src/integrations/chat-sdk/status.ts +244 -0
- package/src/integrations/chat-sdk/steering.ts +58 -0
- package/src/integrations/chat-sdk/teams-origin.ts +77 -0
- package/src/integrations/chat-sdk/telegram-api.ts +56 -0
- package/src/integrations/chat-sdk/templates.ts +16 -0
- package/src/integrations/chat-sdk/test-hooks.ts +37 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
- package/src/integrations/chat-sdk/typing.ts +65 -0
- package/src/pages/version.ts +4 -5
- package/src/prompts/base-prompt.ts +111 -45
- package/src/providers/acp-target-catalog.ts +6 -0
- package/src/providers/acp-targets.ts +55 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +1 -1
- package/src/providers/claude-flag-settings.ts +17 -5
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +243 -26
- package/src/providers/opencode-swarm-plugin.ts +31 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +33 -2
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +6 -2
- package/src/rbac/legacy-policy.ts +8 -2
- package/src/rbac/permissions.ts +21 -0
- package/src/scheduler/scheduler.ts +4 -2
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/sdk-allowlist.ts +8 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +27 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
- package/src/server.ts +52 -18
- package/src/slack/event-dedup.ts +1 -1
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +60 -1
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +9 -4
- package/src/tests/claude-flag-settings.test.ts +11 -3
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
- package/src/tests/claude-thinking-tokens.test.ts +57 -0
- package/src/tests/claude-worker-parity.test.ts +2 -7
- package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
- package/src/tests/config-refs.test.ts +66 -0
- package/src/tests/context-key.test.ts +19 -0
- package/src/tests/cors-allowlist.test.ts +25 -0
- package/src/tests/create-page-tool.test.ts +18 -0
- package/src/tests/credential-check.test.ts +139 -0
- package/src/tests/credentials.test.ts +21 -0
- package/src/tests/db-runtime.test.ts +61 -0
- package/src/tests/db-task-read-contract.test.ts +20 -0
- package/src/tests/db-task-write-contract.test.ts +10 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/enabled-capabilities.test.ts +20 -0
- package/src/tests/entrypoint-api-readiness.test.ts +14 -8
- package/src/tests/entrypoint-config-env-export.test.ts +5 -2
- package/src/tests/entrypoint-export-to-env.test.ts +78 -0
- package/src/tests/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
- package/src/tests/extensions-post-bridge.test.ts +51 -0
- package/src/tests/fetch-resolved-env.test.ts +128 -0
- package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
- package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
- package/src/tests/github-handlers.test.ts +35 -0
- package/src/tests/harness-provider-resolution.test.ts +12 -0
- package/src/tests/heartbeat-checklist.test.ts +3 -2
- package/src/tests/hook-runtime-close.test.ts +0 -2
- package/src/tests/http-api-integration.test.ts +0 -25
- package/src/tests/migration-046-budgets.test.ts +17 -16
- package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
- package/src/tests/model-tier-resolution.test.ts +93 -0
- package/src/tests/models-catalog.test.ts +42 -1
- package/src/tests/openai-compatible-providers.test.ts +134 -0
- package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
- package/src/tests/opencode-adapter.test.ts +216 -2
- package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
- package/src/tests/opencode-shell-env.test.ts +145 -0
- package/src/tests/openrouter-base-url.test.ts +101 -151
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/pages-browser-sdk.test.ts +76 -0
- package/src/tests/pages-feedback.test.ts +1 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -0
- package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
- package/src/tests/pi-mono-adapter.test.ts +385 -5
- package/src/tests/pi-shell-env.test.ts +170 -0
- package/src/tests/prompt-template-remaining.test.ts +35 -0
- package/src/tests/rbac-engine.test.ts +11 -3
- package/src/tests/runner-exit-after-tasks.test.ts +0 -4
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/scripts-http.test.ts +201 -1
- package/src/tests/scripts-only-gating.test.ts +2 -3
- package/src/tests/scripts-runtime.test.ts +58 -40
- package/src/tests/secret-scrubber.test.ts +86 -0
- package/src/tests/seed-skills-bundled-files.test.ts +45 -53
- package/src/tests/seed-skills-retire.test.ts +182 -0
- package/src/tests/send-task-requester-gate.test.ts +58 -0
- package/src/tests/session-cost-recompute-unit.test.ts +46 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/swarm-config-export-to-env.test.ts +267 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
- package/src/tests/swarm-diff.test.ts +1 -1
- package/src/tests/task-model-effort-rerun.test.ts +164 -0
- package/src/tests/task-session-prompts.test.ts +132 -0
- package/src/tests/task-tool-manifest.test.ts +14 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-annotations.test.ts +6 -6
- package/src/tests/ui-logs-parser.test.ts +43 -0
- package/src/tests/used-by-route.test.ts +6 -0
- package/src/tests/vercel-ai-gateway.test.ts +149 -0
- package/src/tests/workflow-swarm-script.test.ts +38 -0
- package/src/tests/workflow-wait-filter.test.ts +5 -3
- package/src/tools/chat-access.ts +41 -0
- package/src/tools/chat-open-dm.ts +59 -0
- package/src/tools/chat-post.ts +74 -0
- package/src/tools/chat-read-thread.ts +100 -0
- package/src/tools/chat-reply.ts +75 -0
- package/src/tools/create-page.ts +3 -13
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/send-task.ts +24 -0
- package/src/tools/skills/skill-get.ts +17 -9
- package/src/tools/swarm-config/get-config.ts +2 -1
- package/src/tools/swarm-config/list-config.ts +2 -1
- package/src/tools/swarm-config/set-config.ts +16 -3
- package/src/tools/tool-config.ts +8 -6
- package/src/types.ts +12 -2
- package/src/utils/config-env-export.ts +74 -0
- package/src/utils/credentials.test.ts +92 -0
- package/src/utils/credentials.ts +52 -4
- package/src/utils/harness-provider.ts +15 -6
- package/src/utils/runtime-model-catalog.ts +11 -1
- package/src/utils/secret-scrubber.ts +71 -2
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/workflows/executors/swarm-script.ts +1 -0
- package/templates/skills/agent-browser/SKILL.md +1 -1
- package/templates/skills/agent-browser/content.md +1 -1
- package/templates/skills/apps/SKILL.md +8 -1
- package/templates/skills/apps/content.md +8 -1
- package/templates/skills/chat-sdk/config.json +14 -0
- package/templates/skills/chat-sdk/content.md +84 -0
- package/templates/skills/composio-gmail/content.md +7 -0
- package/templates/skills/composio-google-docs/content.md +1 -1
- package/templates/skills/email-domain-health/config.json +14 -0
- package/templates/skills/email-domain-health/content.md +131 -0
- package/templates/skills/kv-storage/content.md +2 -2
- package/templates/skills/pages/content.md +8 -10
- package/templates/skills/swarm-extensions/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +4 -2
- package/templates/skills/swarm-scripts/config.json +1 -1
- package/templates/skills/swarm-scripts/content.md +4 -2
- package/templates/skills/workflow-iterate/content.md +38 -0
- package/dist/artifact-eczsknc3.js +0 -3843
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- package/dist/cli-tcc4wd5d.js +0 -56471
- package/dist/index-9ch1n761.js +0 -1102
- package/src/artifact-sdk/index.ts +0 -2
- package/src/artifact-sdk/localtunnel.d.ts +0 -20
- package/src/artifact-sdk/port.ts +0 -12
- package/src/artifact-sdk/server.ts +0 -183
- package/src/artifact-sdk/tunnel.ts +0 -19
- package/src/commands/artifact.ts +0 -249
- package/src/http/ecosystem.ts +0 -77
- package/src/tests/artifact-commands.test.ts +0 -92
- package/src/tests/artifact-sdk.test.ts +0 -793
- package/src/tests/register-service-security.test.ts +0 -194
- package/src/tools/list-services.ts +0 -107
- package/src/tools/register-service.ts +0 -177
- package/src/tools/unregister-service.ts +0 -73
- package/src/tools/update-service-status.ts +0 -96
- package/templates/skills/artifacts/config.json +0 -14
- package/templates/skills/artifacts/content.md +0 -344
- package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
- package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
- package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
- package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
4
|
+
import {
|
|
5
|
+
startTelegramBotApiMock,
|
|
6
|
+
type TelegramBotApiMock,
|
|
7
|
+
} from "../../scripts/dev/telegram-bot-api-mock";
|
|
8
|
+
import { closeDb, createAgent, getDbClient, initDb } from "../be/db";
|
|
9
|
+
import { handleWebhooks } from "../http/webhooks";
|
|
10
|
+
import { drainBackground } from "../integrations/chat-sdk/background";
|
|
11
|
+
import { getChatSdkHealth, startChatSdk, stopChatSdk } from "../integrations/chat-sdk/runtime";
|
|
12
|
+
import { flushAllChatBuffers } from "../integrations/chat-sdk/thread-buffer";
|
|
13
|
+
import { getEnabledCapabilities } from "../server";
|
|
14
|
+
import privateText from "./fixtures/chat-sdk/telegram-private-text.json";
|
|
15
|
+
|
|
16
|
+
const TEST_DB_PATH = "./test-chat-sdk-telegram.sqlite";
|
|
17
|
+
const SECRET = "s";
|
|
18
|
+
const ENV_KEYS = ["CHAT_SDK_ENABLED", "CHAT_SDK_ADAPTERS", "CHAT_SDK_API_URL_OVERRIDES"];
|
|
19
|
+
const savedEnv = new Map(ENV_KEYS.map((key) => [key, process.env[key]]));
|
|
20
|
+
|
|
21
|
+
let mock: TelegramBotApiMock;
|
|
22
|
+
let leadId: string;
|
|
23
|
+
|
|
24
|
+
async function removeDbFiles(): Promise<void> {
|
|
25
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
26
|
+
await unlink(`${TEST_DB_PATH}${suffix}`).catch(() => {});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Minimal fake req/res to drive handleWebhooks without a live server. */
|
|
31
|
+
function fakeReqRes(path: string, rawBody: string, headers: Record<string, string>) {
|
|
32
|
+
const rawHeaders = Object.entries(headers).flat();
|
|
33
|
+
const req = {
|
|
34
|
+
method: "POST",
|
|
35
|
+
url: path,
|
|
36
|
+
headers: Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v])),
|
|
37
|
+
rawHeaders,
|
|
38
|
+
async *[Symbol.asyncIterator]() {
|
|
39
|
+
yield Buffer.from(rawBody);
|
|
40
|
+
},
|
|
41
|
+
} as unknown as IncomingMessage;
|
|
42
|
+
|
|
43
|
+
const captured = { status: 0, body: "" };
|
|
44
|
+
const res = {
|
|
45
|
+
writeHead(status: number) {
|
|
46
|
+
captured.status = status;
|
|
47
|
+
return this;
|
|
48
|
+
},
|
|
49
|
+
end(chunk?: string | Buffer) {
|
|
50
|
+
if (chunk) captured.body = chunk.toString();
|
|
51
|
+
return this;
|
|
52
|
+
},
|
|
53
|
+
} as unknown as ServerResponse;
|
|
54
|
+
|
|
55
|
+
return { req, res, captured };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function post(adapter: string, body: unknown, headers: Record<string, string>) {
|
|
59
|
+
const path = `/api/integrations/chat/${adapter}/webhook`;
|
|
60
|
+
const { req, res, captured } = fakeReqRes(path, JSON.stringify(body), {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
...headers,
|
|
63
|
+
});
|
|
64
|
+
const handled = await handleWebhooks(req, res, path.split("/").filter(Boolean));
|
|
65
|
+
expect(handled).toBe(true);
|
|
66
|
+
return captured;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
beforeAll(async () => {
|
|
70
|
+
await removeDbFiles();
|
|
71
|
+
initDb(TEST_DB_PATH);
|
|
72
|
+
const lead = await createAgent({
|
|
73
|
+
id: crypto.randomUUID(),
|
|
74
|
+
name: "ChatLead",
|
|
75
|
+
isLead: true,
|
|
76
|
+
status: "idle",
|
|
77
|
+
});
|
|
78
|
+
leadId = lead.id;
|
|
79
|
+
mock = startTelegramBotApiMock();
|
|
80
|
+
process.env.CHAT_SDK_ENABLED = "true";
|
|
81
|
+
process.env.CHAT_SDK_ADAPTERS = JSON.stringify({
|
|
82
|
+
telegram: { botToken: "t", secretToken: SECRET, mode: "webhook" },
|
|
83
|
+
});
|
|
84
|
+
process.env.CHAT_SDK_API_URL_OVERRIDES = JSON.stringify({ telegram: mock.url });
|
|
85
|
+
await startChatSdk();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterAll(async () => {
|
|
89
|
+
await stopChatSdk();
|
|
90
|
+
mock.stop();
|
|
91
|
+
for (const [key, value] of savedEnv) {
|
|
92
|
+
if (value === undefined) delete process.env[key];
|
|
93
|
+
else process.env[key] = value;
|
|
94
|
+
}
|
|
95
|
+
closeDb();
|
|
96
|
+
await removeDbFiles();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe("Chat SDK Telegram webhook", () => {
|
|
100
|
+
test("the adapter starts healthy against the mock Bot API", () => {
|
|
101
|
+
expect(getChatSdkHealth().telegram?.status).toBe("ok");
|
|
102
|
+
expect(mock.calls.some((call) => call.method === "getMe")).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("a wrong secret token is rejected with 401", async () => {
|
|
106
|
+
const captured = await post("telegram", privateText, {
|
|
107
|
+
"X-Telegram-Bot-Api-Secret-Token": "wrong",
|
|
108
|
+
});
|
|
109
|
+
expect(captured.status).toBe(401);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("a body above 1 MiB is rejected with 413 before the adapter runs", async () => {
|
|
113
|
+
const path = "/api/integrations/chat/telegram/webhook";
|
|
114
|
+
const segments = path.split("/").filter(Boolean);
|
|
115
|
+
const oversized = "x".repeat(1024 * 1024 + 1);
|
|
116
|
+
const secretHeader = { "X-Telegram-Bot-Api-Secret-Token": SECRET };
|
|
117
|
+
const sentBefore = mock.calls.length;
|
|
118
|
+
|
|
119
|
+
// Declared up front: rejected before any chunk is read.
|
|
120
|
+
const declared = fakeReqRes(path, "{}", {
|
|
121
|
+
...secretHeader,
|
|
122
|
+
"Content-Length": String(oversized.length),
|
|
123
|
+
});
|
|
124
|
+
expect(await handleWebhooks(declared.req, declared.res, segments)).toBe(true);
|
|
125
|
+
expect(declared.captured.status).toBe(413);
|
|
126
|
+
|
|
127
|
+
// Streamed without Content-Length: rejected once the cap is crossed.
|
|
128
|
+
const streamed = fakeReqRes(path, oversized, secretHeader);
|
|
129
|
+
expect(await handleWebhooks(streamed.req, streamed.res, segments)).toBe(true);
|
|
130
|
+
expect(streamed.captured.status).toBe(413);
|
|
131
|
+
expect(JSON.parse(streamed.captured.body).error).toContain("Payload too large");
|
|
132
|
+
expect(mock.calls.length).toBe(sentBefore);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("an unconfigured adapter answers 404", async () => {
|
|
136
|
+
const captured = await post("discord", {}, {});
|
|
137
|
+
expect(captured.status).toBe(404);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("a private-chat text update creates one Lead task with a chat-sdk contextKey", async () => {
|
|
141
|
+
const captured = await post("telegram", privateText, {
|
|
142
|
+
"X-Telegram-Bot-Api-Secret-Token": SECRET,
|
|
143
|
+
});
|
|
144
|
+
expect(captured.status).toBe(200);
|
|
145
|
+
expect(await drainBackground(5_000)).toBe(true);
|
|
146
|
+
// Messages wait in the thread buffer; flush it instead of waiting 10 s.
|
|
147
|
+
await flushAllChatBuffers();
|
|
148
|
+
expect(await drainBackground(5_000)).toBe(true);
|
|
149
|
+
|
|
150
|
+
const tasks = await getDbClient().query<{
|
|
151
|
+
id: string;
|
|
152
|
+
source: string;
|
|
153
|
+
contextKey: string;
|
|
154
|
+
agentId: string | null;
|
|
155
|
+
task: string;
|
|
156
|
+
taskType: string;
|
|
157
|
+
}>(
|
|
158
|
+
"SELECT id, source, contextKey, agentId, task, taskType FROM agent_tasks WHERE source = 'chat'",
|
|
159
|
+
);
|
|
160
|
+
expect(tasks).toHaveLength(1);
|
|
161
|
+
const [task] = tasks;
|
|
162
|
+
expect(task!.contextKey.startsWith("task:chat-sdk:telegram:")).toBe(true);
|
|
163
|
+
expect(task!.agentId).toBe(leadId);
|
|
164
|
+
expect(task!.taskType).toBe("chat-inbound");
|
|
165
|
+
expect(task!.task).toContain("summarize the open tasks");
|
|
166
|
+
|
|
167
|
+
const subscriptions = await getDbClient().query<{ thread_id: string }>(
|
|
168
|
+
"SELECT thread_id FROM chat_subscriptions",
|
|
169
|
+
);
|
|
170
|
+
expect(subscriptions.map((row) => row.thread_id)).toContain("telegram:555001");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("a redelivered update is deduplicated", async () => {
|
|
174
|
+
const captured = await post("telegram", privateText, {
|
|
175
|
+
"X-Telegram-Bot-Api-Secret-Token": SECRET,
|
|
176
|
+
});
|
|
177
|
+
expect(captured.status).toBe(200);
|
|
178
|
+
expect(await drainBackground(5_000)).toBe(true);
|
|
179
|
+
await flushAllChatBuffers();
|
|
180
|
+
const row = await getDbClient().get<{ n: number }>(
|
|
181
|
+
"SELECT COUNT(*) AS n FROM agent_tasks WHERE source = 'chat'",
|
|
182
|
+
);
|
|
183
|
+
expect(row?.n).toBe(1);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("chat-sdk capability", () => {
|
|
188
|
+
test("is advertised only when CHAT_SDK_ENABLED is true", () => {
|
|
189
|
+
const previous = process.env.CHAT_SDK_ENABLED;
|
|
190
|
+
try {
|
|
191
|
+
process.env.CHAT_SDK_ENABLED = "true";
|
|
192
|
+
expect(getEnabledCapabilities()).toContain("chat-sdk");
|
|
193
|
+
process.env.CHAT_SDK_ENABLED = "false";
|
|
194
|
+
expect(getEnabledCapabilities()).not.toContain("chat-sdk");
|
|
195
|
+
} finally {
|
|
196
|
+
if (previous === undefined) delete process.env.CHAT_SDK_ENABLED;
|
|
197
|
+
else process.env.CHAT_SDK_ENABLED = previous;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
resolveClaudeBridgeEnabled,
|
|
50
50
|
resolveClaudeTrustDirs,
|
|
51
51
|
} from "../providers/claude-adapter";
|
|
52
|
-
import { ClaudeSettingsConfigError } from "../providers/claude-flag-settings";
|
|
52
|
+
import { ClaudeSettingsConfigError, userClaudeMdExclude } from "../providers/claude-flag-settings";
|
|
53
53
|
import type { ProviderSessionConfig } from "../providers/types";
|
|
54
54
|
import { setFlockForTests } from "../utils/file-lock";
|
|
55
55
|
import { holdFileLock } from "./fixtures/hold-file-lock";
|
|
@@ -775,7 +775,7 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
775
775
|
expect(argv[0]).toBe("claude");
|
|
776
776
|
});
|
|
777
777
|
|
|
778
|
-
test("excludes
|
|
778
|
+
test("excludes both on-disk agent CLAUDE.md copies from Claude's memory load", async () => {
|
|
779
779
|
const adapter = new ClaudeAdapter();
|
|
780
780
|
await createCompletedSession(adapter, makeConfig());
|
|
781
781
|
|
|
@@ -783,7 +783,7 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
783
783
|
const at = argv.indexOf("--settings");
|
|
784
784
|
expect(at).toBeGreaterThan(0);
|
|
785
785
|
expect(JSON.parse(argv[at + 1] ?? "")).toEqual({
|
|
786
|
-
claudeMdExcludes: [WORKSPACE_CLAUDE_MD_PATH],
|
|
786
|
+
claudeMdExcludes: [WORKSPACE_CLAUDE_MD_PATH, userClaudeMdExclude()],
|
|
787
787
|
});
|
|
788
788
|
});
|
|
789
789
|
|
|
@@ -820,7 +820,12 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
820
820
|
expect(JSON.parse(argv[argv.indexOf("--settings") + 1] ?? "")).toEqual({
|
|
821
821
|
model: "from-file",
|
|
822
822
|
env: { X: "kept" },
|
|
823
|
-
claudeMdExcludes: [
|
|
823
|
+
claudeMdExcludes: [
|
|
824
|
+
"/repo/CLAUDE.md",
|
|
825
|
+
WORKSPACE_CLAUDE_MD_PATH,
|
|
826
|
+
"/other/CLAUDE.md",
|
|
827
|
+
userClaudeMdExclude(),
|
|
828
|
+
],
|
|
824
829
|
});
|
|
825
830
|
expect(argv[0]).toBe("claude");
|
|
826
831
|
expect(argv.slice(argv.indexOf("--max-turns"), argv.indexOf("--max-turns") + 2)).toEqual([
|
|
@@ -5,6 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import {
|
|
6
6
|
ClaudeSettingsConfigError,
|
|
7
7
|
mergeClaudeSettingsArgs,
|
|
8
|
+
userClaudeMdExclude,
|
|
8
9
|
WORKSPACE_CLAUDE_MD_EXCLUDE,
|
|
9
10
|
} from "../providers/claude-flag-settings";
|
|
10
11
|
|
|
@@ -22,7 +23,9 @@ describe("mergeClaudeSettingsArgs", () => {
|
|
|
22
23
|
test("no caller settings: args pass through, only the workspace exclusion", () => {
|
|
23
24
|
const merged = mergeClaudeSettingsArgs([["--max-turns", "3"]], directory);
|
|
24
25
|
expect(merged.argLists).toEqual([["--max-turns", "3"]]);
|
|
25
|
-
expect(merged.settings).toEqual({
|
|
26
|
+
expect(merged.settings).toEqual({
|
|
27
|
+
claudeMdExcludes: [WORKSPACE_CLAUDE_MD_EXCLUDE, userClaudeMdExclude()],
|
|
28
|
+
});
|
|
26
29
|
});
|
|
27
30
|
|
|
28
31
|
test("strips both flag forms, keeps caller keys, unions and dedupes claudeMdExcludes", async () => {
|
|
@@ -44,7 +47,12 @@ describe("mergeClaudeSettingsArgs", () => {
|
|
|
44
47
|
expect(merged.settings).toEqual({
|
|
45
48
|
model: "file",
|
|
46
49
|
env: { X: "kept" },
|
|
47
|
-
claudeMdExcludes: [
|
|
50
|
+
claudeMdExcludes: [
|
|
51
|
+
"/a/CLAUDE.md",
|
|
52
|
+
WORKSPACE_CLAUDE_MD_EXCLUDE,
|
|
53
|
+
"/b/CLAUDE.md",
|
|
54
|
+
userClaudeMdExclude(),
|
|
55
|
+
],
|
|
48
56
|
});
|
|
49
57
|
});
|
|
50
58
|
|
|
@@ -100,7 +108,7 @@ describe("mergeClaudeSettingsArgs", () => {
|
|
|
100
108
|
expect(merged.settings).toEqual({
|
|
101
109
|
model: "b",
|
|
102
110
|
env: {},
|
|
103
|
-
claudeMdExcludes: [WORKSPACE_CLAUDE_MD_EXCLUDE],
|
|
111
|
+
claudeMdExcludes: [WORKSPACE_CLAUDE_MD_EXCLUDE, userClaudeMdExclude()],
|
|
104
112
|
});
|
|
105
113
|
});
|
|
106
114
|
});
|
|
@@ -966,7 +966,7 @@ describe("ClaudeManagedAdapter (Phase 4) — repo provisioning + cost data", ()
|
|
|
966
966
|
expect(getClaudeManagedModelPricing("claude-sonnet-5-5")).toEqual({
|
|
967
967
|
inputPerMillion: 2.0,
|
|
968
968
|
outputPerMillion: 10.0,
|
|
969
|
-
cacheReadPerMillion: 0.
|
|
969
|
+
cacheReadPerMillion: 0.1,
|
|
970
970
|
cacheWritePerMillion: 2.5,
|
|
971
971
|
});
|
|
972
972
|
expect(getClaudeManagedModelPricing("claude-sonnet-5")).toEqual({
|
|
@@ -3,6 +3,7 @@ import { mkdtemp, readFile, realpath, rm } from "node:fs/promises";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { ClaudeAdapter, getTaskFilePath } from "../providers/claude-adapter";
|
|
6
|
+
import { userClaudeMdExclude } from "../providers/claude-flag-settings";
|
|
6
7
|
import type { ProviderEvent, ProviderSessionConfig } from "../providers/types";
|
|
7
8
|
import { CHILD_PROCESS_TEST_BUDGET_MS, runChild } from "./test-proc";
|
|
8
9
|
|
|
@@ -148,11 +149,11 @@ describe("Claude SDK production adapter lifecycle", () => {
|
|
|
148
149
|
argument === "--system-prompt" && fixtureState.argv[index + 1] === "",
|
|
149
150
|
),
|
|
150
151
|
).toBeFalse();
|
|
151
|
-
// The SDK forwards `settings` as `--settings`: Claude skips
|
|
152
|
+
// The SDK forwards `settings` as `--settings`: Claude skips both agent CLAUDE.md copies.
|
|
152
153
|
const settingsAt = fixtureState.argv.indexOf("--settings");
|
|
153
154
|
expect(settingsAt).toBeGreaterThan(-1);
|
|
154
155
|
expect(JSON.parse(fixtureState.argv[settingsAt + 1] ?? "")).toMatchObject({
|
|
155
|
-
claudeMdExcludes: ["/workspace/CLAUDE.md"],
|
|
156
|
+
claudeMdExcludes: ["/workspace/CLAUDE.md", userClaudeMdExclude()],
|
|
156
157
|
});
|
|
157
158
|
},
|
|
158
159
|
{ timeout: CHILD_PROCESS_TEST_BUDGET_MS },
|
|
@@ -191,7 +192,12 @@ describe("Claude SDK production adapter lifecycle", () => {
|
|
|
191
192
|
expect(JSON.parse(argv[argv.indexOf("--settings") + 1] ?? "")).toEqual({
|
|
192
193
|
model: "from-file",
|
|
193
194
|
env: { X: "kept" },
|
|
194
|
-
claudeMdExcludes: [
|
|
195
|
+
claudeMdExcludes: [
|
|
196
|
+
"/repo/CLAUDE.md",
|
|
197
|
+
"/other/CLAUDE.md",
|
|
198
|
+
"/workspace/CLAUDE.md",
|
|
199
|
+
userClaudeMdExclude(),
|
|
200
|
+
],
|
|
195
201
|
});
|
|
196
202
|
expect(argv).not.toContain(settingsFile);
|
|
197
203
|
// The version probe carries the same merged settings value.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { normalizeClaudeMessage } from "../providers/claude-session-events";
|
|
3
|
+
|
|
4
|
+
const state = {
|
|
5
|
+
taskId: "task-fixture",
|
|
6
|
+
agentId: "agent-fixture",
|
|
7
|
+
model: "claude-opus-5-5",
|
|
8
|
+
contextWindowSize: 1_000_000,
|
|
9
|
+
transport: "cli" as const,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Trimmed from a claude CLI stream-json `result` line.
|
|
13
|
+
const resultLine = {
|
|
14
|
+
type: "result",
|
|
15
|
+
subtype: "success",
|
|
16
|
+
is_error: false,
|
|
17
|
+
duration_ms: 48_210,
|
|
18
|
+
num_turns: 6,
|
|
19
|
+
session_id: "session-fixture",
|
|
20
|
+
total_cost_usd: 0.3121,
|
|
21
|
+
usage: {
|
|
22
|
+
input_tokens: 12,
|
|
23
|
+
cache_creation_input_tokens: 20_792,
|
|
24
|
+
cache_read_input_tokens: 54_611,
|
|
25
|
+
output_tokens: 2_993,
|
|
26
|
+
output_tokens_details: { thinking_tokens: 1_304 },
|
|
27
|
+
cache_creation: { ephemeral_5m_input_tokens: 0, ephemeral_1h_input_tokens: 20_792 },
|
|
28
|
+
},
|
|
29
|
+
modelUsage: {
|
|
30
|
+
"claude-opus-5-5": {
|
|
31
|
+
inputTokens: 12,
|
|
32
|
+
outputTokens: 2_993,
|
|
33
|
+
cacheReadInputTokens: 54_611,
|
|
34
|
+
cacheCreationInputTokens: 20_792,
|
|
35
|
+
webSearchRequests: 0,
|
|
36
|
+
costUSD: 0.3121,
|
|
37
|
+
contextWindow: 1_000_000,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
describe("claude result-line thinking tokens", () => {
|
|
43
|
+
test("records output_tokens_details.thinking_tokens without touching output or cost", () => {
|
|
44
|
+
const { cost } = normalizeClaudeMessage(resultLine, state);
|
|
45
|
+
expect(cost).toMatchObject({
|
|
46
|
+
thinkingTokens: 1_304,
|
|
47
|
+
outputTokens: 2_993,
|
|
48
|
+
totalCostUsd: 0.3121,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("reports zero when the result line has no thinking breakdown", () => {
|
|
53
|
+
const { output_tokens_details: _, ...usage } = resultLine.usage;
|
|
54
|
+
const { cost } = normalizeClaudeMessage({ ...resultLine, usage }, state);
|
|
55
|
+
expect(cost?.thinkingTokens).toBe(0);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -27,7 +27,6 @@ let sut: Sut;
|
|
|
27
27
|
let api: ApiClient;
|
|
28
28
|
let fixtureDir: string;
|
|
29
29
|
let fixturePath: string;
|
|
30
|
-
let pm2StubPath: string;
|
|
31
30
|
let openRouterMock: Bun.Server;
|
|
32
31
|
|
|
33
32
|
const fixtureSource = `#!/usr/bin/env bun
|
|
@@ -248,7 +247,7 @@ async function runTransport(transport: "cli" | "sdk", agentId: string): Promise<
|
|
|
248
247
|
const home = await mkdtemp(join(fixtureDir, `home-${transport}-`));
|
|
249
248
|
const workerEnv = {
|
|
250
249
|
...minimalEnv(),
|
|
251
|
-
PATH:
|
|
250
|
+
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
252
251
|
HOME: home,
|
|
253
252
|
AGENT_SWARM_API_KEY: sut.apiKey,
|
|
254
253
|
API_KEY: sut.apiKey,
|
|
@@ -387,7 +386,7 @@ async function runCredentialRotation(): Promise<void> {
|
|
|
387
386
|
const observationFile = join(home, "fixture-observation.json");
|
|
388
387
|
const workerEnv = {
|
|
389
388
|
...minimalEnv(),
|
|
390
|
-
PATH:
|
|
389
|
+
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
391
390
|
HOME: home,
|
|
392
391
|
AGENT_SWARM_API_KEY: sut.apiKey,
|
|
393
392
|
API_KEY: sut.apiKey,
|
|
@@ -537,12 +536,8 @@ describe("Claude worker transport parity", () => {
|
|
|
537
536
|
}
|
|
538
537
|
fixtureDir = await mkdtemp("/tmp/claude-worker-parity-");
|
|
539
538
|
fixturePath = join(fixtureDir, "claude-fixture");
|
|
540
|
-
pm2StubPath = join(fixtureDir, "bin");
|
|
541
|
-
await Bun.$`mkdir -p ${pm2StubPath}`.quiet();
|
|
542
539
|
await Bun.write(fixturePath, fixtureSource);
|
|
543
|
-
await Bun.write(join(pm2StubPath, "pm2"), "#!/bin/sh\nexit 0\n");
|
|
544
540
|
await Bun.$`chmod 755 ${fixturePath}`.quiet();
|
|
545
|
-
await Bun.$`chmod 755 ${join(pm2StubPath, "pm2")}`.quiet();
|
|
546
541
|
openRouterMock = Bun.serve({
|
|
547
542
|
port: 0,
|
|
548
543
|
fetch: () =>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { defaultExportToEnv } from "../utils/config-env-export";
|
|
3
|
+
|
|
4
|
+
describe("defaultExportToEnv for Chat SDK rows", () => {
|
|
5
|
+
test("CHAT_SDK_* rows start server-only; other keys keep the default", () => {
|
|
6
|
+
expect(defaultExportToEnv("CHAT_SDK_TELEGRAM_BOT_TOKEN")).toBe(false);
|
|
7
|
+
expect(defaultExportToEnv("chat_sdk_adapters")).toBe(false);
|
|
8
|
+
expect(defaultExportToEnv("CHAT_SDK_ENABLED")).toBe(false);
|
|
9
|
+
expect(defaultExportToEnv("MY_TOOL_TOKEN")).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { ConfigRefError, isConfigRef, resolveConfigRefs } from "../be/config-refs";
|
|
3
|
+
|
|
4
|
+
const values: Record<string, string> = { A: "alpha", B: "bravo" };
|
|
5
|
+
const lookup = (key: string) => values[key];
|
|
6
|
+
|
|
7
|
+
describe("resolveConfigRefs", () => {
|
|
8
|
+
test("resolves nested refs and refs inside arrays", () => {
|
|
9
|
+
const resolved = resolveConfigRefs<Record<string, unknown>>(
|
|
10
|
+
{
|
|
11
|
+
top: { $config: "A" },
|
|
12
|
+
nested: { deep: { value: { $config: "B" } } },
|
|
13
|
+
list: [{ $config: "A" }, "plain", { inner: { $config: "B" } }],
|
|
14
|
+
},
|
|
15
|
+
lookup,
|
|
16
|
+
);
|
|
17
|
+
expect(resolved).toEqual({
|
|
18
|
+
top: "alpha",
|
|
19
|
+
nested: { deep: { value: "bravo" } },
|
|
20
|
+
list: ["alpha", "plain", { inner: "bravo" }],
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("aggregates every missing key into one error", () => {
|
|
25
|
+
let error: unknown;
|
|
26
|
+
try {
|
|
27
|
+
resolveConfigRefs({ a: { $config: "MISSING_2" }, b: [{ $config: "MISSING_1" }] }, lookup);
|
|
28
|
+
} catch (caught) {
|
|
29
|
+
error = caught;
|
|
30
|
+
}
|
|
31
|
+
expect(error).toBeInstanceOf(ConfigRefError);
|
|
32
|
+
expect((error as ConfigRefError).missingKeys).toEqual(["MISSING_1", "MISSING_2"]);
|
|
33
|
+
expect((error as Error).message).toContain("MISSING_1, MISSING_2");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("leaves non-ref objects and scalars untouched", () => {
|
|
37
|
+
const input = {
|
|
38
|
+
notRef: { $config: "A", extra: true },
|
|
39
|
+
emptyRef: { $config: "" },
|
|
40
|
+
numberRef: { $config: 7 },
|
|
41
|
+
n: 1,
|
|
42
|
+
b: false,
|
|
43
|
+
nil: null,
|
|
44
|
+
};
|
|
45
|
+
expect(resolveConfigRefs(input, lookup)).toEqual(input);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("propagates a lookup that throws", () => {
|
|
49
|
+
expect(() =>
|
|
50
|
+
resolveConfigRefs({ k: { $config: "FORBIDDEN" } }, () => {
|
|
51
|
+
throw new Error("forbidden key");
|
|
52
|
+
}),
|
|
53
|
+
).toThrow("forbidden key");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("isConfigRef", () => {
|
|
58
|
+
test("accepts only a single non-empty $config string key", () => {
|
|
59
|
+
expect(isConfigRef({ $config: "X" })).toBe(true);
|
|
60
|
+
expect(isConfigRef({ $config: "X", other: 1 })).toBe(false);
|
|
61
|
+
expect(isConfigRef({ $config: "" })).toBe(false);
|
|
62
|
+
expect(isConfigRef([{ $config: "X" }])).toBe(false);
|
|
63
|
+
expect(isConfigRef("X")).toBe(false);
|
|
64
|
+
expect(isConfigRef(null)).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
azureDevOpsContextKey,
|
|
6
6
|
azureDevOpsWorkItemContextKey,
|
|
7
7
|
buildJiraContextKey,
|
|
8
|
+
chatSdkContextKey,
|
|
8
9
|
githubContextKey,
|
|
9
10
|
gitlabContextKey,
|
|
10
11
|
linearContextKey,
|
|
@@ -166,6 +167,24 @@ describe("parseContextKey", () => {
|
|
|
166
167
|
});
|
|
167
168
|
});
|
|
168
169
|
|
|
170
|
+
test("round-trips chat-sdk keys whose thread id contains colons", () => {
|
|
171
|
+
const threadId = "telegram:-1001234567890:42";
|
|
172
|
+
const key = chatSdkContextKey(threadId);
|
|
173
|
+
expect(key).toBe("task:chat-sdk:telegram:-1001234567890%3A42");
|
|
174
|
+
expect(key.split(":")).toHaveLength(4);
|
|
175
|
+
expect(parseContextKey(key)).toEqual({
|
|
176
|
+
family: "chat-sdk",
|
|
177
|
+
parts: { adapter: "telegram", threadId },
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("chat-sdk keys reject thread ids without an adapter prefix", () => {
|
|
182
|
+
expect(() => chatSdkContextKey("no-adapter")).toThrow(/<adapter>:<id>/);
|
|
183
|
+
expect(() => chatSdkContextKey(":123")).toThrow(/<adapter>:<id>/);
|
|
184
|
+
expect(() => chatSdkContextKey("telegram:")).toThrow(/<adapter>:<id>/);
|
|
185
|
+
expect(() => parseContextKey("task:chat-sdk:telegram")).toThrow(/malformed chat-sdk/);
|
|
186
|
+
});
|
|
187
|
+
|
|
169
188
|
test("round-trips agentmail keys", () => {
|
|
170
189
|
const key = agentmailContextKey({ threadId: "thr_abc" });
|
|
171
190
|
expect(parseContextKey(key)).toEqual({
|
|
@@ -58,6 +58,31 @@ describe("isOriginAllowedForCredentials", () => {
|
|
|
58
58
|
expect(isOriginAllowedForCredentials("https://evil.example")).toBe(false);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
test("development trusts loopback origins on any port; other modes do not", () => {
|
|
62
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
63
|
+
try {
|
|
64
|
+
process.env.NODE_ENV = "development";
|
|
65
|
+
delete process.env[ENV_KEY];
|
|
66
|
+
expect(isOriginAllowedForCredentials("http://localhost:5974")).toBe(true);
|
|
67
|
+
expect(isOriginAllowedForCredentials("http://127.0.0.1:4173")).toBe(true);
|
|
68
|
+
expect(isOriginAllowedForCredentials("http://[::1]:3000")).toBe(true);
|
|
69
|
+
expect(isOriginAllowedForCredentials("https://localhost:8443")).toBe(true);
|
|
70
|
+
expect(isOriginAllowedForCredentials("http://localhost.evil.example")).toBe(false);
|
|
71
|
+
expect(isOriginAllowedForCredentials("http://evil.example:5974")).toBe(false);
|
|
72
|
+
// A custom allowlist does not switch the loopback rule off in development.
|
|
73
|
+
process.env[ENV_KEY] = "https://app.example";
|
|
74
|
+
expect(isOriginAllowedForCredentials("http://localhost:5974")).toBe(true);
|
|
75
|
+
|
|
76
|
+
process.env.NODE_ENV = "production";
|
|
77
|
+
expect(isOriginAllowedForCredentials("http://localhost:5974")).toBe(false);
|
|
78
|
+
delete process.env.NODE_ENV;
|
|
79
|
+
expect(isOriginAllowedForCredentials("http://localhost:5974")).toBe(false);
|
|
80
|
+
} finally {
|
|
81
|
+
if (originalNodeEnv === undefined) delete process.env.NODE_ENV;
|
|
82
|
+
else process.env.NODE_ENV = originalNodeEnv;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
61
86
|
test("denies arbitrary origins when CORS_ALLOWED_ORIGINS is blank", () => {
|
|
62
87
|
process.env[ENV_KEY] = " ";
|
|
63
88
|
expect(isOriginAllowedForCredentials("https://evil.example")).toBe(false);
|
|
@@ -159,6 +159,24 @@ describe("create_page MCP tool", () => {
|
|
|
159
159
|
// Parent now holds the new body.
|
|
160
160
|
const row = await getPageBySlug(agentId, "upsert");
|
|
161
161
|
expect(row?.body).toBe("v1");
|
|
162
|
+
|
|
163
|
+
// The counter and the next snapshot number keep climbing from MAX(version).
|
|
164
|
+
const third = (await tool.handler(
|
|
165
|
+
{
|
|
166
|
+
title: "Upsert Page",
|
|
167
|
+
slug: "upsert",
|
|
168
|
+
body: "v2",
|
|
169
|
+
contentType: "text/html",
|
|
170
|
+
authMode: "public",
|
|
171
|
+
},
|
|
172
|
+
fakeMeta,
|
|
173
|
+
)) as { structuredContent: { version: number } };
|
|
174
|
+
expect(third.structuredContent.version).toBe(3);
|
|
175
|
+
const after = await getPageVersions(first.structuredContent.id);
|
|
176
|
+
expect(after.map((v) => [v.version, v.snapshot.body])).toEqual([
|
|
177
|
+
[2, "v1"],
|
|
178
|
+
[1, "v0"],
|
|
179
|
+
]);
|
|
162
180
|
});
|
|
163
181
|
|
|
164
182
|
test("missing X-Agent-ID returns an error result", async () => {
|