@desplega.ai/agent-swarm 1.173.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-sj2g0m84.js} +17 -16
- package/dist/{actions-sgeyv08k.js → actions-fegk44gr.js} +39 -34
- package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{app-km9qnv2f.js → app-kfvgbvzy.js} +18 -14
- package/dist/{assistant-5r8tcvvd.js → assistant-z7zdy9ja.js} +40 -35
- package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-5c2z0mbe.js} +10 -9
- package/dist/{boot-reembed-16rv9843.js → boot-reembed-j8xa181e.js} +10 -9
- package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-hnkn3rgt.js} +11 -10
- package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-kwjq4d2z.js} +14 -13
- package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-9vmvpvgd.js} +19 -18
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
- package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-9jye6cxr.js} +11881 -11472
- package/dist/{cli-94b48jhk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-1w0vj3gw.js → cli-1e4b6bzh.js} +7 -7
- package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-x119kdba.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-srqq3gc5.js → cli-3fbmmawm.js} +5 -5
- package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
- package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
- package/dist/{cli-42qhyvwx.js → cli-5t4f29ez.js} +3 -3
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-0kxf81jj.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-w1apjecb.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-anzdk0z4.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-na2pxe4f.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-rfz2ve55.js → cli-bzszjf2p.js} +2855 -862
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
- package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
- package/dist/{cli-rfs4vddv.js → cli-d5f9ed5c.js} +5 -5
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
- package/dist/{cli-7a93cv8c.js → cli-ee9gtz70.js} +98 -23
- package/dist/{cli-3nxdmjrc.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-fmhj1ehj.js → cli-ef1hg1wv.js} +470 -51
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
- package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
- package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
- package/dist/{cli-s8z6x4b4.js → cli-j0pfptdp.js} +218 -102
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-5er5gjbm.js → cli-k382tshb.js} +10 -11
- package/dist/{cli-v3zhnxsb.js → cli-k3dp5tpf.js} +2 -2
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-ne7smj1b.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-xc7p7s3g.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-wrh08zjd.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-bv2etw2y.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-qm1448f9.js → cli-ne236afy.js} +8 -8
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-0a7mm3zp.js → cli-q0ke1yww.js} +25 -21
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-phcqp1b9.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-jpc4r224.js → cli-r62a35ea.js} +19 -3
- package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-r4fqfpwf.js → cli-s2sp957d.js} +50 -27
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-6thk4jz3.js → cli-se8w6wny.js} +6 -6
- package/dist/cli-skxvvpap.js +10140 -0
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
- package/dist/{cli-nwrdx840.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-r0byd61h.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
- package/dist/{cli-6r2f7edk.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-saqyage0.js → cli-vatyhshy.js} +179 -27
- package/dist/{cli-5wpw4rab.js → cli-vdach5a9.js} +5 -5
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/{cli-c3rk1v0x.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-9xf7fdtp.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +29 -45
- package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-y81sssk0.js} +15 -14
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-8vx4j6a9.js} +15 -14
- package/dist/{commands-z8fq9qna.js → commands-kcpvpcrr.js} +11 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-kwpvj3rf.js} +42 -37
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-yyhqqrbf.js → db-k8ankj20.js} +12 -11
- package/dist/{db-qfpq4bt7.js → db-ww5d7jq3.js} +28 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-x0x7qfcq.js → dispatcher-e8gq5m68.js} +38 -33
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-3epjm3af.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
- package/dist/{external-channel-h1fjecwe.js → external-channel-h3359cwn.js} +11 -10
- package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
- package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
- package/dist/{grok-adapter-e7mr287e.js → grok-adapter-0d4x7gkx.js} +18 -17
- package/dist/{handlers-znb9n7d4.js → handlers-an1gzv21.js} +41 -36
- package/dist/{heartbeat-bm4qkn8d.js → heartbeat-6dakeb61.js} +43 -38
- package/dist/{hook-254r4mza.js → hook-6v6cv6d5.js} +11 -23
- package/dist/{hook-xaa3q80s.js → hook-sa5xye4y.js} +12 -11
- package/dist/{http-3dgrgp8y.js → http-r7f3eky0.js} +1499 -251
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-fx3jqq1e.js → index-7ep4gzdk.js} +38 -33
- package/dist/index-9gw58n4k.js +193 -0
- package/dist/index-9j87mcm8.js +56305 -0
- package/dist/index-bsmcresk.js +79424 -0
- package/dist/index-mh85qhec.js +475 -0
- package/dist/{index-g2byveez.js → index-rmpw9a8q.js} +38 -33
- package/dist/{index-2ybk7khy.js → index-s2wxgzr0.js} +468 -683
- package/dist/{index-bdsqa799.js → index-v1v6n7hg.js} +43 -38
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-jd7sejm2.js → index-zk96aq1k.js} +10 -9
- package/dist/{keepalive-6ywhpja1.js → keepalive-be9vwy5h.js} +12 -11
- package/dist/{lead-cw45n21s.js → lead-0861cwrf.js} +61 -56
- package/dist/{maintenance-ss1a1ge9.js → maintenance-mzzgc8bn.js} +10 -9
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-cpdnfwdj.js} +11 -10
- package/dist/{onboard-8hzdhc1k.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-nm42wwj8.js} +18 -13
- package/dist/{otel-impl-e6mnvc4v.js → otel-impl-x6c1c9g4.js} +242 -868
- package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-9n2ya240.js} +244 -106
- package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-qb0rv0ap.js} +12 -11
- package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-1gzdwbh1.js} +11 -10
- package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-3mraey52.js} +12 -11
- package/dist/{render-v2-907cy6sa.js → render-v2-agpa45zz.js} +18 -14
- package/dist/{resume-42stcaz0.js → resume-x0ydy9s9.js} +25 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-adbc1c10.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
- package/dist/{work-objects-wpj8ck95.js → work-objects-y5g1y7ev.js} +41 -36
- package/dist/{worker-bzdra9rf.js → worker-860c3e38.js} +61 -56
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +523 -344
- package/package.json +10 -11
- package/src/be/config-refs.ts +60 -0
- package/src/be/db/page-versions.ts +15 -0
- package/src/be/db/runtime.ts +35 -8
- package/src/be/db/skill-name-resolution.ts +36 -0
- package/src/be/db/tasks/read.ts +230 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +52 -7
- package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
- package/src/be/migrations/216_task_resolved_effort.sql +5 -0
- package/src/be/migrations/217_chat_sdk_state.sql +104 -0
- package/src/be/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +12 -1
- package/src/be/model-validation.ts +5 -2
- package/src/be/models-catalog.ts +26 -1
- package/src/be/modelsdev-cache.json +198 -63
- package/src/be/modelsdev-cache.ts +9 -1
- package/src/be/script-credential-broker.ts +39 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -8
- package/src/be/seed/runner.ts +13 -1
- package/src/be/seed/state-db.ts +5 -0
- package/src/be/seed/types.ts +6 -0
- package/src/be/seed-pricing.ts +19 -2
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-skills/bundled-files.generated.json +0 -18
- package/src/be/seed-skills/index.ts +104 -3
- package/src/be/swarm-config-guard.ts +52 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +190 -54
- package/src/e2b/env.ts +5 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +45 -0
- package/src/extensions/dispatcher.ts +7 -0
- package/src/extensions/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/all-routes.ts +0 -1
- package/src/http/config.ts +36 -17
- package/src/http/core.ts +4 -0
- package/src/http/index.ts +14 -2
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +3 -3
- package/src/http/pages.ts +3 -13
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/scripts.ts +1 -0
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +61 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +159 -1
- package/src/http/x.ts +1 -0
- package/src/integrations/chat-sdk/adapters.ts +129 -0
- package/src/integrations/chat-sdk/attachments.ts +232 -0
- package/src/integrations/chat-sdk/background.ts +36 -0
- package/src/integrations/chat-sdk/commands.ts +194 -0
- package/src/integrations/chat-sdk/config.ts +198 -0
- package/src/integrations/chat-sdk/discord-api.ts +63 -0
- package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
- package/src/integrations/chat-sdk/handlers.ts +28 -0
- package/src/integrations/chat-sdk/inbound.ts +426 -0
- package/src/integrations/chat-sdk/limits.ts +48 -0
- package/src/integrations/chat-sdk/logger.ts +81 -0
- package/src/integrations/chat-sdk/outbound.ts +123 -0
- package/src/integrations/chat-sdk/relay.ts +172 -0
- package/src/integrations/chat-sdk/router.ts +169 -0
- package/src/integrations/chat-sdk/runtime.ts +351 -0
- package/src/integrations/chat-sdk/schema.ts +245 -0
- package/src/integrations/chat-sdk/state.ts +243 -0
- package/src/integrations/chat-sdk/status.ts +244 -0
- package/src/integrations/chat-sdk/steering.ts +58 -0
- package/src/integrations/chat-sdk/teams-origin.ts +77 -0
- package/src/integrations/chat-sdk/telegram-api.ts +56 -0
- package/src/integrations/chat-sdk/templates.ts +16 -0
- package/src/integrations/chat-sdk/test-hooks.ts +37 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
- package/src/integrations/chat-sdk/typing.ts +65 -0
- package/src/pages/version.ts +4 -5
- package/src/prompts/base-prompt.ts +111 -45
- package/src/providers/acp-target-catalog.ts +6 -0
- package/src/providers/acp-targets.ts +55 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +1 -1
- package/src/providers/claude-flag-settings.ts +17 -5
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +243 -26
- package/src/providers/opencode-swarm-plugin.ts +31 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +33 -2
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +6 -2
- package/src/rbac/legacy-policy.ts +8 -2
- package/src/rbac/permissions.ts +21 -0
- package/src/scheduler/scheduler.ts +4 -2
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/sdk-allowlist.ts +8 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +27 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
- package/src/server.ts +52 -18
- package/src/slack/event-dedup.ts +1 -1
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +60 -1
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +9 -4
- package/src/tests/claude-flag-settings.test.ts +11 -3
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
- package/src/tests/claude-thinking-tokens.test.ts +57 -0
- package/src/tests/claude-worker-parity.test.ts +2 -7
- package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
- package/src/tests/config-refs.test.ts +66 -0
- package/src/tests/context-key.test.ts +19 -0
- package/src/tests/cors-allowlist.test.ts +25 -0
- package/src/tests/create-page-tool.test.ts +18 -0
- package/src/tests/credential-check.test.ts +139 -0
- package/src/tests/credentials.test.ts +21 -0
- package/src/tests/db-runtime.test.ts +61 -0
- package/src/tests/db-task-read-contract.test.ts +20 -0
- package/src/tests/db-task-write-contract.test.ts +10 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/enabled-capabilities.test.ts +20 -0
- package/src/tests/entrypoint-api-readiness.test.ts +14 -8
- package/src/tests/entrypoint-config-env-export.test.ts +5 -2
- package/src/tests/entrypoint-export-to-env.test.ts +78 -0
- package/src/tests/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
- package/src/tests/extensions-post-bridge.test.ts +51 -0
- package/src/tests/fetch-resolved-env.test.ts +128 -0
- package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
- package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
- package/src/tests/github-handlers.test.ts +35 -0
- package/src/tests/harness-provider-resolution.test.ts +12 -0
- package/src/tests/heartbeat-checklist.test.ts +3 -2
- package/src/tests/hook-runtime-close.test.ts +0 -2
- package/src/tests/http-api-integration.test.ts +0 -25
- package/src/tests/migration-046-budgets.test.ts +17 -16
- package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
- package/src/tests/model-tier-resolution.test.ts +93 -0
- package/src/tests/models-catalog.test.ts +42 -1
- package/src/tests/openai-compatible-providers.test.ts +134 -0
- package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
- package/src/tests/opencode-adapter.test.ts +216 -2
- package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
- package/src/tests/opencode-shell-env.test.ts +145 -0
- package/src/tests/openrouter-base-url.test.ts +101 -151
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/pages-browser-sdk.test.ts +76 -0
- package/src/tests/pages-feedback.test.ts +1 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -0
- package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
- package/src/tests/pi-mono-adapter.test.ts +385 -5
- package/src/tests/pi-shell-env.test.ts +170 -0
- package/src/tests/prompt-template-remaining.test.ts +35 -0
- package/src/tests/rbac-engine.test.ts +11 -3
- package/src/tests/runner-exit-after-tasks.test.ts +0 -4
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/scripts-http.test.ts +201 -1
- package/src/tests/scripts-only-gating.test.ts +2 -3
- package/src/tests/scripts-runtime.test.ts +58 -40
- package/src/tests/secret-scrubber.test.ts +86 -0
- package/src/tests/seed-skills-bundled-files.test.ts +45 -53
- package/src/tests/seed-skills-retire.test.ts +182 -0
- package/src/tests/send-task-requester-gate.test.ts +58 -0
- package/src/tests/session-cost-recompute-unit.test.ts +46 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/swarm-config-export-to-env.test.ts +267 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
- package/src/tests/swarm-diff.test.ts +1 -1
- package/src/tests/task-model-effort-rerun.test.ts +164 -0
- package/src/tests/task-session-prompts.test.ts +132 -0
- package/src/tests/task-tool-manifest.test.ts +14 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-annotations.test.ts +6 -6
- package/src/tests/ui-logs-parser.test.ts +43 -0
- package/src/tests/used-by-route.test.ts +6 -0
- package/src/tests/vercel-ai-gateway.test.ts +149 -0
- package/src/tests/workflow-swarm-script.test.ts +38 -0
- package/src/tests/workflow-wait-filter.test.ts +5 -3
- package/src/tools/chat-access.ts +41 -0
- package/src/tools/chat-open-dm.ts +59 -0
- package/src/tools/chat-post.ts +74 -0
- package/src/tools/chat-read-thread.ts +100 -0
- package/src/tools/chat-reply.ts +75 -0
- package/src/tools/create-page.ts +3 -13
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/send-task.ts +24 -0
- package/src/tools/skills/skill-get.ts +17 -9
- package/src/tools/swarm-config/get-config.ts +2 -1
- package/src/tools/swarm-config/list-config.ts +2 -1
- package/src/tools/swarm-config/set-config.ts +16 -3
- package/src/tools/tool-config.ts +8 -6
- package/src/types.ts +12 -2
- package/src/utils/config-env-export.ts +74 -0
- package/src/utils/credentials.test.ts +92 -0
- package/src/utils/credentials.ts +52 -4
- package/src/utils/harness-provider.ts +15 -6
- package/src/utils/runtime-model-catalog.ts +11 -1
- package/src/utils/secret-scrubber.ts +71 -2
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/workflows/executors/swarm-script.ts +1 -0
- package/templates/skills/agent-browser/SKILL.md +1 -1
- package/templates/skills/agent-browser/content.md +1 -1
- package/templates/skills/apps/SKILL.md +8 -1
- package/templates/skills/apps/content.md +8 -1
- package/templates/skills/chat-sdk/config.json +14 -0
- package/templates/skills/chat-sdk/content.md +84 -0
- package/templates/skills/composio-gmail/content.md +7 -0
- package/templates/skills/composio-google-docs/content.md +1 -1
- package/templates/skills/email-domain-health/config.json +14 -0
- package/templates/skills/email-domain-health/content.md +131 -0
- package/templates/skills/kv-storage/content.md +2 -2
- package/templates/skills/pages/content.md +8 -10
- package/templates/skills/swarm-extensions/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +4 -2
- package/templates/skills/swarm-scripts/config.json +1 -1
- package/templates/skills/swarm-scripts/content.md +4 -2
- package/templates/skills/workflow-iterate/content.md +38 -0
- package/dist/artifact-eczsknc3.js +0 -3843
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- package/dist/cli-tcc4wd5d.js +0 -56471
- package/dist/index-9ch1n761.js +0 -1102
- package/src/artifact-sdk/index.ts +0 -2
- package/src/artifact-sdk/localtunnel.d.ts +0 -20
- package/src/artifact-sdk/port.ts +0 -12
- package/src/artifact-sdk/server.ts +0 -183
- package/src/artifact-sdk/tunnel.ts +0 -19
- package/src/commands/artifact.ts +0 -249
- package/src/http/ecosystem.ts +0 -77
- package/src/tests/artifact-commands.test.ts +0 -92
- package/src/tests/artifact-sdk.test.ts +0 -793
- package/src/tests/register-service-security.test.ts +0 -194
- package/src/tools/list-services.ts +0 -107
- package/src/tools/register-service.ts +0 -177
- package/src/tools/unregister-service.ts +0 -73
- package/src/tools/update-service-status.ts +0 -96
- package/templates/skills/artifacts/config.json +0 -14
- package/templates/skills/artifacts/content.md +0 -344
- package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
- package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
- package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
- package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-swarm.dev",
|
|
@@ -168,11 +168,6 @@
|
|
|
168
168
|
"docs:mcp": "bun scripts/generate-mcp-docs.ts",
|
|
169
169
|
"docs:openapi": "bun scripts/generate-openapi.ts",
|
|
170
170
|
"docs:business-use": "bun scripts/generate-business-use-docs.ts",
|
|
171
|
-
"pm2-start": "pm2 start ecosystem.config.cjs",
|
|
172
|
-
"pm2-stop": "pm2 stop ecosystem.config.cjs",
|
|
173
|
-
"pm2-restart": "pm2 restart ecosystem.config.cjs",
|
|
174
|
-
"pm2-logs": "pm2 logs swarm-api swarm-ui swarm-lead swarm-worker",
|
|
175
|
-
"pm2-status": "pm2 status swarm-api swarm-ui swarm-lead swarm-worker",
|
|
176
171
|
"seed": "bun scripts/seed.ts",
|
|
177
172
|
"seed:clean": "bun scripts/seed.ts --clean",
|
|
178
173
|
"seed:people": "bun scripts/seed-people.ts",
|
|
@@ -180,7 +175,7 @@
|
|
|
180
175
|
},
|
|
181
176
|
"devDependencies": {
|
|
182
177
|
"@biomejs/biome": "^2.3.10",
|
|
183
|
-
"@desplega.ai/slack-mock": "^0.4.
|
|
178
|
+
"@desplega.ai/slack-mock": "^0.4.1",
|
|
184
179
|
"@desplega/model-catalog": "workspace:*",
|
|
185
180
|
"@desplega/model-routing": "workspace:*",
|
|
186
181
|
"@faker-js/faker": "^10.4.0",
|
|
@@ -205,13 +200,16 @@
|
|
|
205
200
|
"dependencies": {
|
|
206
201
|
"@agentclientprotocol/sdk": "1.8.0",
|
|
207
202
|
"@ai-sdk/openai": "^3.0.41",
|
|
208
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
209
|
-
"@anthropic-ai/sdk": "^0.
|
|
203
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.300",
|
|
204
|
+
"@anthropic-ai/sdk": "^0.134.0",
|
|
210
205
|
"@asteasolutions/zod-to-openapi": "^8.0.0",
|
|
211
206
|
"@aws-sdk/client-bedrock": "3.1048.0",
|
|
207
|
+
"@chat-adapter/discord": "4.41.1",
|
|
208
|
+
"@chat-adapter/slack": "4.41.1",
|
|
209
|
+
"@chat-adapter/teams": "4.41.1",
|
|
210
|
+
"@chat-adapter/telegram": "4.41.1",
|
|
212
211
|
"@cursor/sdk": "1.0.37",
|
|
213
212
|
"@desplega.ai/business-use": "^0.4.2",
|
|
214
|
-
"@desplega.ai/localtunnel": "^2.2.0",
|
|
215
213
|
"@earendil-works/pi-agent-core": "^1.2.0",
|
|
216
214
|
"@earendil-works/pi-ai": "^1.2.0",
|
|
217
215
|
"@earendil-works/pi-coding-agent": "^1.2.0",
|
|
@@ -230,15 +228,16 @@
|
|
|
230
228
|
"@opentelemetry/sdk-node": "^0.218.0",
|
|
231
229
|
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
232
230
|
"@slack/bolt": "^4.6.0",
|
|
231
|
+
"@slack/web-api": "7.13.0",
|
|
233
232
|
"@types/react": "^19.2.7",
|
|
234
233
|
"@x402/core": "^2.5.0",
|
|
235
234
|
"@x402/evm": "^2.5.0",
|
|
236
235
|
"@x402/fetch": "^2.5.0",
|
|
237
236
|
"ai": "^6.0.116",
|
|
237
|
+
"chat": "4.41.1",
|
|
238
238
|
"cron-parser": "^5.4.0",
|
|
239
239
|
"date-fns": "^4.1.0",
|
|
240
240
|
"e2b": "2.26.0",
|
|
241
|
-
"hono": "^4.12.3",
|
|
242
241
|
"ink": "^6.5.1",
|
|
243
242
|
"oauth4webapi": "^3.8.5",
|
|
244
243
|
"openai": "^6.22.0",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config references: `{ "$config": "KEY" }` leaves inside a JSON config value
|
|
3
|
+
* that point at another config key (usually a secret). Pure, no DB access: the
|
|
4
|
+
* caller supplies the lookup and decides which keys are allowed.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface ConfigRef {
|
|
8
|
+
$config: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** True when `value` is exactly `{ "$config": "<non-empty string>" }`. */
|
|
12
|
+
export function isConfigRef(value: unknown): value is ConfigRef {
|
|
13
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
14
|
+
const keys = Object.keys(value);
|
|
15
|
+
const ref = (value as { $config?: unknown }).$config;
|
|
16
|
+
return keys.length === 1 && keys[0] === "$config" && typeof ref === "string" && ref.length > 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ConfigRefError extends Error {
|
|
20
|
+
constructor(
|
|
21
|
+
message: string,
|
|
22
|
+
readonly missingKeys: string[],
|
|
23
|
+
) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "ConfigRefError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Replace every `{ "$config": "KEY" }` leaf in `value` with `lookup(KEY)`.
|
|
31
|
+
* Walks arrays and plain objects. Missing keys (lookup returns undefined) are
|
|
32
|
+
* collected and reported in one error. A lookup that throws (for example on a
|
|
33
|
+
* forbidden key) propagates as-is.
|
|
34
|
+
*/
|
|
35
|
+
export function resolveConfigRefs<T>(
|
|
36
|
+
value: unknown,
|
|
37
|
+
lookup: (key: string) => string | undefined,
|
|
38
|
+
): T {
|
|
39
|
+
const missing = new Set<string>();
|
|
40
|
+
|
|
41
|
+
const walk = (node: unknown): unknown => {
|
|
42
|
+
if (isConfigRef(node)) {
|
|
43
|
+
const resolved = lookup(node.$config);
|
|
44
|
+
if (resolved === undefined) missing.add(node.$config);
|
|
45
|
+
return resolved;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
48
|
+
if (node !== null && typeof node === "object") {
|
|
49
|
+
return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, walk(v)]));
|
|
50
|
+
}
|
|
51
|
+
return node;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const result = walk(value);
|
|
55
|
+
if (missing.size > 0) {
|
|
56
|
+
const keys = [...missing].sort();
|
|
57
|
+
throw new ConfigRefError(`Unresolved config reference(s): ${keys.join(", ")}`, keys);
|
|
58
|
+
}
|
|
59
|
+
return result as T;
|
|
60
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getDbClient } from "./runtime";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The page's edit counter, `MAX(page_versions.version) + 1`, or 1 before the
|
|
5
|
+
* first snapshot. Reads one indexed aggregate instead of every snapshot body:
|
|
6
|
+
* loading all versions of a large, often-edited page blocked the event loop
|
|
7
|
+
* for seconds per call.
|
|
8
|
+
*/
|
|
9
|
+
export async function getPageEditCounter(pageId: string): Promise<number> {
|
|
10
|
+
const row = await getDbClient().get<{ latest: number | null }>(
|
|
11
|
+
"SELECT MAX(version) AS latest FROM page_versions WHERE pageId = ?",
|
|
12
|
+
[pageId],
|
|
13
|
+
);
|
|
14
|
+
return (row?.latest ?? 0) + 1;
|
|
15
|
+
}
|
package/src/be/db/runtime.ts
CHANGED
|
@@ -104,7 +104,34 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
|
|
|
104
104
|
db = new Database(dbPath, { create: true });
|
|
105
105
|
console.log(`Database initialized at ${dbPath}`);
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
// Boot must finish before getDb() hands this handle out. A step below can
|
|
108
|
+
// throw SQLITE_BUSY while another connection holds the file, and the
|
|
109
|
+
// db-client retries BUSY by calling getDb() again. With `db` still assigned,
|
|
110
|
+
// that retry got a connection whose encryption key was never resolved, and
|
|
111
|
+
// the server died on "Encryption key not resolved yet". Drop the handle so
|
|
112
|
+
// the retry runs boot again.
|
|
113
|
+
const opened = db;
|
|
114
|
+
try {
|
|
115
|
+
return bootOpenedDb(opened, dbPath, resolvePromptTemplate, autoEncryptLegacyPlaintextSecrets);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (db === opened) {
|
|
118
|
+
db = null;
|
|
119
|
+
try {
|
|
120
|
+
opened.close();
|
|
121
|
+
} catch {
|
|
122
|
+
// Already closed by the step that failed.
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function bootOpenedDb(
|
|
130
|
+
database: Database,
|
|
131
|
+
dbPath: string,
|
|
132
|
+
resolvePromptTemplate: typeof import("../db").resolvePromptTemplate,
|
|
133
|
+
autoEncryptLegacyPlaintextSecrets: typeof import("../db").autoEncryptLegacyPlaintextSecrets,
|
|
134
|
+
): Database {
|
|
108
135
|
database.run("PRAGMA journal_mode = WAL;");
|
|
109
136
|
database.run("PRAGMA busy_timeout = 5000;");
|
|
110
137
|
database.run("PRAGMA foreign_keys = ON;");
|
|
@@ -140,7 +167,7 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
|
|
|
140
167
|
// Old databases have CHECK(status IN ('pending','in_progress','completed','failed'))
|
|
141
168
|
// which blocks 'cancelled', 'paused', 'offered', 'unassigned' statuses
|
|
142
169
|
try {
|
|
143
|
-
const taskSchemaInfo =
|
|
170
|
+
const taskSchemaInfo = database
|
|
144
171
|
.prepare<{ sql: string | null }, []>(
|
|
145
172
|
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'agent_tasks'",
|
|
146
173
|
)
|
|
@@ -153,7 +180,7 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
|
|
|
153
180
|
|
|
154
181
|
if (needsStatusMigration) {
|
|
155
182
|
console.log("[Migration] Removing restrictive CHECK constraint on agent_tasks.status");
|
|
156
|
-
|
|
183
|
+
database.run("PRAGMA foreign_keys=off");
|
|
157
184
|
|
|
158
185
|
// Migrations run before this compatibility guard, so a legacy table now
|
|
159
186
|
// carries every current column. Rebuilding from an old hard-coded column
|
|
@@ -169,12 +196,12 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
|
|
|
169
196
|
if (rebuiltSchemaSql === schemaSql || !/agent_tasks_new/i.test(rebuiltSchemaSql)) {
|
|
170
197
|
throw new Error("Could not derive agent_tasks schema without legacy status CHECK");
|
|
171
198
|
}
|
|
172
|
-
const columns =
|
|
199
|
+
const columns = database
|
|
173
200
|
.prepare<{ name: string }, []>('PRAGMA table_info("agent_tasks")')
|
|
174
201
|
.all()
|
|
175
202
|
.map((column) => `"${column.name.replaceAll('"', '""')}"`)
|
|
176
203
|
.join(", ");
|
|
177
|
-
const schemaObjects =
|
|
204
|
+
const schemaObjects = database
|
|
178
205
|
.prepare<{ sql: string }, []>(
|
|
179
206
|
`SELECT sql FROM sqlite_master
|
|
180
207
|
WHERE tbl_name = 'agent_tasks'
|
|
@@ -194,13 +221,13 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
|
|
|
194
221
|
for (const sql of schemaObjects) database.run(sql);
|
|
195
222
|
})();
|
|
196
223
|
|
|
197
|
-
|
|
224
|
+
database.run("PRAGMA foreign_keys=on");
|
|
198
225
|
console.log("[Migration] Successfully removed CHECK constraint on agent_tasks.status");
|
|
199
226
|
}
|
|
200
227
|
} catch (e) {
|
|
201
228
|
console.error("[Migration] Failed to update agent_tasks CHECK constraint:", e);
|
|
202
229
|
try {
|
|
203
|
-
|
|
230
|
+
database.run("PRAGMA foreign_keys=on");
|
|
204
231
|
} catch (cleanupError) {
|
|
205
232
|
console.error("[Migration] Failed to re-enable SQLite foreign_keys pragma:", cleanupError);
|
|
206
233
|
}
|
|
@@ -291,7 +318,7 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
|
|
|
291
318
|
throw err;
|
|
292
319
|
}
|
|
293
320
|
|
|
294
|
-
return
|
|
321
|
+
return database;
|
|
295
322
|
}
|
|
296
323
|
|
|
297
324
|
export function getDb(path?: string): Database {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getDbClient } from "./runtime";
|
|
2
|
+
|
|
3
|
+
export type SwarmSkillNameResolution =
|
|
4
|
+
| { kind: "found"; skillId: string }
|
|
5
|
+
| { kind: "ambiguous"; skillIds: string[] }
|
|
6
|
+
| { kind: "none" };
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a swarm-scope skill name for `skill-get`.
|
|
10
|
+
*
|
|
11
|
+
* Migration 019 makes a name unique only per scope + owner, so a swarm name can
|
|
12
|
+
* match one ownerless row plus any number of agent-owned rows. Precedence:
|
|
13
|
+
* the ownerless row, then the caller's own row, then a single owned row.
|
|
14
|
+
* Several foreign-owned rows are ambiguous; the caller must pass a skillId.
|
|
15
|
+
*
|
|
16
|
+
* `getSkillByName(name, "swarm")` stays ownerless-only: the seeder relies on it.
|
|
17
|
+
*/
|
|
18
|
+
export async function resolveSwarmSkillByName(
|
|
19
|
+
name: string,
|
|
20
|
+
callerAgentId?: string,
|
|
21
|
+
): Promise<SwarmSkillNameResolution> {
|
|
22
|
+
const rows = await getDbClient().query<{ id: string; ownerAgentId: string | null }>(
|
|
23
|
+
"SELECT id, ownerAgentId FROM skills WHERE name = ? AND scope = 'swarm' ORDER BY createdAt, id",
|
|
24
|
+
[name],
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const ownerless = rows.find((row) => !row.ownerAgentId);
|
|
28
|
+
if (ownerless) return { kind: "found", skillId: ownerless.id };
|
|
29
|
+
|
|
30
|
+
const own = callerAgentId ? rows.find((row) => row.ownerAgentId === callerAgentId) : undefined;
|
|
31
|
+
if (own) return { kind: "found", skillId: own.id };
|
|
32
|
+
|
|
33
|
+
if (rows.length === 1) return { kind: "found", skillId: rows[0]!.id };
|
|
34
|
+
if (rows.length > 1) return { kind: "ambiguous", skillIds: rows.map((row) => row.id) };
|
|
35
|
+
return { kind: "none" };
|
|
36
|
+
}
|
package/src/be/db/tasks/read.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
RoutingAffinitySchema,
|
|
21
21
|
} from "../../../types";
|
|
22
22
|
import { parseProviderMeta } from "../../../utils/provider-metadata";
|
|
23
|
+
import { scrubSecrets } from "../../../utils/secret-scrubber";
|
|
23
24
|
import { getAgentById } from "../agents";
|
|
24
25
|
import { getDbClient } from "../runtime";
|
|
25
26
|
|
|
@@ -87,6 +88,7 @@ export type AgentTaskRow = {
|
|
|
87
88
|
model: string | null;
|
|
88
89
|
modelTier: string | null;
|
|
89
90
|
effort: string | null;
|
|
91
|
+
resolvedEffort?: string | null;
|
|
90
92
|
resolvedModel?: string | null;
|
|
91
93
|
modelSource?: string | null;
|
|
92
94
|
modelAlias?: string | null;
|
|
@@ -154,6 +156,7 @@ type AgentTaskSummaryRow = Pick<
|
|
|
154
156
|
| "modelSource"
|
|
155
157
|
| "modelAlias"
|
|
156
158
|
| "effort"
|
|
159
|
+
| "resolvedEffort"
|
|
157
160
|
| "provider"
|
|
158
161
|
| "requestedByUserId"
|
|
159
162
|
| "progress"
|
|
@@ -207,6 +210,7 @@ const LIST_COLUMNS = {
|
|
|
207
210
|
agent_tasks.offeredTo, agent_tasks.acceptedAt, agent_tasks.parentTaskId,
|
|
208
211
|
agent_tasks.scheduleId, agent_tasks.model, agent_tasks.modelTier,
|
|
209
212
|
agent_tasks.resolvedModel, agent_tasks.modelSource, agent_tasks.modelAlias, agent_tasks.effort,
|
|
213
|
+
agent_tasks.resolvedEffort,
|
|
210
214
|
agent_tasks.provider, agent_tasks.requestedByUserId, agent_tasks.progress,
|
|
211
215
|
agent_tasks.createdAt, agent_tasks.lastUpdatedAt, agent_tasks.finishedAt,
|
|
212
216
|
agent_tasks.peakContextPercent`,
|
|
@@ -315,6 +319,9 @@ export function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
315
319
|
effort: ReasoningEffortSchema.safeParse(row.effort).success
|
|
316
320
|
? (row.effort as ReasoningEffort)
|
|
317
321
|
: undefined,
|
|
322
|
+
resolvedEffort: ReasoningEffortSchema.safeParse(row.resolvedEffort).success
|
|
323
|
+
? (row.resolvedEffort as ReasoningEffort)
|
|
324
|
+
: undefined,
|
|
318
325
|
scheduleId: row.scheduleId ?? undefined,
|
|
319
326
|
workflowRunId: row.workflowRunId ?? undefined,
|
|
320
327
|
workflowRunStepId: row.workflowRunStepId ?? undefined,
|
|
@@ -381,6 +388,9 @@ export function rowToAgentTaskSummary(row: AgentTaskSummaryRow): AgentTaskSummar
|
|
|
381
388
|
effort: ReasoningEffortSchema.safeParse(row.effort).success
|
|
382
389
|
? (row.effort as ReasoningEffort)
|
|
383
390
|
: undefined,
|
|
391
|
+
resolvedEffort: ReasoningEffortSchema.safeParse(row.resolvedEffort).success
|
|
392
|
+
? (row.resolvedEffort as ReasoningEffort)
|
|
393
|
+
: undefined,
|
|
384
394
|
provider: (row.provider as ProviderName | null) ?? undefined,
|
|
385
395
|
requestedByUserId: row.requestedByUserId ?? undefined,
|
|
386
396
|
progress: row.progress ?? undefined,
|
|
@@ -1035,6 +1045,163 @@ export async function markFinalizedSlackRelaysDelivered(): Promise<number> {
|
|
|
1035
1045
|
return result.changes;
|
|
1036
1046
|
}
|
|
1037
1047
|
|
|
1048
|
+
/** Pending Chat SDK relay row: the terminal task plus its obligation bookkeeping. */
|
|
1049
|
+
export interface PendingChatRelay {
|
|
1050
|
+
task: AgentTask;
|
|
1051
|
+
createdAt: string;
|
|
1052
|
+
lastError: string | null;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Backoff gate for a chat relay obligation: eligible when never attempted, or
|
|
1057
|
+
* when `min(3 s * 2^attempt_count, 10 min)` passed since `last_attempt_at`.
|
|
1058
|
+
* `attempt_count >= 8` is already past the cap (3 s * 2^8 = 768 s). The one
|
|
1059
|
+
* parameter is the reference time as ISO text.
|
|
1060
|
+
*/
|
|
1061
|
+
const CHAT_RELAY_ELIGIBLE_SQL = `(obligation.last_attempt_at IS NULL
|
|
1062
|
+
OR (julianday(?) - julianday(obligation.last_attempt_at)) * 86400000.0 >=
|
|
1063
|
+
CASE WHEN obligation.attempt_count >= 8 THEN 600000
|
|
1064
|
+
ELSE 3000 * (1 << obligation.attempt_count) END)`;
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* Terminal chat tasks whose relay obligation is pending, out of backoff at
|
|
1068
|
+
* `now`, and whose `task:chat-sdk:<adapter>:` contextKey names one of
|
|
1069
|
+
* `adapters` (the adapters that are running). Rows of other adapters are left
|
|
1070
|
+
* out of the query, so a stopped adapter cannot fill the window and starve the
|
|
1071
|
+
* healthy ones. Returns no rows when `adapters` is empty. Never-attempted rows
|
|
1072
|
+
* sort first, then the oldest attempts. A contextKey that does not parse as a
|
|
1073
|
+
* chat key is not selected here; `giveUpStaleChatRelays` retires such rows once
|
|
1074
|
+
* they age out.
|
|
1075
|
+
*/
|
|
1076
|
+
export async function getPendingChatRelayTasks(
|
|
1077
|
+
now: number = Date.now(),
|
|
1078
|
+
limit = 200,
|
|
1079
|
+
adapters: readonly string[] = [],
|
|
1080
|
+
): Promise<PendingChatRelay[]> {
|
|
1081
|
+
if (adapters.length === 0) return [];
|
|
1082
|
+
for (const adapter of adapters) {
|
|
1083
|
+
if (!/^[a-z]+$/.test(adapter)) throw new Error(`invalid chat adapter name: ${adapter}`);
|
|
1084
|
+
}
|
|
1085
|
+
const adapterFilter = adapters.map(() => "task.contextKey GLOB ?").join(" OR ");
|
|
1086
|
+
const rows = await getDbClient().query<
|
|
1087
|
+
AgentTaskRow & {
|
|
1088
|
+
relay_created_at: string;
|
|
1089
|
+
relay_last_error: string | null;
|
|
1090
|
+
}
|
|
1091
|
+
>(
|
|
1092
|
+
`SELECT task.*,
|
|
1093
|
+
obligation.created_at AS relay_created_at,
|
|
1094
|
+
obligation.last_error AS relay_last_error
|
|
1095
|
+
FROM chat_relay_obligations obligation
|
|
1096
|
+
JOIN agent_tasks task ON task.id = obligation.task_id
|
|
1097
|
+
WHERE obligation.delivered_at IS NULL
|
|
1098
|
+
AND obligation.given_up_at IS NULL
|
|
1099
|
+
AND task.status IN ('completed', 'failed', 'cancelled')
|
|
1100
|
+
AND (${adapterFilter})
|
|
1101
|
+
AND ${CHAT_RELAY_ELIGIBLE_SQL}
|
|
1102
|
+
ORDER BY obligation.last_attempt_at IS NOT NULL,
|
|
1103
|
+
obligation.last_attempt_at ASC,
|
|
1104
|
+
obligation.created_at ASC
|
|
1105
|
+
LIMIT ?`,
|
|
1106
|
+
[
|
|
1107
|
+
...adapters.map((adapter) => `task:chat-sdk:${adapter}:*`),
|
|
1108
|
+
new Date(now).toISOString(),
|
|
1109
|
+
limit,
|
|
1110
|
+
],
|
|
1111
|
+
);
|
|
1112
|
+
return rows.map((row) => ({
|
|
1113
|
+
task: rowToAgentTask(row),
|
|
1114
|
+
createdAt: row.relay_created_at,
|
|
1115
|
+
lastError: row.relay_last_error,
|
|
1116
|
+
}));
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Give up every pending chat relay obligation created more than `olderThanMs`
|
|
1121
|
+
* before `now`, whatever the adapter state. Returns how many rows were retired.
|
|
1122
|
+
*/
|
|
1123
|
+
export async function giveUpStaleChatRelays(now: number, olderThanMs: number): Promise<number> {
|
|
1124
|
+
const at = new Date(now).toISOString();
|
|
1125
|
+
const cutoff = new Date(now - olderThanMs).toISOString();
|
|
1126
|
+
const result = await getDbClient().run(
|
|
1127
|
+
`UPDATE chat_relay_obligations
|
|
1128
|
+
SET given_up_at = ?, last_error = 'gave up: older than 24h', updated_at = ?
|
|
1129
|
+
WHERE delivered_at IS NULL AND given_up_at IS NULL AND created_at < ?`,
|
|
1130
|
+
[at, at, cutoff],
|
|
1131
|
+
);
|
|
1132
|
+
return result.changes;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* Claim a chat relay row before the send: bump `attempt_count` and set
|
|
1137
|
+
* `last_attempt_at`. Conditional on the row still being pending and out of
|
|
1138
|
+
* backoff, so two concurrent ticks cannot both send. Returns true when claimed.
|
|
1139
|
+
*/
|
|
1140
|
+
export async function markChatRelayAttempted(
|
|
1141
|
+
taskId: string,
|
|
1142
|
+
now: number = Date.now(),
|
|
1143
|
+
): Promise<boolean> {
|
|
1144
|
+
const at = new Date(now).toISOString();
|
|
1145
|
+
const result = await getDbClient().run(
|
|
1146
|
+
`UPDATE chat_relay_obligations AS obligation
|
|
1147
|
+
SET attempt_count = attempt_count + 1,
|
|
1148
|
+
last_attempt_at = ?,
|
|
1149
|
+
updated_at = ?
|
|
1150
|
+
WHERE task_id = ?
|
|
1151
|
+
AND delivered_at IS NULL
|
|
1152
|
+
AND given_up_at IS NULL
|
|
1153
|
+
AND ${CHAT_RELAY_ELIGIBLE_SQL}`,
|
|
1154
|
+
[at, at, taskId, at],
|
|
1155
|
+
);
|
|
1156
|
+
return result.changes > 0;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/** Record why the last chat relay attempt failed. The text is scrubbed before it is stored. */
|
|
1160
|
+
export async function recordChatRelayError(
|
|
1161
|
+
taskId: string,
|
|
1162
|
+
error: string,
|
|
1163
|
+
now: number = Date.now(),
|
|
1164
|
+
): Promise<boolean> {
|
|
1165
|
+
const result = await getDbClient().run(
|
|
1166
|
+
`UPDATE chat_relay_obligations
|
|
1167
|
+
SET last_error = ?, updated_at = ?
|
|
1168
|
+
WHERE task_id = ? AND delivered_at IS NULL`,
|
|
1169
|
+
[scrubSecrets(error), new Date(now).toISOString(), taskId],
|
|
1170
|
+
);
|
|
1171
|
+
return result.changes > 0;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/** Mark a chat relay obligation delivered after the platform accepted every chunk. Idempotent. */
|
|
1175
|
+
export async function markChatRelayDelivered(
|
|
1176
|
+
taskId: string,
|
|
1177
|
+
now: number = Date.now(),
|
|
1178
|
+
): Promise<boolean> {
|
|
1179
|
+
const at = new Date(now).toISOString();
|
|
1180
|
+
const result = await getDbClient().run(
|
|
1181
|
+
`UPDATE chat_relay_obligations
|
|
1182
|
+
SET delivered_at = ?, updated_at = ?
|
|
1183
|
+
WHERE task_id = ? AND delivered_at IS NULL`,
|
|
1184
|
+
[at, at, taskId],
|
|
1185
|
+
);
|
|
1186
|
+
return result.changes > 0;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/** Stop retrying a chat relay obligation. The reason is scrubbed before it is stored. */
|
|
1190
|
+
export async function markChatRelayGivenUp(
|
|
1191
|
+
taskId: string,
|
|
1192
|
+
error: string,
|
|
1193
|
+
now: number = Date.now(),
|
|
1194
|
+
): Promise<boolean> {
|
|
1195
|
+
const at = new Date(now).toISOString();
|
|
1196
|
+
const result = await getDbClient().run(
|
|
1197
|
+
`UPDATE chat_relay_obligations
|
|
1198
|
+
SET given_up_at = ?, last_error = ?, updated_at = ?
|
|
1199
|
+
WHERE task_id = ? AND delivered_at IS NULL AND given_up_at IS NULL`,
|
|
1200
|
+
[at, scrubSecrets(error), at, taskId],
|
|
1201
|
+
);
|
|
1202
|
+
return result.changes > 0;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1038
1205
|
/**
|
|
1039
1206
|
* Get tasks that were recently finished (completed/failed) by workers (non-lead agents).
|
|
1040
1207
|
* Used by leads to know when workers complete tasks.
|
|
@@ -1334,6 +1501,69 @@ export async function getLatestLeadTaskInThread(
|
|
|
1334
1501
|
return row ? rowToAgentTask(row) : null;
|
|
1335
1502
|
}
|
|
1336
1503
|
|
|
1504
|
+
/**
|
|
1505
|
+
* ContextKey twins of the Slack thread lookups above, for channels that key a
|
|
1506
|
+
* conversation by `contextKey` only (Chat SDK). `source` narrows to the
|
|
1507
|
+
* channel's ingress tasks, as the Slack twins do with `source = 'slack'`:
|
|
1508
|
+
* follow-ups and delegated worker tasks inherit the parent's contextKey.
|
|
1509
|
+
* All three use `idx_agent_tasks_context_key_status`.
|
|
1510
|
+
*/
|
|
1511
|
+
export async function getAgentWorkingOnContextKey(
|
|
1512
|
+
contextKey: string,
|
|
1513
|
+
source?: string,
|
|
1514
|
+
): Promise<Agent | null> {
|
|
1515
|
+
const taskRow = await getDbClient().get<AgentTaskRow>(
|
|
1516
|
+
`SELECT agentId FROM agent_tasks
|
|
1517
|
+
WHERE contextKey = ?
|
|
1518
|
+
AND (? IS NULL OR source = ?)
|
|
1519
|
+
ORDER BY createdAt DESC, rowid DESC
|
|
1520
|
+
LIMIT 1`,
|
|
1521
|
+
[contextKey, source ?? null, source ?? null],
|
|
1522
|
+
);
|
|
1523
|
+
|
|
1524
|
+
if (taskRow?.agentId) return getAgentById(taskRow.agentId);
|
|
1525
|
+
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/** Latest `in_progress` or `pending` task on a contextKey (dependency chaining). */
|
|
1530
|
+
export async function getLatestActiveTaskByContextKey(
|
|
1531
|
+
contextKey: string,
|
|
1532
|
+
source?: string,
|
|
1533
|
+
): Promise<AgentTask | null> {
|
|
1534
|
+
const row = await getDbClient().get<AgentTaskRow>(
|
|
1535
|
+
`SELECT * FROM agent_tasks
|
|
1536
|
+
WHERE contextKey = ?
|
|
1537
|
+
AND (? IS NULL OR source = ?)
|
|
1538
|
+
AND status IN ('in_progress', 'pending')
|
|
1539
|
+
ORDER BY createdAt DESC, rowid DESC
|
|
1540
|
+
LIMIT 1`,
|
|
1541
|
+
[contextKey, source ?? null, source ?? null],
|
|
1542
|
+
);
|
|
1543
|
+
|
|
1544
|
+
return row ? rowToAgentTask(row) : null;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
/** Latest task assigned to a lead agent on a contextKey (the steering target). */
|
|
1548
|
+
export async function getLatestLeadTaskByContextKey(
|
|
1549
|
+
contextKey: string,
|
|
1550
|
+
source?: string,
|
|
1551
|
+
): Promise<AgentTask | null> {
|
|
1552
|
+
const row = await getDbClient().get<AgentTaskRow>(
|
|
1553
|
+
`SELECT t.*
|
|
1554
|
+
FROM agent_tasks t
|
|
1555
|
+
JOIN agents a ON a.id = t.agentId
|
|
1556
|
+
WHERE t.contextKey = ?
|
|
1557
|
+
AND (? IS NULL OR t.source = ?)
|
|
1558
|
+
AND a.isLead = 1
|
|
1559
|
+
ORDER BY t.createdAt DESC, t.rowid DESC
|
|
1560
|
+
LIMIT 1`,
|
|
1561
|
+
[contextKey, source ?? null, source ?? null],
|
|
1562
|
+
);
|
|
1563
|
+
|
|
1564
|
+
return row ? rowToAgentTask(row) : null;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1337
1567
|
/**
|
|
1338
1568
|
* Find the most recent task in a Slack thread, regardless of source or status.
|
|
1339
1569
|
* Unlike getAgentWorkingOnThread (which filters source='slack'), this finds ALL tasks
|
package/src/be/db/tasks/write.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
AgentTask,
|
|
9
9
|
AgentTaskSource,
|
|
10
10
|
ProviderName,
|
|
11
|
+
ReasoningEffort,
|
|
11
12
|
RuntimePool,
|
|
12
13
|
TaskAttachment,
|
|
13
14
|
} from "../../../types";
|
|
@@ -312,6 +313,8 @@ export async function updateTaskClaudeSessionId(
|
|
|
312
313
|
model?: string,
|
|
313
314
|
harnessVariant?: string,
|
|
314
315
|
harnessVariantMeta?: Record<string, unknown>,
|
|
316
|
+
/** Effort the session runs at; null records that the harness default applied. */
|
|
317
|
+
resolvedEffort?: ReasoningEffort | null,
|
|
315
318
|
): Promise<AgentTask | null> {
|
|
316
319
|
const setClauses = ["claudeSessionId = ?", "lastUpdatedAt = ?"];
|
|
317
320
|
const params: (string | null)[] = [claudeSessionId, new Date().toISOString()];
|
|
@@ -336,6 +339,10 @@ export async function updateTaskClaudeSessionId(
|
|
|
336
339
|
setClauses.push("harnessVariantMeta = ?");
|
|
337
340
|
params.push(JSON.stringify(harnessVariantMeta));
|
|
338
341
|
}
|
|
342
|
+
if (resolvedEffort !== undefined) {
|
|
343
|
+
setClauses.push("resolvedEffort = ?");
|
|
344
|
+
params.push(resolvedEffort);
|
|
345
|
+
}
|
|
339
346
|
|
|
340
347
|
params.push(taskId);
|
|
341
348
|
|