@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
package/src/slack/responses.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
markdownToSlack,
|
|
16
16
|
splitSlackSectionText,
|
|
17
17
|
} from "./blocks";
|
|
18
|
+
import { completedStatusIcon } from "./reaction-shortcode";
|
|
18
19
|
import { getSlackOutputAttachments } from "./task-attachments";
|
|
19
20
|
import { slackTaskOutput } from "./task-output";
|
|
20
21
|
|
|
@@ -67,7 +68,7 @@ export function formatInlineCompletionOutputChunks(opts: {
|
|
|
67
68
|
taskId: string;
|
|
68
69
|
output: string;
|
|
69
70
|
}): string[] {
|
|
70
|
-
const header =
|
|
71
|
+
const header = `${completedStatusIcon()} *${opts.agentName}* completed with output (${getTaskLink(opts.taskId)}):\n\n`;
|
|
71
72
|
const slackOutput = markdownToSlack(opts.output.trim());
|
|
72
73
|
return splitSlackSectionText(header + slackOutput);
|
|
73
74
|
}
|
|
@@ -169,7 +170,7 @@ export async function sendTaskResponse(task: AgentTask): Promise<boolean> {
|
|
|
169
170
|
thread_ts: task.slackThreadTs,
|
|
170
171
|
text:
|
|
171
172
|
task.slackReplySent || i > 0
|
|
172
|
-
?
|
|
173
|
+
? `${completedStatusIcon()} ${agentName} completed${i > 0 ? ` (continued ${i + 1}/${blockBatches.length})` : ""}`
|
|
173
174
|
: body,
|
|
174
175
|
username: getAgentDisplayName(agent),
|
|
175
176
|
icon_emoji: getAgentEmoji(agent),
|
|
@@ -324,7 +325,7 @@ export async function updateToFinal(
|
|
|
324
325
|
};
|
|
325
326
|
completionBlockBatches = buildCompletedBlockBatches(completionOpts);
|
|
326
327
|
blocks = completionBlockBatches[0] ?? buildCompletedBlocks(completionOpts);
|
|
327
|
-
text = task.slackReplySent ?
|
|
328
|
+
text = task.slackReplySent ? `${completedStatusIcon()} ${agentName} completed` : body;
|
|
328
329
|
} else if (task.status === "cancelled") {
|
|
329
330
|
blocks = buildCancelledBlocks({ agentName, taskId: task.id });
|
|
330
331
|
text = "Task cancelled";
|
|
@@ -351,7 +352,7 @@ export async function updateToFinal(
|
|
|
351
352
|
await sendWithPersona(app.client, {
|
|
352
353
|
channel: task.slackChannelId,
|
|
353
354
|
thread_ts: task.slackThreadTs ?? messageTs,
|
|
354
|
-
text:
|
|
355
|
+
text: `${completedStatusIcon()} ${agentName} completed (continued ${i + 1}/${completionBlockBatches.length})`,
|
|
355
356
|
username: getAgentDisplayName(agent),
|
|
356
357
|
icon_emoji: getAgentEmoji(agent),
|
|
357
358
|
blocks: completionBlockBatches[i],
|
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
import { findUserByExternalId } from "../be/users";
|
|
8
8
|
import { createAdditiveBuffer } from "../tasks/additive-buffer";
|
|
9
9
|
import { slackContextKey } from "../tasks/context-key";
|
|
10
|
+
import { TaskCreationBlockedError } from "../tasks/errors";
|
|
11
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
12
|
+
import { ackSlackMessage } from "./ack";
|
|
10
13
|
import { getSlackApp } from "./app";
|
|
11
14
|
import { buildBufferFlushBlocks } from "./blocks";
|
|
12
15
|
import { resolveSlackUserId, rewriteSlackMentions } from "./enrich";
|
|
@@ -286,28 +289,44 @@ async function slackFlush(
|
|
|
286
289
|
const dependsOn = !immediate && latestActiveTask ? [latestActiveTask.id] : undefined;
|
|
287
290
|
|
|
288
291
|
const mostRecentTask = await getMostRecentTaskInThread(channelId, threadTs);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
292
|
+
let created: Awaited<ReturnType<typeof createSlackTaskWithFiles>>;
|
|
293
|
+
try {
|
|
294
|
+
created = await createSlackTaskWithFiles(
|
|
295
|
+
fullDescription,
|
|
296
|
+
{
|
|
297
|
+
agentId: lead?.id,
|
|
298
|
+
routingReason:
|
|
299
|
+
lead && mostRecentTask?.agentId === lead.id ? "continuity" : lead ? "skill" : undefined,
|
|
300
|
+
routingSource: lead ? "engine_default" : undefined,
|
|
301
|
+
source: "slack",
|
|
302
|
+
slackChannelId: channelId,
|
|
303
|
+
slackThreadTs: threadTs,
|
|
304
|
+
slackTriggerMessageTs: items.at(-1)!.ts,
|
|
305
|
+
slackUserId: originalRequesterId,
|
|
306
|
+
requestedByUserId,
|
|
307
|
+
dependsOn,
|
|
308
|
+
parentTaskId: mostRecentTask?.id,
|
|
309
|
+
// A human message in the thread: never answer it in the latest thread
|
|
310
|
+
// task's structured-output contract.
|
|
311
|
+
inheritParentOutputSchema: false,
|
|
312
|
+
contextKey: slackContextKey({ channelId, threadTs }),
|
|
313
|
+
},
|
|
314
|
+
inbound,
|
|
315
|
+
);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
if (!(error instanceof TaskCreationBlockedError)) throw error;
|
|
318
|
+
|
|
319
|
+
console.info(
|
|
320
|
+
"[Slack] pre.task.create blocked:",
|
|
321
|
+
error.extension.name,
|
|
322
|
+
scrubSecrets(error.reason),
|
|
323
|
+
);
|
|
324
|
+
if (app) {
|
|
325
|
+
await ackSlackMessage(app.client, channelId, items.at(-1)!.ts, "no_entry");
|
|
326
|
+
}
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const { task, unattached } = created;
|
|
311
330
|
|
|
312
331
|
if (app) await notifySlackFileFailures(app.client, channelId, threadTs, unattached);
|
|
313
332
|
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
* the underlying context becomes irrelevant — e.g. user cancels).
|
|
23
23
|
*
|
|
24
24
|
* Concurrency: single-process, single-event-loop. No cross-instance locking.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* The buffer is cleared BEFORE the callback fires, so re-enqueues during
|
|
26
|
+
* `onFlush` create a fresh buffer, and its flush can start while the earlier
|
|
27
|
+
* `onFlush` for the same key still runs. A caller that needs per-key order
|
|
28
|
+
* must serialize inside `onFlush`.
|
|
27
29
|
*/
|
|
28
30
|
|
|
29
31
|
export type BufferFlushReason = "timer" | "manual";
|
package/src/tasks/context-key.ts
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* Key schema:
|
|
15
15
|
* task:slack:{channelId}:{threadTs}
|
|
16
16
|
* task:agentmail:{threadId}
|
|
17
|
+
* task:chat-sdk:{adapter}:{encodeURIComponent(platformThreadId)}
|
|
18
|
+
* (Chat SDK thread ids carry `:`, so the
|
|
19
|
+
* part after the adapter is URI-encoded)
|
|
17
20
|
* task:trackers:github:{owner}:{repo}:{issue|pr}:{number}
|
|
18
21
|
* task:trackers:gitlab:{projectId}:{mr|issue}:{iid}
|
|
19
22
|
* task:trackers:azure-devops:{repositoryId}:pr:{pullRequestId}
|
|
@@ -39,13 +42,20 @@
|
|
|
39
42
|
|
|
40
43
|
const SEPARATOR = ":";
|
|
41
44
|
|
|
42
|
-
export type ContextKeyFamily =
|
|
45
|
+
export type ContextKeyFamily =
|
|
46
|
+
| "slack"
|
|
47
|
+
| "agentmail"
|
|
48
|
+
| "chat-sdk"
|
|
49
|
+
| "trackers"
|
|
50
|
+
| "schedule"
|
|
51
|
+
| "workflow";
|
|
43
52
|
|
|
44
53
|
export type TrackerProvider = "github" | "gitlab" | "azure-devops" | "linear" | "jira";
|
|
45
54
|
|
|
46
55
|
export type ParsedContextKey =
|
|
47
56
|
| { family: "slack"; parts: { channelId: string; threadTs: string } }
|
|
48
57
|
| { family: "agentmail"; parts: { threadId: string } }
|
|
58
|
+
| { family: "chat-sdk"; parts: { adapter: string; threadId: string } }
|
|
49
59
|
| {
|
|
50
60
|
family: "trackers";
|
|
51
61
|
subFamily: "github";
|
|
@@ -101,6 +111,42 @@ export function slackContextKey(input: { channelId: string; threadTs: string }):
|
|
|
101
111
|
return ["task", "slack", channelId, threadTs].join(SEPARATOR);
|
|
102
112
|
}
|
|
103
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Chat SDK thread ids are `<adapter>:<platform id>` and the platform id itself
|
|
116
|
+
* may contain `:` (Telegram `telegram:<chatId>:<topicId>`, Slack
|
|
117
|
+
* `slack:<channel>:<ts>`). The adapter stays a plain key part; the rest is
|
|
118
|
+
* URI-encoded so the key keeps a fixed part count. `parseContextKey` returns
|
|
119
|
+
* the original thread id in `parts.threadId`.
|
|
120
|
+
*/
|
|
121
|
+
export function chatSdkContextKey(threadId: string): string {
|
|
122
|
+
const raw = typeof threadId === "string" ? threadId : "";
|
|
123
|
+
const separatorIndex = raw.indexOf(SEPARATOR);
|
|
124
|
+
if (separatorIndex <= 0 || separatorIndex === raw.length - 1) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`context-key: chat-sdk thread id must be "<adapter>:<id>" (got ${JSON.stringify(threadId)})`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const adapter = assertSafePart(raw.slice(0, separatorIndex), "adapter");
|
|
130
|
+
const rest = encodeURIComponent(raw.slice(separatorIndex + 1));
|
|
131
|
+
return ["task", "chat-sdk", adapter, rest].join(SEPARATOR);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The Chat SDK thread a contextKey points at, or null when the key is missing,
|
|
136
|
+
* malformed, or of another family. Never throws.
|
|
137
|
+
*/
|
|
138
|
+
export function chatThreadOfContextKey(
|
|
139
|
+
key: string | null | undefined,
|
|
140
|
+
): { adapter: string; threadId: string } | null {
|
|
141
|
+
if (!key) return null;
|
|
142
|
+
try {
|
|
143
|
+
const parsed = parseContextKey(key);
|
|
144
|
+
return parsed.family === "chat-sdk" ? parsed.parts : null;
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
104
150
|
export function agentmailContextKey(input: { threadId: string }): string {
|
|
105
151
|
const threadId = assertSafePart(input.threadId, "threadId");
|
|
106
152
|
return ["task", "agentmail", threadId].join(SEPARATOR);
|
|
@@ -255,6 +301,19 @@ export function parseContextKey(key: string): ParsedContextKey {
|
|
|
255
301
|
}
|
|
256
302
|
return { family: "agentmail", parts: { threadId: parts[2] as string } };
|
|
257
303
|
}
|
|
304
|
+
case "chat-sdk": {
|
|
305
|
+
if (parts.length !== 4 || !parts[2] || !parts[3]) {
|
|
306
|
+
throw new Error(`context-key: malformed chat-sdk key: ${JSON.stringify(key)}`);
|
|
307
|
+
}
|
|
308
|
+
const adapter = parts[2];
|
|
309
|
+
let rest: string;
|
|
310
|
+
try {
|
|
311
|
+
rest = decodeURIComponent(parts[3]);
|
|
312
|
+
} catch {
|
|
313
|
+
throw new Error(`context-key: malformed chat-sdk key: ${JSON.stringify(key)}`);
|
|
314
|
+
}
|
|
315
|
+
return { family: "chat-sdk", parts: { adapter, threadId: `${adapter}:${rest}` } };
|
|
316
|
+
}
|
|
258
317
|
case "schedule": {
|
|
259
318
|
if (parts.length !== 3) {
|
|
260
319
|
throw new Error(`context-key: malformed schedule key: ${JSON.stringify(key)}`);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { AgentTask } from "../types";
|
|
2
|
+
|
|
3
|
+
/** Missing fields read as unset, so a bare `{ model }` is its own pin. */
|
|
4
|
+
export type TaskModelPinFields = {
|
|
5
|
+
[K in
|
|
6
|
+
| "model"
|
|
7
|
+
| "modelSource"
|
|
8
|
+
| "modelAlias"
|
|
9
|
+
| "modelTier"
|
|
10
|
+
| "resolvedModel"
|
|
11
|
+
| "claudeSessionId"]?: AgentTask[K] | null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The task's own `model` pin, or undefined when the task has none.
|
|
16
|
+
*
|
|
17
|
+
* `agent_tasks.model` is not always the creator's pin: the worker reports the
|
|
18
|
+
* model it actually ran on `PUT /api/tasks/{id}/session`, which overwrites the
|
|
19
|
+
* column. So the pin is read from the claim-time record instead:
|
|
20
|
+
* - `modelSource = "model"`: the task's own `model` won at claim. A `latest:`
|
|
21
|
+
* alias survives only in `modelAlias` (the session report replaced `model`
|
|
22
|
+
* with the concrete id), so the alias is the pin.
|
|
23
|
+
* - `modelSource = "fallback:cli-unsupported:model"`: the task's own
|
|
24
|
+
* `latest:` alias won, then the claiming CLI rejected what it resolved to.
|
|
25
|
+
* The alias in `modelAlias` is the pin, with or without a `modelTier`.
|
|
26
|
+
* - `modelSource = "fallback:cli-unsupported"` (a tier layer's alias fell
|
|
27
|
+
* back) is not a pin. Rows written before the `:model` variant existed are
|
|
28
|
+
* ambiguous; one with a `modelAlias` and no `modelTier` can only have come
|
|
29
|
+
* from a `model` alias, so its alias is the pin. With a `modelTier` it stays
|
|
30
|
+
* ambiguous and only the tier counts.
|
|
31
|
+
* - no claim record and no session: `model` is still the creator's value.
|
|
32
|
+
* Anything else (a tier layer won, or `model` is just the session report) is
|
|
33
|
+
* not a pin: re-running the row must resolve the model again, from the agent's
|
|
34
|
+
* current config, instead of replaying the model of the previous run.
|
|
35
|
+
*/
|
|
36
|
+
export function taskModelPin(task: TaskModelPinFields): string | undefined {
|
|
37
|
+
if (task.modelSource === "model") return task.modelAlias ?? task.model ?? undefined;
|
|
38
|
+
if (task.modelSource === "fallback:cli-unsupported:model" && task.modelAlias) {
|
|
39
|
+
return task.modelAlias;
|
|
40
|
+
}
|
|
41
|
+
if (task.modelSource === "fallback:cli-unsupported" && task.modelAlias && !task.modelTier) {
|
|
42
|
+
return task.modelAlias;
|
|
43
|
+
}
|
|
44
|
+
if (!task.modelSource && !task.resolvedModel && !task.claudeSessionId) {
|
|
45
|
+
return task.model ?? undefined;
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The model fields a re-run of the SAME task row (paused-task resume) passes to
|
|
52
|
+
* the spawn: the pin and the claim record that resolved it, or nothing, so the
|
|
53
|
+
* worker resolves the model from the agent's current config.
|
|
54
|
+
*/
|
|
55
|
+
export function resumedTaskModelSelection(task: TaskModelPinFields): {
|
|
56
|
+
model: string | undefined;
|
|
57
|
+
resolvedModel: string | undefined;
|
|
58
|
+
modelSource: string | undefined;
|
|
59
|
+
} {
|
|
60
|
+
const pin = taskModelPin(task);
|
|
61
|
+
if (!pin) return { model: undefined, resolvedModel: undefined, modelSource: undefined };
|
|
62
|
+
return {
|
|
63
|
+
model: pin,
|
|
64
|
+
resolvedModel: task.resolvedModel ?? undefined,
|
|
65
|
+
modelSource: task.modelSource ?? undefined,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
} from "../types";
|
|
33
33
|
import { isEnvFlagEnabled } from "../utils/env-flag";
|
|
34
34
|
import { taskAttachmentDisplayUrl } from "../utils/task-attachment-links";
|
|
35
|
+
import { taskModelPin } from "./model-pin";
|
|
35
36
|
import { createTaskWithSiblingAwareness } from "./sibling-awareness";
|
|
36
37
|
// Side-effect import: registers task lifecycle templates in the in-memory registry.
|
|
37
38
|
import "../tools/templates";
|
|
@@ -165,23 +166,8 @@ export function getNextResumeGeneration(parent: Pick<AgentTask, "tags">): number
|
|
|
165
166
|
* reboot retry) must carry: the parent's portable `modelTier`, plus its
|
|
166
167
|
* concrete `model` only when that `model` was a task-level pin.
|
|
167
168
|
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* column. So the pin is read from the claim-time record instead:
|
|
171
|
-
* - `modelSource = "model"`: the task's own `model` won at claim. A `latest:`
|
|
172
|
-
* alias survives only in `modelAlias` (the session report replaced `model`
|
|
173
|
-
* with the concrete id), so the alias is what travels.
|
|
174
|
-
* - `modelSource = "fallback:cli-unsupported:model"`: the task's own
|
|
175
|
-
* `latest:` alias won, then the claiming CLI rejected what it resolved to.
|
|
176
|
-
* The alias in `modelAlias` travels, with or without a `modelTier`.
|
|
177
|
-
* - `modelSource = "fallback:cli-unsupported"` (a tier layer's alias fell
|
|
178
|
-
* back) is not a pin. Rows written before the `:model` variant existed are
|
|
179
|
-
* ambiguous; one with a `modelAlias` and no `modelTier` can only have come
|
|
180
|
-
* from a `model` alias, so its alias travels. With a `modelTier` it stays
|
|
181
|
-
* ambiguous and only the tier travels.
|
|
182
|
-
* - no claim record and no session: `model` is still the creator's value.
|
|
183
|
-
* Anything else (a tier layer won, or `model` is just the session report) is
|
|
184
|
-
* not a pin and is left off, so the resume resolves on its claiming worker.
|
|
169
|
+
* The pin rules live in `taskModelPin` (`./model-pin`); anything that is not
|
|
170
|
+
* a pin is left off, so the resume resolves on its claiming worker.
|
|
185
171
|
*
|
|
186
172
|
* `resolvedModel`, `modelSource` and `modelAlias` themselves are NOT copied:
|
|
187
173
|
* claim time writes all three together for the task being claimed, and the
|
|
@@ -193,26 +179,22 @@ export function getNextResumeGeneration(parent: Pick<AgentTask, "tags">): number
|
|
|
193
179
|
export function inheritedModelSelection(
|
|
194
180
|
parent: Pick<
|
|
195
181
|
AgentTask,
|
|
196
|
-
|
|
182
|
+
| "model"
|
|
183
|
+
| "modelTier"
|
|
184
|
+
| "modelSource"
|
|
185
|
+
| "modelAlias"
|
|
186
|
+
| "resolvedModel"
|
|
187
|
+
| "claudeSessionId"
|
|
188
|
+
| "profile"
|
|
197
189
|
>,
|
|
198
|
-
): Pick<CreateTaskOptions, "model" | "modelTier"> {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
} else if (parent.modelSource === "fallback:cli-unsupported:model" && parent.modelAlias) {
|
|
203
|
-
model = parent.modelAlias;
|
|
204
|
-
} else if (
|
|
205
|
-
parent.modelSource === "fallback:cli-unsupported" &&
|
|
206
|
-
parent.modelAlias &&
|
|
207
|
-
!parent.modelTier
|
|
208
|
-
) {
|
|
209
|
-
model = parent.modelAlias;
|
|
210
|
-
} else if (!parent.modelSource && !parent.resolvedModel && !parent.claudeSessionId) {
|
|
211
|
-
model = parent.model;
|
|
212
|
-
}
|
|
190
|
+
): Pick<CreateTaskOptions, "model" | "modelTier" | "profile"> {
|
|
191
|
+
const model = taskModelPin(parent);
|
|
192
|
+
// The task's own profile travels like its tier; an agent-default profile
|
|
193
|
+
// (`resolvedProfile` only) is re-resolved by the child's claim.
|
|
213
194
|
return {
|
|
214
195
|
...(model ? { model } : {}),
|
|
215
196
|
...(parent.modelTier ? { modelTier: parent.modelTier } : {}),
|
|
197
|
+
...(parent.profile ? { profile: parent.profile } : {}),
|
|
216
198
|
};
|
|
217
199
|
}
|
|
218
200
|
|
|
@@ -667,6 +667,48 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
|
667
667
|
expect(resolveAcpTarget(config).env(config).OPENCODE_CONFIG_CONTENT).toBe(content);
|
|
668
668
|
});
|
|
669
669
|
|
|
670
|
+
test("OpenCode preset adds the helmcode block with an {env:} key reference, never the key", () => {
|
|
671
|
+
const sentinel = "sk-helmcode-acp-sentinel-0123456789";
|
|
672
|
+
const config = baseConfig({
|
|
673
|
+
model: "helmcode/glm5.3",
|
|
674
|
+
env: {
|
|
675
|
+
ACP_TARGET: "opencode",
|
|
676
|
+
HELMCODE_API_KEY: sentinel,
|
|
677
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
678
|
+
provider: { helmcode: { options: { timeout: 1000 } } },
|
|
679
|
+
}),
|
|
680
|
+
},
|
|
681
|
+
});
|
|
682
|
+
const env = resolveAcpTarget(config).env(config);
|
|
683
|
+
expect(env.HELMCODE_API_KEY).toBe(sentinel);
|
|
684
|
+
expect(env.OPENCODE_CONFIG_CONTENT).not.toContain(sentinel);
|
|
685
|
+
const helmcode = JSON.parse(env.OPENCODE_CONFIG_CONTENT!).provider.helmcode;
|
|
686
|
+
expect(helmcode).toMatchObject({
|
|
687
|
+
npm: "@ai-sdk/openai-compatible",
|
|
688
|
+
name: "Helmcode",
|
|
689
|
+
env: [],
|
|
690
|
+
options: {
|
|
691
|
+
baseURL: "https://api.helmcode.com/v1",
|
|
692
|
+
apiKey: "{env:HELMCODE_API_KEY}",
|
|
693
|
+
timeout: 1000,
|
|
694
|
+
},
|
|
695
|
+
});
|
|
696
|
+
expect(helmcode.models["glm5.3"]).toMatchObject({
|
|
697
|
+
tool_call: true,
|
|
698
|
+
limit: { context: 1048576, output: 32768 },
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
test("OpenCode preset adds no custom block for a nan model", () => {
|
|
703
|
+
const config = baseConfig({
|
|
704
|
+
model: "nan/glm5.3-flash",
|
|
705
|
+
env: { ACP_TARGET: "opencode", NAN_API_KEY: "example-test-key" },
|
|
706
|
+
});
|
|
707
|
+
const env = resolveAcpTarget(config).env(config);
|
|
708
|
+
expect(env.NAN_API_KEY).toBe("example-test-key");
|
|
709
|
+
expect(JSON.parse(env.OPENCODE_CONFIG_CONTENT!).provider?.helmcode).toBeUndefined();
|
|
710
|
+
});
|
|
711
|
+
|
|
670
712
|
test("OpenCode preset injects gateway even without a model fallback", () => {
|
|
671
713
|
const config = baseConfig({
|
|
672
714
|
model: "",
|
|
@@ -38,6 +38,27 @@ describe("isInboxAllowed", () => {
|
|
|
38
38
|
test("rejects empty inbox id", () => {
|
|
39
39
|
expect(isInboxAllowed("", "x.dev")).toBe(false);
|
|
40
40
|
});
|
|
41
|
+
|
|
42
|
+
test("allows exact full-address match", () => {
|
|
43
|
+
expect(isInboxAllowed("bot@x.dev", "bot@x.dev")).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("rejects another address on the same domain as a full-address entry", () => {
|
|
47
|
+
expect(isInboxAllowed("other@x.dev", "bot@x.dev")).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("full-address match is case-insensitive", () => {
|
|
51
|
+
expect(isInboxAllowed("Bot@X.Dev", "bot@x.dev")).toBe(true);
|
|
52
|
+
expect(isInboxAllowed("bot@x.dev", "BOT@X.DEV")).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("supports mixed address and domain entries", () => {
|
|
56
|
+
const filter = "bot@x.dev, y.xyz";
|
|
57
|
+
expect(isInboxAllowed("bot@x.dev", filter)).toBe(true);
|
|
58
|
+
expect(isInboxAllowed("anyone@y.xyz", filter)).toBe(true);
|
|
59
|
+
expect(isInboxAllowed("other@x.dev", filter)).toBe(false);
|
|
60
|
+
expect(isInboxAllowed("bot@evil.com", filter)).toBe(false);
|
|
61
|
+
});
|
|
41
62
|
});
|
|
42
63
|
|
|
43
64
|
describe("isSenderAllowed", () => {
|
|
@@ -94,4 +115,30 @@ describe("isSenderAllowed", () => {
|
|
|
94
115
|
test("rejects non-matching domain in 'Name <email>' format", () => {
|
|
95
116
|
expect(isSenderAllowed("Taras <t@evil.com>", "desplega.ai")).toBe(false);
|
|
96
117
|
});
|
|
118
|
+
|
|
119
|
+
test("allows exact full-address match", () => {
|
|
120
|
+
expect(isSenderAllowed("alice@a.com", "alice@a.com")).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("rejects another address on the same domain as a full-address entry", () => {
|
|
124
|
+
expect(isSenderAllowed("bob@a.com", "alice@a.com")).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("full-address match is case-insensitive", () => {
|
|
128
|
+
expect(isSenderAllowed("Alice@A.com", "alice@a.com")).toBe(true);
|
|
129
|
+
expect(isSenderAllowed("alice@a.com", "ALICE@A.COM")).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("matches a full address in 'Name <email>' format", () => {
|
|
133
|
+
expect(isSenderAllowed("Taras <t@gmail.com>", "t@gmail.com")).toBe(true);
|
|
134
|
+
expect(isSenderAllowed(["Someone <s@gmail.com>"], "t@gmail.com")).toBe(false);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("supports mixed address and domain entries", () => {
|
|
138
|
+
const filter = "t@gmail.com, desplega.ai";
|
|
139
|
+
expect(isSenderAllowed("t@gmail.com", filter)).toBe(true);
|
|
140
|
+
expect(isSenderAllowed("anyone@desplega.ai", filter)).toBe(true);
|
|
141
|
+
expect(isSenderAllowed("other@gmail.com", filter)).toBe(false);
|
|
142
|
+
expect(isSenderAllowed(["other@gmail.com", "Taras <t@gmail.com>"], filter)).toBe(true);
|
|
143
|
+
});
|
|
97
144
|
});
|
|
@@ -28,7 +28,6 @@ let sut: Sut;
|
|
|
28
28
|
let api: ApiClient;
|
|
29
29
|
let fixtureDir: string;
|
|
30
30
|
let fixturePath: string;
|
|
31
|
-
let pm2StubPath: string;
|
|
32
31
|
|
|
33
32
|
/** A `claude` that initializes, accepts the prompt, and then never answers. */
|
|
34
33
|
const hangingFixtureSource = `#!/usr/bin/env bun
|
|
@@ -87,12 +86,8 @@ describe("API drain with a real worker", () => {
|
|
|
87
86
|
beforeAll(async () => {
|
|
88
87
|
fixtureDir = await mkdtemp("/tmp/api-drain-worker-");
|
|
89
88
|
fixturePath = join(fixtureDir, "claude-fixture");
|
|
90
|
-
pm2StubPath = join(fixtureDir, "bin");
|
|
91
|
-
await Bun.$`mkdir -p ${pm2StubPath}`.quiet();
|
|
92
89
|
await Bun.write(fixturePath, hangingFixtureSource);
|
|
93
|
-
await Bun.write(join(pm2StubPath, "pm2"), "#!/bin/sh\nexit 0\n");
|
|
94
90
|
await Bun.$`chmod 755 ${fixturePath}`.quiet();
|
|
95
|
-
await Bun.$`chmod 755 ${join(pm2StubPath, "pm2")}`.quiet();
|
|
96
91
|
sut = await startSut(
|
|
97
92
|
false,
|
|
98
93
|
{},
|
|
@@ -138,7 +133,7 @@ describe("API drain with a real worker", () => {
|
|
|
138
133
|
cwd: repoRoot,
|
|
139
134
|
env: {
|
|
140
135
|
...minimalEnv(),
|
|
141
|
-
PATH:
|
|
136
|
+
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
142
137
|
HOME: home,
|
|
143
138
|
AGENT_SWARM_API_KEY: sut.apiKey,
|
|
144
139
|
API_KEY: sut.apiKey,
|
|
@@ -987,6 +987,41 @@ describe("custom app actions", () => {
|
|
|
987
987
|
);
|
|
988
988
|
});
|
|
989
989
|
|
|
990
|
+
test("app writes return quickjs compat warnings for wired scripts without rejecting", async () => {
|
|
991
|
+
const saved = await upsertScriptByName({
|
|
992
|
+
name: `app_compat_${crypto.randomUUID().replaceAll("-", "")}`,
|
|
993
|
+
scope: "agent",
|
|
994
|
+
scopeId: AGENT_ID,
|
|
995
|
+
source: "export default async () => Buffer.from('aGk=', 'base64').toString();",
|
|
996
|
+
description: "Apps compat warning fixture",
|
|
997
|
+
intent: "Exercise quickjs compat warnings on app writes",
|
|
998
|
+
signatureJson: JSON.stringify({ args: { type: "object" }, result: { type: "string" } }),
|
|
999
|
+
agentId: AGENT_ID,
|
|
1000
|
+
typeChecked: true,
|
|
1001
|
+
});
|
|
1002
|
+
const created = await request<{ app: { id: string }; warnings?: string[] }>("/api/apps", {
|
|
1003
|
+
method: "POST",
|
|
1004
|
+
body: JSON.stringify({
|
|
1005
|
+
name: "Compat",
|
|
1006
|
+
definition: {
|
|
1007
|
+
...baseDefinition,
|
|
1008
|
+
actions: { decode: { kind: "script", scriptId: saved.script.id } },
|
|
1009
|
+
},
|
|
1010
|
+
}),
|
|
1011
|
+
});
|
|
1012
|
+
expect(created.status).toBe(201);
|
|
1013
|
+
expect(created.body.warnings).toEqual([
|
|
1014
|
+
"actions.decode: quickjs compat (unsupportedGlobal, line 1): Buffer is not available under quickjs",
|
|
1015
|
+
]);
|
|
1016
|
+
|
|
1017
|
+
const cleared = await request<{ warnings?: string[] }>(`/api/apps/${created.body.app.id}`, {
|
|
1018
|
+
method: "PUT",
|
|
1019
|
+
body: JSON.stringify({ definition: baseDefinition }),
|
|
1020
|
+
});
|
|
1021
|
+
expect(cleared.status).toBe(200);
|
|
1022
|
+
expect(cleared.body.warnings).toBeUndefined();
|
|
1023
|
+
});
|
|
1024
|
+
|
|
990
1025
|
test("agent writers cannot wire another agent's script; operator wiring is grandfathered", async () => {
|
|
991
1026
|
const OTHER_AGENT_ID = crypto.randomUUID();
|
|
992
1027
|
const foreign = await upsertScriptByName({
|