@desplega.ai/agent-swarm 1.173.0 → 2.1.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-kr4abrsk.js} +17 -16
- package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
- package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
- package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
- package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
- package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
- package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
- package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
- package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
- package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
- package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
- package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
- package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
- package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
- package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
- package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
- package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
- package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
- package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
- package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
- package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
- package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
- package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
- package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
- package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/cli-cvv9k0hh.js +10143 -0
- package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
- package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
- package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
- package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
- package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
- package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
- package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
- package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
- package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
- package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
- package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
- package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
- package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
- package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
- package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
- package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
- package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
- package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
- package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
- package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
- package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
- package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
- package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/cli-wfnemr1t.js +86 -0
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
- package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
- package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
- package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
- package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
- package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
- package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
- package/dist/cli.js +34 -49
- package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
- package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
- package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
- package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
- package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
- package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
- package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
- package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
- package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
- package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
- package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
- package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.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-s9ncp9vy.js} +18 -17
- package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
- package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
- package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
- package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
- package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
- package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
- package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
- package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
- 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-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
- package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
- package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
- package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
- package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
- package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
- package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
- package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
- package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
- package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
- package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
- package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
- package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
- package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-adbc1c10.js → setup-2fp2pypp.js} +2 -2
- package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
- package/dist/{work-objects-wpj8ck95.js → work-objects-6k0ywz3m.js} +41 -36
- package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
- package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
- package/openapi.json +1279 -329
- package/package.json +15 -15
- package/src/agentmail/handlers.ts +21 -11
- package/src/apps/definition.ts +16 -0
- package/src/azure-devops/api.ts +52 -2
- package/src/azure-devops/boards-sync.ts +50 -20
- package/src/azure-devops/index.ts +1 -0
- package/src/azure-devops/outbound.ts +95 -0
- package/src/be/boot-seeds.ts +11 -0
- package/src/be/config-refs.ts +60 -0
- package/src/be/db/model-profiles.ts +315 -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 +237 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +87 -36
- 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/migrations/219_relabel_pi_context_compactions.sql +22 -0
- package/src/be/migrations/220_model_profiles.sql +137 -0
- package/src/be/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +155 -10
- package/src/be/model-validation.ts +12 -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 +22 -8
- package/src/be/secret-registry.ts +6 -2
- 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-model-profiles.ts +41 -0
- package/src/be/seed-pricing.ts +19 -2
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
- 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-scripts/index.ts +9 -0
- 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 +53 -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 +193 -71
- package/src/e2b/env.ts +5 -0
- package/src/extensions/catalog.generated.json +17 -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/loader.ts +10 -5
- package/src/extensions/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/heartbeat.ts +2 -1
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/agents.ts +49 -2
- package/src/http/all-routes.ts +1 -1
- package/src/http/apps.ts +30 -3
- package/src/http/config.ts +62 -19
- package/src/http/core.ts +8 -0
- package/src/http/index.ts +25 -3
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp.ts +15 -5
- package/src/http/model-profiles.ts +303 -0
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +13 -7
- package/src/http/pages.ts +3 -13
- package/src/http/poll.ts +42 -71
- package/src/http/requested-by.ts +54 -0
- package/src/http/script-runs.ts +1 -1
- package/src/http/scripts.ts +26 -2
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +79 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +160 -3
- 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/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
- package/src/pages/version.ts +4 -5
- package/src/prompts/base-prompt.ts +111 -45
- package/src/providers/acp-target-catalog.ts +6 -0
- package/src/providers/acp-targets.ts +56 -3
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +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/pi-mono-extension.ts +17 -3
- package/src/providers/pricing-sources.md +33 -2
- package/src/providers/reasoning-effort.ts +37 -0
- package/src/providers/types.ts +6 -2
- package/src/rbac/legacy-policy.ts +16 -2
- package/src/rbac/permissions.ts +26 -0
- package/src/scheduler/deferred-task-waits.ts +18 -5
- package/src/scheduler/scheduler.ts +11 -3
- package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
- package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
- package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
- package/src/scripts-runtime/extract-args-schema.ts +9 -8
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/quickjs-compat.ts +464 -0
- package/src/scripts-runtime/sdk-allowlist.ts +12 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +39 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
- package/src/server.ts +62 -19
- package/src/slack/blocks.ts +4 -2
- package/src/slack/event-dedup.ts +1 -1
- package/src/slack/reaction-shortcode.ts +14 -0
- package/src/slack/render-v2.ts +12 -7
- package/src/slack/responses.ts +5 -4
- package/src/slack/thread-buffer.ts +41 -22
- 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 +15 -33
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/agentmail-filters.test.ts +47 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/apps-spike2.test.ts +35 -0
- package/src/tests/azure-devops-outbound.test.ts +420 -0
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +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 +22 -0
- package/src/tests/db-task-write-contract.test.ts +11 -0
- package/src/tests/deferred-task-wake.test.ts +78 -1
- 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/env-flag.test.ts +1 -0
- package/src/tests/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-catalog.test.ts +1 -0
- package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
- package/src/tests/extensions-loader.test.ts +15 -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/heartbeat-jev-gate-credentials.test.ts +168 -0
- package/src/tests/heartbeat-jev-gate.test.ts +385 -0
- 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-profile-backcompat.test.ts +327 -0
- package/src/tests/model-profile-providers.test.ts +302 -0
- package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
- package/src/tests/model-profiles-api.test.ts +614 -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-keys.test.ts +121 -0
- package/src/tests/pages-feedback.test.ts +4 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -0
- package/src/tests/pi-context-compaction.test.ts +193 -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/profile-claim.test.ts +269 -0
- package/src/tests/prompt-template-remaining.test.ts +35 -0
- package/src/tests/quickjs-compat.test.ts +213 -0
- package/src/tests/rbac-engine.test.ts +32 -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 +6 -0
- package/src/tests/script-executor-conformance.test.ts +252 -1
- package/src/tests/script-executor-quickjs.test.ts +96 -0
- package/src/tests/script-runs-http.test.ts +89 -0
- package/src/tests/scripts-http.test.ts +217 -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 +96 -0
- package/src/tests/seed-model-profiles.test.ts +174 -0
- package/src/tests/seed-scripts.test.ts +2 -2
- 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/skill-invocations.test.ts +4 -2
- package/src/tests/slack-blocks.test.ts +36 -0
- package/src/tests/slack-inline-output.test.ts +14 -0
- package/src/tests/slack-reaction-config.test.ts +20 -0
- package/src/tests/slack-render-v2.test.ts +37 -0
- package/src/tests/slack-thread-buffer.test.ts +98 -1
- 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-llm.test.ts +61 -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/model-profiles/list-model-profiles.ts +54 -0
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/request-human-input.ts +11 -3
- package/src/tools/script-apis.ts +5 -1
- package/src/tools/script-upsert.ts +4 -1
- package/src/tools/send-task.ts +48 -1
- 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/system-one-decide.ts +104 -0
- package/src/tools/task-action.ts +22 -1
- package/src/tools/tool-config.ts +14 -6
- package/src/types.ts +48 -3
- 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 +86 -10
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/utils/vcs-repo-match.ts +29 -0
- package/src/workflows/executors/raw-llm.ts +8 -3
- package/src/workflows/executors/swarm-script.ts +1 -0
- package/src/workflows/executors/system-one-decision.ts +21 -11
- package/src/workflows/executors/workflow-llm.ts +22 -0
- package/src/workflows/index.ts +21 -12
- package/templates/extensions/README.md +1 -0
- package/templates/extensions/comms-adherence-gate/README.md +88 -0
- package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
- package/templates/extensions/comms-adherence-gate/manifest.json +8 -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-42qhyvwx.js +0 -33
- 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
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model profiles: a named (harness, model, effort) picked per task (`profile`)
|
|
3
|
+
* or applied as an agent's default (agent-scoped `MODEL_PROFILE` config row).
|
|
4
|
+
* Claim resolves them (`src/be/model-tier-resolution.ts`). See
|
|
5
|
+
* runbooks/model-tiers.md § Model profiles.
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
type ModelProfile,
|
|
9
|
+
type ProviderName,
|
|
10
|
+
ProviderNameSchema,
|
|
11
|
+
type ReasoningEffort,
|
|
12
|
+
ReasoningEffortSchema,
|
|
13
|
+
} from "../../types";
|
|
14
|
+
import { vcsRepoName, vcsRepoUrlMatches } from "../../utils/vcs-repo-match";
|
|
15
|
+
import { getDbClient } from "./runtime";
|
|
16
|
+
import { SUPERSEDED_RESUME_REPAIR_WINDOW_MS } from "./tasks/read";
|
|
17
|
+
|
|
18
|
+
/** Agent-scoped swarm_config key holding the agent's default profile name. */
|
|
19
|
+
export const MODEL_PROFILE_CONFIG_KEY = "MODEL_PROFILE";
|
|
20
|
+
|
|
21
|
+
type ModelProfileRow = {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
harness: string;
|
|
25
|
+
model: string;
|
|
26
|
+
effort: string | null;
|
|
27
|
+
allowCustomModel: number;
|
|
28
|
+
description: string | null;
|
|
29
|
+
seededFrom: string | null;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
lastUpdatedAt: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function rowToModelProfile(row: ModelProfileRow): ModelProfile {
|
|
35
|
+
return {
|
|
36
|
+
id: row.id,
|
|
37
|
+
name: row.name,
|
|
38
|
+
harness: ProviderNameSchema.parse(row.harness),
|
|
39
|
+
model: row.model,
|
|
40
|
+
effort: ReasoningEffortSchema.safeParse(row.effort).success
|
|
41
|
+
? (row.effort as ReasoningEffort)
|
|
42
|
+
: null,
|
|
43
|
+
allowCustomModel: row.allowCustomModel === 1,
|
|
44
|
+
description: row.description,
|
|
45
|
+
seededFrom: row.seededFrom,
|
|
46
|
+
createdAt: row.createdAt,
|
|
47
|
+
lastUpdatedAt: row.lastUpdatedAt,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function listModelProfiles(
|
|
52
|
+
filter: { harness?: ProviderName } = {},
|
|
53
|
+
): Promise<ModelProfile[]> {
|
|
54
|
+
const rows = filter.harness
|
|
55
|
+
? await getDbClient().query<ModelProfileRow>(
|
|
56
|
+
"SELECT * FROM model_profiles WHERE harness = ? ORDER BY harness, name",
|
|
57
|
+
[filter.harness],
|
|
58
|
+
)
|
|
59
|
+
: await getDbClient().query<ModelProfileRow>(
|
|
60
|
+
"SELECT * FROM model_profiles ORDER BY harness, name",
|
|
61
|
+
);
|
|
62
|
+
return rows.map(rowToModelProfile);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function getModelProfileByName(name: string): Promise<ModelProfile | null> {
|
|
66
|
+
const row = await getDbClient().get<ModelProfileRow>(
|
|
67
|
+
"SELECT * FROM model_profiles WHERE name = ?",
|
|
68
|
+
[name.trim()],
|
|
69
|
+
);
|
|
70
|
+
return row ? rowToModelProfile(row) : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ModelProfileInput {
|
|
74
|
+
name: string;
|
|
75
|
+
harness: ProviderName;
|
|
76
|
+
model: string;
|
|
77
|
+
effort?: ReasoningEffort | null;
|
|
78
|
+
allowCustomModel?: boolean;
|
|
79
|
+
description?: string | null;
|
|
80
|
+
seededFrom?: string | null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Insert a profile. Returns null when the name is taken. */
|
|
84
|
+
export async function createModelProfile(
|
|
85
|
+
input: ModelProfileInput,
|
|
86
|
+
audit: { userId?: string | null } = {},
|
|
87
|
+
): Promise<ModelProfile | null> {
|
|
88
|
+
const now = new Date().toISOString();
|
|
89
|
+
const row = await getDbClient().get<ModelProfileRow>(
|
|
90
|
+
`INSERT INTO model_profiles
|
|
91
|
+
(id, name, harness, model, effort, allowCustomModel, description, seededFrom, createdAt, lastUpdatedAt, created_by, updated_by)
|
|
92
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
93
|
+
ON CONFLICT(name) DO NOTHING
|
|
94
|
+
RETURNING *`,
|
|
95
|
+
[
|
|
96
|
+
crypto.randomUUID(),
|
|
97
|
+
input.name,
|
|
98
|
+
input.harness,
|
|
99
|
+
input.model,
|
|
100
|
+
input.effort ?? null,
|
|
101
|
+
input.allowCustomModel ? 1 : 0,
|
|
102
|
+
input.description ?? null,
|
|
103
|
+
input.seededFrom ?? null,
|
|
104
|
+
now,
|
|
105
|
+
now,
|
|
106
|
+
audit.userId ?? null,
|
|
107
|
+
audit.userId ?? null,
|
|
108
|
+
],
|
|
109
|
+
);
|
|
110
|
+
return row ? rowToModelProfile(row) : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type ModelProfilePatch = Partial<
|
|
114
|
+
Pick<ModelProfileInput, "model" | "effort" | "allowCustomModel" | "description">
|
|
115
|
+
>;
|
|
116
|
+
|
|
117
|
+
/** Update a profile's model, effort or description. The name and harness are fixed. */
|
|
118
|
+
export async function updateModelProfile(
|
|
119
|
+
name: string,
|
|
120
|
+
patch: ModelProfilePatch,
|
|
121
|
+
audit: { userId?: string | null } = {},
|
|
122
|
+
): Promise<ModelProfile | null> {
|
|
123
|
+
const sets: string[] = [];
|
|
124
|
+
const params: (string | number | null)[] = [];
|
|
125
|
+
if (patch.model !== undefined) {
|
|
126
|
+
sets.push("model = ?");
|
|
127
|
+
params.push(patch.model);
|
|
128
|
+
}
|
|
129
|
+
if (patch.effort !== undefined) {
|
|
130
|
+
sets.push("effort = ?");
|
|
131
|
+
params.push(patch.effort);
|
|
132
|
+
}
|
|
133
|
+
if (patch.allowCustomModel !== undefined) {
|
|
134
|
+
sets.push("allowCustomModel = ?");
|
|
135
|
+
params.push(patch.allowCustomModel ? 1 : 0);
|
|
136
|
+
}
|
|
137
|
+
if (patch.description !== undefined) {
|
|
138
|
+
sets.push("description = ?");
|
|
139
|
+
params.push(patch.description);
|
|
140
|
+
}
|
|
141
|
+
sets.push("lastUpdatedAt = ?", "updated_by = ?");
|
|
142
|
+
params.push(new Date().toISOString(), audit.userId ?? null);
|
|
143
|
+
const row = await getDbClient().get<ModelProfileRow>(
|
|
144
|
+
`UPDATE model_profiles SET ${sets.join(", ")} WHERE name = ? RETURNING *`,
|
|
145
|
+
[...params, name],
|
|
146
|
+
);
|
|
147
|
+
return row ? rowToModelProfile(row) : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Tasks (alias `t`) that still hold their profile: unfinished ones, and
|
|
152
|
+
* superseded ones still owed a resume. The resume copies the profile in a
|
|
153
|
+
* later write than the supersede (HTTP supersede, heartbeat remediation), and
|
|
154
|
+
* after a restart the heartbeat's orphan repair makes it, inside the same
|
|
155
|
+
* window (`SUPERSEDED_RESUME_REPAIR_WINDOW_MS`). Binds one parameter: the
|
|
156
|
+
* oldest `finishedAt` the repair still covers.
|
|
157
|
+
*/
|
|
158
|
+
const TASK_HOLDS_PROFILE_SQL = `(
|
|
159
|
+
t.status NOT IN ('completed', 'failed', 'cancelled', 'superseded')
|
|
160
|
+
OR (t.status = 'superseded'
|
|
161
|
+
AND t.workflowRunStepId IS NULL
|
|
162
|
+
AND (t.finishedAt IS NULL OR t.finishedAt > ?)
|
|
163
|
+
AND NOT EXISTS (
|
|
164
|
+
SELECT 1 FROM agent_tasks c WHERE c.parentTaskId = t.id AND c.taskType = 'resume')))`;
|
|
165
|
+
|
|
166
|
+
function repairWindowStart(): string {
|
|
167
|
+
return new Date(Date.now() - SUPERSEDED_RESUME_REPAIR_WINDOW_MS).toISOString();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Who still points at a profile: agents with it as default, and tasks that still hold it. */
|
|
171
|
+
export async function modelProfileReferences(
|
|
172
|
+
name: string,
|
|
173
|
+
): Promise<{ agentIds: string[]; openTaskCount: number }> {
|
|
174
|
+
const agents = await getDbClient().query<{ scopeId: string }>(
|
|
175
|
+
"SELECT scopeId FROM swarm_config WHERE scope = 'agent' AND key = ? AND value = ?",
|
|
176
|
+
[MODEL_PROFILE_CONFIG_KEY, name],
|
|
177
|
+
);
|
|
178
|
+
const tasks = await getDbClient().get<{ n: number }>(
|
|
179
|
+
`SELECT COUNT(*) AS n FROM agent_tasks t WHERE t.profile = ? AND ${TASK_HOLDS_PROFILE_SQL}`,
|
|
180
|
+
[name, repairWindowStart()],
|
|
181
|
+
);
|
|
182
|
+
return { agentIds: agents.map((a) => a.scopeId), openTaskCount: tasks?.n ?? 0 };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Which migration-220 reference trigger refused a write: `missing` when a task
|
|
187
|
+
* or an agent default names a profile that does not exist.
|
|
188
|
+
*/
|
|
189
|
+
export function modelProfileRefError(error: unknown): "missing" | null {
|
|
190
|
+
const message = error instanceof Error ? error.message : "";
|
|
191
|
+
return message.includes("model-profile-missing:") ? "missing" : null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Delete a profile unless a task still holds it (`TASK_HOLDS_PROFILE_SQL`) or
|
|
196
|
+
* an agent default names it. The check is part of the DELETE statement, so a
|
|
197
|
+
* reference written after the caller's own count still makes it `in-use`; the
|
|
198
|
+
* triggers in migration 220 refuse the opposite order (a reference written
|
|
199
|
+
* after this delete).
|
|
200
|
+
*/
|
|
201
|
+
export async function deleteModelProfile(name: string): Promise<"deleted" | "missing" | "in-use"> {
|
|
202
|
+
const row = await getDbClient().get<{ id: string }>(
|
|
203
|
+
`DELETE FROM model_profiles
|
|
204
|
+
WHERE name = ?
|
|
205
|
+
AND NOT EXISTS (
|
|
206
|
+
SELECT 1 FROM agent_tasks t
|
|
207
|
+
WHERE t.profile = model_profiles.name AND ${TASK_HOLDS_PROFILE_SQL})
|
|
208
|
+
AND NOT EXISTS (
|
|
209
|
+
SELECT 1 FROM swarm_config
|
|
210
|
+
WHERE scope = 'agent' AND key = ? AND trim(value) = model_profiles.name)
|
|
211
|
+
RETURNING id`,
|
|
212
|
+
[name, repairWindowStart(), MODEL_PROFILE_CONFIG_KEY],
|
|
213
|
+
);
|
|
214
|
+
if (row) return "deleted";
|
|
215
|
+
return (await getModelProfileByName(name)) ? "in-use" : "missing";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** The agent's default profile name (agent-scoped MODEL_PROFILE), or null. */
|
|
219
|
+
export async function getAgentDefaultProfileName(agentId: string): Promise<string | null> {
|
|
220
|
+
const row = await getDbClient().get<{ value: string }>(
|
|
221
|
+
"SELECT value FROM swarm_config WHERE scope = 'agent' AND scopeId = ? AND key = ?",
|
|
222
|
+
[agentId, MODEL_PROFILE_CONFIG_KEY],
|
|
223
|
+
);
|
|
224
|
+
return row?.value.trim() || null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Which of MODEL_OVERRIDE / REASONING_EFFORT_OVERRIDE the task's repo sets at
|
|
229
|
+
* repo scope, exported or not. The worker env takes a repo row over the
|
|
230
|
+
* agent's own (repo > agent), and a withheld one removes the key, so the
|
|
231
|
+
* agent's default profile must not supply that axis. Finds the repo the way
|
|
232
|
+
* the worker does (`fetchRepoConfig`). `includeSecrets: false` leaves out
|
|
233
|
+
* secret rows, as `/api/config/resolved` does for a worker that cannot read
|
|
234
|
+
* them (`readsRepoSecrets`): that worker's env never gets them.
|
|
235
|
+
*/
|
|
236
|
+
export async function repoModelOverrideKeys(
|
|
237
|
+
vcsRepo: string | null | undefined,
|
|
238
|
+
{ includeSecrets = true }: { includeSecrets?: boolean } = {},
|
|
239
|
+
): Promise<Set<string>> {
|
|
240
|
+
if (!vcsRepo?.trim()) return new Set();
|
|
241
|
+
const repos = await getDbClient().query<{ id: string; url: string }>(
|
|
242
|
+
"SELECT id, url FROM swarm_repos WHERE name = ? ORDER BY name ASC",
|
|
243
|
+
[vcsRepoName(vcsRepo)],
|
|
244
|
+
);
|
|
245
|
+
const repo = repos.find((r) => vcsRepoUrlMatches(r.url, vcsRepo));
|
|
246
|
+
if (!repo) return new Set();
|
|
247
|
+
const rows = await getDbClient().query<{ key: string }>(
|
|
248
|
+
`SELECT key FROM swarm_config
|
|
249
|
+
WHERE scope = 'repo' AND scopeId = ? AND key IN ('MODEL_OVERRIDE', 'REASONING_EFFORT_OVERRIDE')
|
|
250
|
+
${includeSecrets ? "" : "AND isSecret = 0"}`,
|
|
251
|
+
[repo.id],
|
|
252
|
+
);
|
|
253
|
+
return new Set(rows.map((row) => row.key));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Why a task cannot ask for `profile`, or null when it can. PR 1 validity is
|
|
258
|
+
* the harness only: the profile must exist and, when the target agent is known
|
|
259
|
+
* and has a harness, run on that harness. `profile` is exclusive with `model`
|
|
260
|
+
* and `modelTier`, which pick the model another way.
|
|
261
|
+
*/
|
|
262
|
+
export async function taskProfileError(check: {
|
|
263
|
+
profile?: string | null;
|
|
264
|
+
model?: string | null;
|
|
265
|
+
modelTier?: string | null;
|
|
266
|
+
agentId?: string | null;
|
|
267
|
+
}): Promise<string | null> {
|
|
268
|
+
const name = check.profile?.trim();
|
|
269
|
+
if (!name) return null;
|
|
270
|
+
if (check.model?.trim() || check.modelTier?.trim()) {
|
|
271
|
+
return "Pass `profile`, or `model`/`modelTier`, not both.";
|
|
272
|
+
}
|
|
273
|
+
const profile = await getModelProfileByName(name);
|
|
274
|
+
if (!profile) {
|
|
275
|
+
return `Unknown model profile "${name}". List profiles with list-model-profiles.`;
|
|
276
|
+
}
|
|
277
|
+
if (!check.agentId) return null;
|
|
278
|
+
const agent = await getDbClient().get<{ harness: string | null }>(
|
|
279
|
+
"SELECT COALESCE(harness_provider, provider) AS harness FROM agents WHERE id = ?",
|
|
280
|
+
[check.agentId],
|
|
281
|
+
);
|
|
282
|
+
if (agent?.harness && agent.harness !== profile.harness) {
|
|
283
|
+
return `Model profile "${name}" runs on the ${profile.harness} harness; the target agent runs ${agent.harness}.`;
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
type OverrideRowState = { value: string; exportToEnv?: number } | null;
|
|
289
|
+
|
|
290
|
+
/** What a config row does to the worker env: its value, withheld (exportToEnv off), or absent. */
|
|
291
|
+
function effectiveOverride(row: OverrideRowState): string | null {
|
|
292
|
+
if (!row) return null;
|
|
293
|
+
return row.exportToEnv === 0 ? "\u0000withheld" : row.value;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* An agent's default model profile (MODEL_PROFILE) beats its MODEL_OVERRIDE and
|
|
298
|
+
* REASONING_EFFORT_OVERRIDE at claim. An effective change to either override, by
|
|
299
|
+
* any path, drops the profile default, so a stale default never beats a fresh
|
|
300
|
+
* override. Effective means what the worker env sees: the value, and whether
|
|
301
|
+
* the row is exported (`exportToEnv`).
|
|
302
|
+
*/
|
|
303
|
+
export async function clearAgentModelProfileOnOverrideChange(
|
|
304
|
+
agentId: string,
|
|
305
|
+
key: string,
|
|
306
|
+
before: OverrideRowState,
|
|
307
|
+
after: OverrideRowState,
|
|
308
|
+
): Promise<void> {
|
|
309
|
+
if (key !== "MODEL_OVERRIDE" && key !== "REASONING_EFFORT_OVERRIDE") return;
|
|
310
|
+
if (effectiveOverride(before) === effectiveOverride(after)) return;
|
|
311
|
+
await getDbClient().run(
|
|
312
|
+
"DELETE FROM swarm_config WHERE scope = 'agent' AND scopeId = ? AND key = ?",
|
|
313
|
+
[agentId, MODEL_PROFILE_CONFIG_KEY],
|
|
314
|
+
);
|
|
315
|
+
}
|
|
@@ -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
|
+
}
|