@desplega.ai/agent-swarm 2.6.0 → 2.7.1
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 +2 -0
- package/dist/{acp-adapter-dgfakfpw.js → acp-adapter-8dn5tq56.js} +6 -6
- package/dist/{actions-fbqma8aa.js → actions-3r6gw7dy.js} +18 -18
- package/dist/{amp-adapter-en0jy6hs.js → amp-adapter-wjtq413p.js} +3 -3
- package/dist/{anthropic-messages-txs190dd.js → anthropic-messages-n4cby1rz.js} +4 -4
- package/dist/{app-k8a5cgpp.js → app-d53yhykk.js} +3 -3
- package/dist/{assistant-a16433gr.js → assistant-ksrawj3k.js} +20 -20
- package/dist/{boot-reembed-6c1sjfnr.js → boot-reembed-fxfw17m2.js} +11 -3
- package/dist/{boot-reembed-f4nn561n.js → boot-reembed-k5y5xbj0.js} +15 -8
- package/dist/{boot-scrub-sweep-d4w9gajf.js → boot-scrub-sweep-se41j9fd.js} +3 -3
- package/dist/{boot-seeds-9bmkspyw.js → boot-seeds-r3kwwv8b.js} +4 -4
- package/dist/{claude-adapter-nys1kjxa.js → claude-adapter-ahmyf231.js} +8 -8
- package/dist/{claude-managed-adapter-55207973.js → claude-managed-adapter-5knamegc.js} +3 -3
- package/dist/{claude-managed-setup-3cm35gey.js → claude-managed-setup-mdc7dy6b.js} +3 -3
- package/dist/{claude-sdk-session-nw5yd8cp.js → claude-sdk-session-n5wen9zk.js} +8729 -8600
- package/dist/{cli-683y0b3a.js → cli-0dqtv2jg.js} +2 -2
- package/dist/{cli-a34pr3w1.js → cli-0tww7dnz.js} +2 -2
- package/dist/{cli-w2656ka1.js → cli-0w4e4v58.js} +7 -7
- package/dist/{cli-5sckpqcx.js → cli-2sjm3t4r.js} +1 -1
- package/dist/{cli-gf2850q7.js → cli-3cywb44q.js} +18 -1
- package/dist/{cli-8wkb09q5.js → cli-3k9jej0c.js} +2 -2
- package/dist/{cli-3aqd4jaa.js → cli-3v2cyqb8.js} +3 -3
- package/dist/{cli-emhjcj2y.js → cli-5qt9vzmq.js} +89 -20
- package/dist/{cli-abkm71vr.js → cli-5rp1w4cr.js} +1 -1
- package/dist/{cli-gf95q3bm.js → cli-6vwjsetx.js} +4 -4
- package/dist/{cli-k21gx5ht.js → cli-6w2yrrc0.js} +10 -10
- package/dist/{cli-m70bajzr.js → cli-75tdydgv.js} +1 -1
- package/dist/{cli-5rj83bam.js → cli-8feswf2v.js} +47 -36
- package/dist/{cli-sxgtf5fw.js → cli-8wd3mbyj.js} +1 -1
- package/dist/{cli-ca6banwz.js → cli-9csfthbw.js} +10 -8
- package/dist/{cli-dqygeeh5.js → cli-b41p764a.js} +31 -3
- package/dist/{cli-m5a9m0ak.js → cli-c1t533hh.js} +3 -3
- package/dist/{cli-2sjhpsns.js → cli-c28jxpcv.js} +1 -1
- package/dist/{cli-bqztfyve.js → cli-cb50g9cd.js} +1 -1
- package/dist/{cli-ag2yrnt5.js → cli-d8gaphtr.js} +2 -2
- package/dist/{cli-9abdgn5t.js → cli-dgtfysne.js} +3 -3
- package/dist/{cli-nq677csy.js → cli-dscnhn18.js} +1 -1
- package/dist/{cli-3fwqy71j.js → cli-dv11pgpv.js} +39 -32
- package/dist/{cli-v49fkghp.js → cli-ekptgk2m.js} +6 -6
- package/dist/{cli-c2habvsf.js → cli-f3mzy662.js} +17 -17
- package/dist/{cli-zqne1qcj.js → cli-fk7k8s9x.js} +2 -2
- package/dist/{cli-1tem6ns9.js → cli-gt4h8cxw.js} +3 -2
- package/dist/{cli-vbhgkw9h.js → cli-h3e7bhvn.js} +3 -3
- package/dist/{cli-ffvsj2qw.js → cli-hkxqdmnb.js} +3 -3
- package/dist/{cli-a2rr0fmg.js → cli-hpkvgdad.js} +7 -4
- package/dist/{cli-art7c1zh.js → cli-hq2v4rr5.js} +37 -9
- package/dist/{cli-sqma6vw1.js → cli-k1zb7raw.js} +5 -5
- package/dist/{cli-4rvr7zfx.js → cli-k4awgvzm.js} +5 -0
- package/dist/{cli-3ndmpxxv.js → cli-k7d3hvya.js} +2 -2
- package/dist/{cli-3gfvmzht.js → cli-kbtdftbw.js} +74 -26
- package/dist/{cli-hfeb68z4.js → cli-kj69b9tw.js} +34 -6
- package/dist/{cli-az25fn5f.js → cli-kk9jy4nm.js} +2 -2
- package/dist/{cli-39aet655.js → cli-m52t4cta.js} +1 -1
- package/dist/{cli-cz37jqss.js → cli-mdadewqp.js} +5 -5
- package/dist/{cli-esakngh8.js → cli-nf6k60sn.js} +1 -1
- package/dist/{cli-j6rktc91.js → cli-nzdf09js.js} +1 -1
- package/dist/{cli-rr7zx19j.js → cli-prcyzecg.js} +12 -12
- package/dist/{cli-4hxrf0p4.js → cli-pzafyqtk.js} +393 -62
- package/dist/{cli-g8ka5j4j.js → cli-qvaa1gjp.js} +173 -52
- package/dist/{cli-d2dpf95n.js → cli-rg4b2g6j.js} +1 -1
- package/dist/{cli-kf4jree9.js → cli-rm66vqdz.js} +1 -1
- package/dist/{cli-4rf0f5vg.js → cli-s504c3w7.js} +5 -3
- package/dist/{cli-nn6vx2mq.js → cli-swkx9jm2.js} +7 -5
- package/dist/{cli-g20jjwt4.js → cli-thsaq4pd.js} +16 -16
- package/dist/{cli-aj8djyqt.js → cli-twjnyvs8.js} +2 -2
- package/dist/{cli-03gg9pd1.js → cli-typdpe8g.js} +4 -4
- package/dist/{cli-mtnj4fwa.js → cli-vg8pwmsd.js} +6 -6
- package/dist/{cli-gnsb1zxa.js → cli-vhpckzvp.js} +1 -1
- package/dist/{cli-7enjwya9.js → cli-vz78s5wm.js} +1 -1
- package/dist/{cli-dv97kdzv.js → cli-wdxgsdz5.js} +2 -2
- package/dist/{cli-7a6p4e65.js → cli-wtjg6je3.js} +1 -1
- package/dist/{cli-6y51ryva.js → cli-x3cngb1h.js} +44 -12
- package/dist/{cli-n7asmce6.js → cli-xbz6mcg4.js} +3 -3
- package/dist/{cli-24j1jeeb.js → cli-y4tdxsqb.js} +3 -3
- package/dist/{cli-mvjz5an3.js → cli-yqrsp3ny.js} +7 -7
- package/dist/cli.js +31 -21
- package/dist/{codex-adapter-d95q4qsn.js → codex-adapter-7wepzq15.js} +6 -6
- package/dist/{codex-hook-brpnycn5.js → codex-hook-pbdh4xhx.js} +2 -2
- package/dist/{codex-session-runner-gdwd8h0c.js → codex-session-runner-02sb49e4.js} +6 -6
- package/dist/{commands-jqmgk54b.js → commands-3rcspxct.js} +2 -2
- package/dist/{controller-z3jq589f.js → controller-8ar4avd6.js} +3 -3
- package/dist/{controllers-connect-r2za39ef.js → controllers-connect-ajvh9h0v.js} +19 -19
- package/dist/{cursor-adapter-4mr4jgkw.js → cursor-adapter-gd0sa7bh.js} +1 -1
- package/dist/{db-w36wwb5g.js → db-dv9j7ts5.js} +2 -2
- package/dist/{db-ppv2tze7.js → db-z26vgdvj.js} +3 -3
- package/dist/{dispatcher-pv5h77vf.js → dispatcher-8m0htjq8.js} +17 -17
- package/dist/{dsh-adapter-d4pdpb3r.js → dsh-adapter-y8gyk130.js} +1 -1
- package/dist/{e2b-fn3zacvt.js → e2b-74vg9b7e.js} +1 -1
- package/dist/{e2b-222hsajc.js → e2b-jyay8wzn.js} +1 -1
- package/dist/{easter-egg-3d-4sp4dvmc.js → easter-egg-3d-28f880xx.js} +1 -1
- package/dist/{execute-jev839y1.js → execute-9seb79vh.js} +1 -1
- package/dist/{external-channel-y6nkzhnn.js → external-channel-smz7jyth.js} +2 -2
- package/dist/{getMachineId-bsd-brn0xym3.js → getMachineId-bsd-whfre6gr.js} +3 -3
- package/dist/{getMachineId-darwin-t339sfxm.js → getMachineId-darwin-5zjynb19.js} +3 -3
- package/dist/{getMachineId-linux-5eq95d8b.js → getMachineId-linux-8mksrrsq.js} +3 -3
- package/dist/{getMachineId-unsupported-qavrtc7j.js → getMachineId-unsupported-fxtqsdt2.js} +3 -3
- package/dist/{getMachineId-win-q7fe1wx7.js → getMachineId-win-nzfmz857.js} +3 -3
- package/dist/{grok-adapter-t08b9ntm.js → grok-adapter-z0nnvtbn.js} +7 -7
- package/dist/handlers-pspryh6g.js +41 -0
- package/dist/{heartbeat-vn31xwdk.js → heartbeat-f928aqyp.js} +20 -20
- package/dist/{hook-cpjs8q51.js → hook-d7c605r4.js} +7 -7
- package/dist/{hook-6d0zbvvt.js → hook-q9hv5xf9.js} +5 -5
- package/dist/{http-9c6medda.js → http-q6j4k989.js} +1000 -251
- package/dist/{index-k0yt1tvq.js → index-5nb266jr.js} +17 -17
- package/dist/{index-ysd45kgc.js → index-8fxt5eah.js} +10 -10
- package/dist/{index-zgvqzjsw.js → index-cekzwhez.js} +5 -5
- package/dist/{index-38t35h0n.js → index-ch0c1xff.js} +17 -17
- package/dist/{index-pkma1yf8.js → index-ebnjhxh1.js} +1 -1
- package/dist/{index-yqgbfgaj.js → index-ed8dy8rn.js} +20 -20
- package/dist/{index-qhjf2htm.js → index-ejqdkkqx.js} +262 -96
- package/dist/{index-dr94zbnh.js → index-farm1zsn.js} +32661 -29443
- package/dist/{index-g6k9tctj.js → index-yn1yxg85.js} +1 -1
- package/dist/{keepalive-em0117bp.js → keepalive-zzc3hks1.js} +3 -3
- package/dist/lead-c0pjcaw4.js +79 -0
- package/dist/{maintenance-kbme3qy9.js → maintenance-kqsxzpzx.js} +1 -1
- package/dist/{oauth-refresh-sweep-xysj4yse.js → oauth-refresh-sweep-7qt0g55z.js} +8 -3
- package/dist/{onboard-p6q0vz97.js → onboard-k7x13fqg.js} +121 -8
- package/dist/{opencode-adapter-esv3k9yn.js → opencode-adapter-tqvrtter.js} +5 -5
- package/dist/{otel-impl-54qhqh1z.js → otel-impl-sqkf6k3b.js} +97 -97
- package/dist/{pi-mono-adapter-mymbwhj0.js → pi-mono-adapter-m2qnafxm.js} +89 -14
- package/dist/{pricing-refresh-yb75wv33.js → pricing-refresh-wkpwhgvs.js} +3 -3
- package/dist/{rbac-roles-dexhc9x8.js → rbac-roles-dpn0c0wj.js} +7 -4
- package/dist/{rbac-roles-1vp2mw4p.js → rbac-roles-wk7xd6a6.js} +2 -2
- package/dist/{render-v2-tjay5hhf.js → render-v2-ex2m4g2k.js} +3 -3
- package/dist/{resume-8ayf37g5.js → resume-725g9b0b.js} +7 -7
- package/dist/{runtime-hqe5cqcd.js → runtime-kajas15g.js} +1 -1
- package/dist/{session-access-fdhp987s.js → session-access-0j2ezjje.js} +8 -4
- package/dist/{session-source-backfill-qgtc86z1.js → session-source-backfill-62202awe.js} +2 -2
- package/dist/{setup-4rrmqcq3.js → setup-9sj11ax6.js} +1 -1
- package/dist/{virtual-modules-52km00d6.js → virtual-modules-c6fcq6zr.js} +2 -2
- package/dist/{work-objects-p28fgd70.js → work-objects-0y07495y.js} +20 -20
- package/dist/worker-d4q9sqbc.js +79 -0
- package/openapi.json +1536 -407
- package/package.json +7 -5
- package/src/be/automation-preflight.ts +2 -0
- package/src/be/connector-codes.ts +65 -22
- package/src/be/db/api-keys.ts +9 -0
- package/src/be/db/workflow-runs.ts +36 -5
- package/src/be/db.ts +80 -22
- package/src/be/memory/boot-reembed.ts +4 -1
- package/src/be/memory/constants.ts +6 -0
- package/src/be/memory/embedding-recovery.ts +48 -0
- package/src/be/memory/index-content.ts +5 -2
- package/src/be/memory/providers/openai-embedding.ts +65 -14
- package/src/be/memory/task-learning.ts +257 -0
- package/src/be/memory/types.ts +13 -2
- package/src/be/migrations/245_script_executor.sql +3 -0
- package/src/be/migrations/246_connector_code_kind.sql +11 -0
- package/src/be/oauth-refresh-sweep.ts +2 -1
- package/src/be/onboarding.ts +125 -15
- package/src/be/rbac-roles.ts +4 -1
- package/src/be/scripts/boot-reembed.ts +2 -0
- package/src/be/scripts/db.ts +14 -4
- package/src/be/scripts/embeddings.ts +4 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +9 -3
- package/src/be/seed/agent-fs-provision.ts +75 -14
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/swarm-config-guard.ts +3 -0
- package/src/cli.tsx +9 -0
- package/src/comb/config.ts +6 -1
- package/src/commands/onboard/agent-fs-version.ts +5 -0
- package/src/commands/onboard/compose-generator.ts +117 -4
- package/src/commands/onboard/env-generator.ts +9 -0
- package/src/commands/onboard/tei-image.ts +12 -0
- package/src/commands/onboard/types.ts +7 -0
- package/src/commands/onboard.tsx +11 -1
- package/src/commands/provider-credentials.ts +2 -1
- package/src/commands/runner.ts +14 -1
- package/src/heartbeat/heartbeat.ts +14 -1
- package/src/heartbeat/script-runner-probe.ts +47 -0
- package/src/http/agentfs-proxy.ts +369 -0
- package/src/http/all-routes.ts +1 -0
- package/src/http/api-keys.ts +24 -9
- package/src/http/codex-oauth-device.ts +8 -1
- package/src/http/fs.ts +64 -10
- package/src/http/idempotency-key.ts +1 -1
- package/src/http/inbox-state.ts +27 -1
- package/src/http/index.ts +7 -4
- package/src/http/memory.ts +7 -4
- package/src/http/onboarding.ts +139 -11
- package/src/http/pages-public.ts +38 -5
- package/src/http/scripts.ts +27 -0
- package/src/http/session-access.ts +24 -0
- package/src/http/sessions.ts +10 -6
- package/src/http/tasks.ts +85 -11
- package/src/http/telemetry-ui.ts +1 -1
- package/src/http/user-roles.ts +4 -1
- package/src/http/users.ts +272 -3
- package/src/http/utils.ts +22 -3
- package/src/http/workflows.ts +10 -0
- package/src/http/x.ts +5 -0
- package/src/prompts/base-prompt.ts +45 -10
- package/src/prompts/session-templates.ts +43 -5
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +6 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +99 -14
- package/src/rbac/legacy-policy.ts +1 -0
- package/src/rbac/permissions.ts +4 -0
- package/src/scheduler/scheduler.ts +2 -1
- package/src/scripts-runtime/eval-harness.ts +8 -1
- package/src/scripts-runtime/executors/native.ts +22 -16
- package/src/scripts-runtime/executors/quickjs-prelude.ts +103 -1
- package/src/scripts-runtime/executors/quickjs-runner.ts +2 -1
- package/src/scripts-runtime/executors/quickjs.ts +7 -0
- package/src/scripts-runtime/executors/registry.ts +32 -0
- package/src/scripts-runtime/executors/types.ts +7 -0
- package/src/scripts-runtime/host-validated-args.ts +133 -0
- package/src/scripts-runtime/loader.ts +30 -3
- package/src/scripts-runtime/swarm-sdk.ts +9 -2
- package/src/scripts-runtime/types/stdlib.d.ts +9 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +9 -1
- package/src/tests/agent-fs-provision-seeder.test.ts +261 -92
- package/src/tests/agentfs-proxy.test.ts +1106 -0
- package/src/tests/api-key-status-by-suffix.test.ts +242 -0
- package/src/tests/base-prompt.test.ts +139 -4
- package/src/tests/codex-adapter.test.ts +46 -8
- package/src/tests/codex-oauth-device.test.ts +12 -1
- package/src/tests/comb-config-guard.test.ts +20 -0
- package/src/tests/comb-links.test.ts +79 -1
- package/src/tests/comb-status.test.ts +44 -0
- package/src/tests/community-linear-delivery-loop.test.ts +2099 -0
- package/src/tests/credential-check.test.ts +4 -2
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/docs-index.test.ts +135 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/fetch-resolved-env.test.ts +16 -2
- package/src/tests/fixtures/onboard/baseline-states.ts +68 -0
- package/src/tests/fixtures/onboard/content.compose.yml.txt +190 -0
- package/src/tests/fixtures/onboard/content.env.txt +29 -0
- package/src/tests/fixtures/onboard/dev.compose.yml.txt +155 -0
- package/src/tests/fixtures/onboard/dev.env.txt +28 -0
- package/src/tests/fixtures/onboard/full-all.compose.yml.txt +582 -0
- package/src/tests/fixtures/onboard/full-all.env.txt +59 -0
- package/src/tests/fixtures/onboard/full.compose.yml.txt +435 -0
- package/src/tests/fixtures/onboard/full.env.txt +36 -0
- package/src/tests/fixtures/onboard/research.compose.yml.txt +155 -0
- package/src/tests/fixtures/onboard/research.env.txt +28 -0
- package/src/tests/fixtures/onboard/solo.compose.yml.txt +85 -0
- package/src/tests/fixtures/onboard/solo.env.txt +26 -0
- package/src/tests/heartbeat-checklist.test.ts +89 -0
- package/src/tests/heartbeat-script-runner-probe.test.ts +83 -0
- package/src/tests/http-log-scrubbing.test.ts +34 -1
- package/src/tests/http-task-write-ownership.test.ts +5 -1
- package/src/tests/invites-http.test.ts +464 -0
- package/src/tests/memory-embedding-input-cap.test.ts +122 -1
- package/src/tests/memory-embedding-recovery.test.ts +137 -0
- package/src/tests/oauth-refresh-sweep.test.ts +34 -1
- package/src/tests/onboard-compose.test.ts +162 -0
- package/src/tests/onboard-env.test.ts +24 -0
- package/src/tests/onboard-non-interactive.test.ts +29 -0
- package/src/tests/onboard-tei-image.test.ts +36 -0
- package/src/tests/onboarding.test.ts +451 -4
- package/src/tests/openai-embedding-provider.test.ts +105 -2
- package/src/tests/opencode-adapter.test.ts +2 -1
- package/src/tests/pages-frame-ancestors.test.ts +162 -0
- package/src/tests/pi-codemode.test.ts +2 -1
- package/src/tests/pi-mono-adapter.test.ts +54 -0
- package/src/tests/pi-mono-session-cost-on-abort.test.ts +270 -0
- package/src/tests/pi-native-mcp.test.ts +13 -1
- package/src/tests/pi-tool-exposure.test.ts +8 -8
- package/src/tests/preload-env.test.ts +4 -0
- package/src/tests/preload.ts +4 -0
- package/src/tests/probe-tool-schema-tokens.test.ts +144 -0
- package/src/tests/prompt-template-session.test.ts +20 -3
- package/src/tests/rbac-admission-e2e.test.ts +22 -6
- package/src/tests/rbac-admission.test.ts +342 -4
- package/src/tests/rbac-engine.test.ts +1 -0
- package/src/tests/rbac-roles.test.ts +9 -1
- package/src/tests/request-composition-derive.test.ts +329 -0
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/script-executor-conformance.test.ts +36 -1
- package/src/tests/script-executor-quickjs-pool.test.ts +50 -0
- package/src/tests/script-executor-quickjs.test.ts +140 -0
- package/src/tests/script-host-validated-args-native.test.ts +196 -0
- package/src/tests/script-per-script-executor.test.ts +415 -0
- package/src/tests/scripts-external-api.test.ts +45 -0
- package/src/tests/sdk-allowlist.test.ts +3 -2
- package/src/tests/self-improvement.test.ts +4 -4
- package/src/tests/send-task-requester-gate.test.ts +64 -3
- package/src/tests/sessions-move.test.ts +39 -1
- package/src/tests/store-progress-learning.test.ts +381 -0
- package/src/tests/ui-logs-parser.test.ts +180 -0
- package/src/tests/whoami-route.test.ts +41 -0
- package/src/tests/workflow-engine-v2.test.ts +116 -1
- package/src/tests/workflow-mcp-trigger-schema.test.ts +209 -0
- package/src/tests/workflow-run-finished-event.test.ts +263 -0
- package/src/tests/workflow-swarm-script.test.ts +34 -0
- package/src/tools/inject-learning.ts +1 -1
- package/src/tools/memory-edit.ts +1 -1
- package/src/tools/memory-search.ts +1 -1
- package/src/tools/script-common.ts +1 -0
- package/src/tools/script-run.ts +7 -0
- package/src/tools/script-upsert.ts +7 -0
- package/src/tools/store-progress.ts +71 -1
- package/src/tools/utils.ts +12 -1
- package/src/tools/workflows/trigger-workflow.ts +104 -10
- package/src/types.ts +12 -1
- package/src/utils/constants.ts +39 -0
- package/src/utils/credentials.ts +5 -2
- package/src/utils/task-attachment-links.ts +15 -3
- package/src/workflows/engine.ts +18 -16
- package/src/workflows/executors/swarm-script.ts +5 -0
- package/src/workflows/foreach-driver.ts +5 -11
- package/src/workflows/node-timeout.ts +30 -0
- package/templates/community/linear-delivery-loop/PLAYBOOK.md +323 -0
- package/templates/community/linear-delivery-loop/README.md +38 -0
- package/templates/community/linear-delivery-loop/config.example.json +31 -0
- package/templates/community/linear-delivery-loop/lead-prompt.md +34 -0
- package/templates/community/linear-delivery-loop/schedule.json +10 -0
- package/templates/community/linear-delivery-loop/scripts/linear-delivery-setup.ts +148 -0
- package/templates/community/linear-delivery-loop/scripts/linear-delivery-tick.ts +1781 -0
- package/templates/skills/swarm-docs/config.json +14 -0
- package/templates/skills/swarm-docs/content.md +144 -0
- package/dist/handlers-eqsnmv95.js +0 -41
- package/dist/lead-23e7z59t.js +0 -79
- package/dist/worker-e3w7vye1.js +0 -79
- package/dist/{azure-openai-responses-9kfwhmn7.js → azure-openai-responses-43asa23s.js} +0 -0
- package/dist/{node-vxx896fa.js → node-t28cc56b.js} +0 -0
- package/dist/{openai-codex-responses-79s8xnbh.js → openai-codex-responses-jhr3sjtm.js} +3 -3
- package/dist/{openai-completions-tdbyts0x.js → openai-completions-gs6yn37k.js} +3 -3
- /package/dist/{openai-responses-dm3t5vqp.js → openai-responses-jqm9vwwk.js} +0 -0
|
@@ -37,7 +37,7 @@ import type {
|
|
|
37
37
|
} from "./types";
|
|
38
38
|
|
|
39
39
|
// npm's `latest` is older and lacks the JSON/stdin contract used here.
|
|
40
|
-
export const DSH_PACKAGE = "@deepseek-ai/dsh@0.2.1-rc.
|
|
40
|
+
export const DSH_PACKAGE = "@deepseek-ai/dsh@0.2.1-rc.4";
|
|
41
41
|
|
|
42
42
|
export function checkDshCredentials(env: Record<string, string | undefined>): CredStatus {
|
|
43
43
|
return env.DEEPSEEK_API_KEY?.trim() || env.OPENROUTER_API_KEY?.trim()
|
|
@@ -382,14 +382,15 @@ type ToolStructuredContent = NonNullable<AgentToolResult["structuredContent"]>;
|
|
|
382
382
|
export const SWARM_TOOL_NAMESPACE = { name: "agent-swarm" } as const;
|
|
383
383
|
|
|
384
384
|
/**
|
|
385
|
-
* `PI_TOOL_DEFERRAL`: hide non-core swarm tools
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
385
|
+
* `PI_TOOL_DEFERRAL`: hide non-core swarm tools, and installed MCP server
|
|
386
|
+
* tools, behind pi's `tool_search`. On by default: the deferred schemas cost
|
|
387
|
+
* more on every request than the one partial cache miss a load causes.
|
|
388
|
+
* `false` declares every tool up front. Read from `process.env` by both the
|
|
389
|
+
* adapter traits (which pick the prompt's tool-discovery line) and
|
|
390
|
+
* `createSession`, so the prompt and the session always agree.
|
|
390
391
|
*/
|
|
391
392
|
export function isPiToolDeferralEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
392
|
-
return parseEnvFlag(env.PI_TOOL_DEFERRAL,
|
|
393
|
+
return parseEnvFlag(env.PI_TOOL_DEFERRAL, true);
|
|
393
394
|
}
|
|
394
395
|
|
|
395
396
|
/**
|
|
@@ -919,6 +920,28 @@ function requestContextTokens(message: unknown): number | undefined {
|
|
|
919
920
|
return usage.input + cacheRead + cacheWrite;
|
|
920
921
|
}
|
|
921
922
|
|
|
923
|
+
/**
|
|
924
|
+
* The session-log line for one LLM call's usage (token counts only, never
|
|
925
|
+
* content). The dashboard reads it as that call's cache-hit chip.
|
|
926
|
+
*/
|
|
927
|
+
function callUsageLine(message: unknown): string | undefined {
|
|
928
|
+
const usage = (message as { usage?: Record<string, unknown> } | null)?.usage;
|
|
929
|
+
if (typeof usage?.input !== "number") return undefined;
|
|
930
|
+
const count = (value: unknown) =>
|
|
931
|
+
typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
932
|
+
return JSON.stringify({
|
|
933
|
+
type: "call_usage",
|
|
934
|
+
harness: "pi",
|
|
935
|
+
usage: {
|
|
936
|
+
input: count(usage.input),
|
|
937
|
+
cacheRead: count(usage.cacheRead),
|
|
938
|
+
cacheWrite: count(usage.cacheWrite),
|
|
939
|
+
output: count(usage.output),
|
|
940
|
+
reasoning: count(usage.reasoning),
|
|
941
|
+
},
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
|
|
922
945
|
function describeAssistantTurn(message: unknown): AssistantTurnShape {
|
|
923
946
|
const msg = (message ?? {}) as {
|
|
924
947
|
content?: unknown;
|
|
@@ -1018,6 +1041,8 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1018
1041
|
private emptyTurnReprompted = false;
|
|
1019
1042
|
/** `abort()` was called: never prompt a session someone is trying to stop. */
|
|
1020
1043
|
private abortRequested = false;
|
|
1044
|
+
/** Pending `waitForIdle()` resolvers released when `agent_end` fires or `abort()` is called. */
|
|
1045
|
+
private idleResolvers = new Set<() => void>();
|
|
1021
1046
|
/** Removes this session's own models.json once the session ends. */
|
|
1022
1047
|
private disposeModels: () => Promise<void>;
|
|
1023
1048
|
/** Fed each assistant request's prompt size; steers the one-time context-bound note. */
|
|
@@ -1116,6 +1141,10 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1116
1141
|
if (endMsg.role === "assistant") {
|
|
1117
1142
|
const turn = describeAssistantTurn(event.message);
|
|
1118
1143
|
this.lastAssistantTurn = turn;
|
|
1144
|
+
// Ahead of the turn's text and tool lines: the chip rides on the
|
|
1145
|
+
// call's first row.
|
|
1146
|
+
const usageLine = callUsageLine(event.message);
|
|
1147
|
+
if (usageLine) this.emit({ type: "raw_log", content: usageLine });
|
|
1119
1148
|
if (endMsg.stopReason === "error") {
|
|
1120
1149
|
// Candidate terminal failure. May still be cleared by a successful
|
|
1121
1150
|
// retry (auto_retry_end success / a later good message_end).
|
|
@@ -1222,6 +1251,14 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1222
1251
|
case "tool_execution_end":
|
|
1223
1252
|
if (this.pendingTerminalStoreProgress.delete(event.toolCallId) && !event.isError) {
|
|
1224
1253
|
this.terminalStoreProgressDone = true;
|
|
1254
|
+
const snapshotCost = this.safeBuildCostData(false);
|
|
1255
|
+
if (snapshotCost) {
|
|
1256
|
+
this.emit({
|
|
1257
|
+
type: "result",
|
|
1258
|
+
cost: snapshotCost,
|
|
1259
|
+
isError: false,
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1225
1262
|
}
|
|
1226
1263
|
this.emit({
|
|
1227
1264
|
type: "raw_log",
|
|
@@ -1327,6 +1364,24 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1327
1364
|
};
|
|
1328
1365
|
} catch (err) {
|
|
1329
1366
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1367
|
+
if (this.abortRequested && this.terminalStoreProgressDone) {
|
|
1368
|
+
const cost = this.safeBuildCostData(false);
|
|
1369
|
+
if (cost) {
|
|
1370
|
+
this.emit({
|
|
1371
|
+
type: "result",
|
|
1372
|
+
cost,
|
|
1373
|
+
isError: false,
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
return {
|
|
1377
|
+
exitCode: 0,
|
|
1378
|
+
sessionId: this._sessionId,
|
|
1379
|
+
cost,
|
|
1380
|
+
output: this.lastAssistantText || undefined,
|
|
1381
|
+
isError: false,
|
|
1382
|
+
appliedReasoningEffort: this.appliedReasoningEffort,
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1330
1385
|
// Defense-in-depth: AWS SDK failures surface as structured events (handled
|
|
1331
1386
|
// above in runSession), not thrown exceptions, so this catch is for genuine
|
|
1332
1387
|
// unexpected throws (MCP / transport / etc). Still classify in case an AWS
|
|
@@ -1341,9 +1396,11 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1341
1396
|
}
|
|
1342
1397
|
this.emit({ type: "raw_stderr", content: `[pi-mono] Error: ${errorMessage}\n` });
|
|
1343
1398
|
|
|
1399
|
+
const cost = this.safeBuildCostData(true);
|
|
1344
1400
|
return {
|
|
1345
1401
|
exitCode: 1,
|
|
1346
1402
|
sessionId: this._sessionId,
|
|
1403
|
+
cost,
|
|
1347
1404
|
isError: true,
|
|
1348
1405
|
errorCategory: awsCatchError?.category,
|
|
1349
1406
|
failureReason: scrubSecrets(awsCatchError?.message ?? errorMessage),
|
|
@@ -1426,16 +1483,38 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1426
1483
|
return;
|
|
1427
1484
|
}
|
|
1428
1485
|
|
|
1429
|
-
|
|
1486
|
+
let settled = false;
|
|
1487
|
+
const finish = () => {
|
|
1488
|
+
if (settled) return;
|
|
1489
|
+
settled = true;
|
|
1490
|
+
unsub();
|
|
1491
|
+
this.idleResolvers.delete(finish);
|
|
1492
|
+
resolve();
|
|
1493
|
+
};
|
|
1494
|
+
|
|
1495
|
+
// Subscribe and wait for agent_end (or abort)
|
|
1430
1496
|
const unsub = this.agentSession.subscribe((event) => {
|
|
1431
1497
|
if (event.type === "agent_end") {
|
|
1432
|
-
|
|
1433
|
-
resolve();
|
|
1498
|
+
finish();
|
|
1434
1499
|
}
|
|
1435
1500
|
});
|
|
1501
|
+
this.idleResolvers.add(finish);
|
|
1502
|
+
if (this.abortRequested) {
|
|
1503
|
+
finish();
|
|
1504
|
+
}
|
|
1436
1505
|
});
|
|
1437
1506
|
}
|
|
1438
1507
|
|
|
1508
|
+
private safeBuildCostData(isError: boolean): CostData | undefined {
|
|
1509
|
+
try {
|
|
1510
|
+
const stats = this.agentSession.getSessionStats();
|
|
1511
|
+
if (!stats) return undefined;
|
|
1512
|
+
return { ...this.buildCostData(stats), isError };
|
|
1513
|
+
} catch {
|
|
1514
|
+
return undefined;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1439
1518
|
private buildCostData(stats: SessionStats): CostData {
|
|
1440
1519
|
return {
|
|
1441
1520
|
sessionId: "", // Runner overrides with runner session ID
|
|
@@ -1475,6 +1554,9 @@ export class PiMonoSession implements ProviderSession {
|
|
|
1475
1554
|
|
|
1476
1555
|
async abort(): Promise<void> {
|
|
1477
1556
|
this.abortRequested = true;
|
|
1557
|
+
for (const resolve of [...this.idleResolvers]) {
|
|
1558
|
+
resolve();
|
|
1559
|
+
}
|
|
1478
1560
|
await this.agentSession.abort();
|
|
1479
1561
|
}
|
|
1480
1562
|
|
|
@@ -1684,12 +1766,15 @@ function escapeValues(values: unknown): Record<string, string> {
|
|
|
1684
1766
|
/**
|
|
1685
1767
|
* Map installed servers (`fetchInstalledMcpServers(..., "claude")` entries)
|
|
1686
1768
|
* to pi MCP configs. pi speaks stdio and streamable HTTP; `sse` entries map to
|
|
1687
|
-
* HTTP, which is how the previous pi client already reached them.
|
|
1688
|
-
* `
|
|
1769
|
+
* HTTP, which is how the previous pi client already reached them. With
|
|
1770
|
+
* `deferred`, their tools load through `tool_search` like non-core swarm
|
|
1771
|
+
* tools; otherwise they are declared up front.
|
|
1689
1772
|
*/
|
|
1690
1773
|
export function toPiMcpServers(
|
|
1691
1774
|
installed: Record<string, Record<string, unknown>> | null,
|
|
1775
|
+
options: { deferred?: boolean } = {},
|
|
1692
1776
|
): Record<string, McpServerConfig> {
|
|
1777
|
+
const exposure = options.deferred ? "deferred" : "direct";
|
|
1693
1778
|
const servers: Record<string, McpServerConfig> = {};
|
|
1694
1779
|
for (const [name, entry] of Object.entries(installed ?? {})) {
|
|
1695
1780
|
if (typeof entry.command === "string") {
|
|
@@ -1698,14 +1783,14 @@ export function toPiMcpServers(
|
|
|
1698
1783
|
command: entry.command,
|
|
1699
1784
|
args: Array.isArray(entry.args) ? entry.args.map(String) : [],
|
|
1700
1785
|
env: escapeValues(entry.env),
|
|
1701
|
-
exposure
|
|
1786
|
+
exposure,
|
|
1702
1787
|
};
|
|
1703
1788
|
} else if (typeof entry.url === "string") {
|
|
1704
1789
|
servers[name] = {
|
|
1705
1790
|
type: "http",
|
|
1706
1791
|
url: entry.url,
|
|
1707
1792
|
headers: escapeValues(entry.headers),
|
|
1708
|
-
exposure
|
|
1793
|
+
exposure,
|
|
1709
1794
|
};
|
|
1710
1795
|
}
|
|
1711
1796
|
}
|
|
@@ -1860,7 +1945,7 @@ export class PiMonoAdapter implements ProviderAdapter {
|
|
|
1860
1945
|
config.apiUrl && config.apiKey && config.agentId
|
|
1861
1946
|
? await fetchInstalledMcpServers(config.apiUrl, config.apiKey, config.agentId, "claude")
|
|
1862
1947
|
: null;
|
|
1863
|
-
const piMcpServers = toPiMcpServers(installedMcpServers);
|
|
1948
|
+
const piMcpServers = toPiMcpServers(installedMcpServers, { deferred: deferTools });
|
|
1864
1949
|
if (Object.keys(piMcpServers).length > 0) {
|
|
1865
1950
|
console.log(
|
|
1866
1951
|
`\x1b[2m[${config.role}]\x1b[0m Registering ${Object.keys(piMcpServers).length} installed MCP server(s) with pi`,
|
|
@@ -340,6 +340,7 @@ export const LEGACY_POLICY = {
|
|
|
340
340
|
"mcp-oauth.authorize.any": anyAuthenticated,
|
|
341
341
|
"kv.write.any": leadOrOwnNamespace,
|
|
342
342
|
"comb.presence": operatorOrUser,
|
|
343
|
+
"fs.join.own": anyAuthenticated,
|
|
343
344
|
"page.delete.any": leadOrResourceOwner,
|
|
344
345
|
"app.manage": anyAuthenticated,
|
|
345
346
|
"app.use": anyAuthenticated,
|
package/src/rbac/permissions.ts
CHANGED
|
@@ -314,6 +314,10 @@ export const PERMISSIONS = {
|
|
|
314
314
|
description: "Use dashboard presence rooms for Comb drives.",
|
|
315
315
|
namespace: "comb",
|
|
316
316
|
},
|
|
317
|
+
"fs.join.own": {
|
|
318
|
+
description: "Join the swarm's shared agent-fs drive with your own account email.",
|
|
319
|
+
namespace: "fs",
|
|
320
|
+
},
|
|
317
321
|
"page.delete.any": {
|
|
318
322
|
description: "Delete a page the caller does not own.",
|
|
319
323
|
namespace: "page",
|
|
@@ -75,7 +75,7 @@ function resolveExecutorRegistry(): ExecutorRegistry | null {
|
|
|
75
75
|
* scripts-runtime — no agent/LLM in the loop. Reuses the same `runScriptWithRunCredential()`
|
|
76
76
|
* path as the `swarm-script` workflow executor.
|
|
77
77
|
*/
|
|
78
|
-
async function executeScheduleScript(schedule: ScheduledTask): Promise<void> {
|
|
78
|
+
export async function executeScheduleScript(schedule: ScheduledTask): Promise<void> {
|
|
79
79
|
if (!schedule.scriptName) {
|
|
80
80
|
throw new Error(`Schedule "${schedule.name}" has no scriptName (targetType=script)`);
|
|
81
81
|
}
|
|
@@ -106,6 +106,7 @@ async function executeScheduleScript(schedule: ScheduledTask): Promise<void> {
|
|
|
106
106
|
source: script.source,
|
|
107
107
|
args,
|
|
108
108
|
fsMode: "none",
|
|
109
|
+
executor: script.executor,
|
|
109
110
|
agentId,
|
|
110
111
|
egressSecrets: credentials.egressSecrets,
|
|
111
112
|
userConfig: credentials.userConfig,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildCtx } from "./ctx";
|
|
2
2
|
import { patchFetchWithEgressSubstitution } from "./egress-secrets";
|
|
3
3
|
import type { SwarmConfigPayload } from "./executors/types";
|
|
4
|
+
import { isHostValidationEquivalent } from "./host-validated-args";
|
|
4
5
|
import { ctxSignatureHintFor } from "./script-error-hints";
|
|
5
6
|
import { SwarmConfig } from "./swarm-config";
|
|
6
7
|
|
|
@@ -131,8 +132,14 @@ try {
|
|
|
131
132
|
);
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
const hostValidatedArgs = process.env.SWARM_SCRIPT_HOST_VALIDATED_ARGS === "1";
|
|
134
136
|
let validatedArgs = parsedArgs;
|
|
135
|
-
if (
|
|
137
|
+
if (
|
|
138
|
+
mod.argsSchema &&
|
|
139
|
+
typeof mod.argsSchema === "object" &&
|
|
140
|
+
"parse" in mod.argsSchema &&
|
|
141
|
+
!(hostValidatedArgs && isHostValidationEquivalent(mod.argsSchema, parsedArgs))
|
|
142
|
+
) {
|
|
136
143
|
try {
|
|
137
144
|
// biome-ignore lint/suspicious/noExplicitAny: argsSchema is a Zod schema at runtime
|
|
138
145
|
validatedArgs = (mod.argsSchema as any).parse(parsedArgs);
|
|
@@ -173,23 +173,21 @@ export class NativeScriptExecutor implements ScriptExecutor {
|
|
|
173
173
|
let removeAbortListener: (() => void) | undefined;
|
|
174
174
|
let proc: Bun.Subprocess<"pipe", "pipe", "pipe"> | undefined;
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
error: "killed",
|
|
186
|
-
};
|
|
187
|
-
}
|
|
176
|
+
const killedOutput = (): ExecutorOutput => ({
|
|
177
|
+
result: undefined,
|
|
178
|
+
stdout: "",
|
|
179
|
+
stderr: "",
|
|
180
|
+
truncated: { stdout: false, stderr: false },
|
|
181
|
+
durationMs: Date.now() - start,
|
|
182
|
+
exitCode: 1,
|
|
183
|
+
error: "killed",
|
|
184
|
+
});
|
|
188
185
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
await writeBareImportShims(tmpdir);
|
|
186
|
+
try {
|
|
187
|
+
if (killed) return killedOutput();
|
|
192
188
|
|
|
189
|
+
// Listen before the first await: an abort during the file writes below
|
|
190
|
+
// must stop the spawn, not land between the writes and the listener.
|
|
193
191
|
const onExternalAbort = () => {
|
|
194
192
|
killed = true;
|
|
195
193
|
if (proc) void terminateProcessGroup(proc.pid);
|
|
@@ -197,12 +195,19 @@ export class NativeScriptExecutor implements ScriptExecutor {
|
|
|
197
195
|
input.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
198
196
|
removeAbortListener = () => input.signal?.removeEventListener("abort", onExternalAbort);
|
|
199
197
|
|
|
198
|
+
await Bun.write(argsFile, JSON.stringify(input.args ?? null));
|
|
199
|
+
await Bun.write(sourceFile, input.source);
|
|
200
|
+
await writeBareImportShims(tmpdir);
|
|
201
|
+
|
|
202
|
+
// No await between this check and the spawn below.
|
|
203
|
+
if (killed) return killedOutput();
|
|
204
|
+
|
|
200
205
|
const timeout = setTimeout(() => {
|
|
201
206
|
timedOut = true;
|
|
202
207
|
if (proc) void terminateProcessGroup(proc.pid);
|
|
203
208
|
}, input.resources.wallClockMs);
|
|
204
209
|
|
|
205
|
-
const harnessEnv = {
|
|
210
|
+
const harnessEnv: Record<string, string> = {
|
|
206
211
|
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
207
212
|
HOME: process.env.HOME ?? "/tmp",
|
|
208
213
|
LANG: process.env.LANG ?? "C.UTF-8",
|
|
@@ -214,6 +219,7 @@ export class NativeScriptExecutor implements ScriptExecutor {
|
|
|
214
219
|
SWARM_SCRIPT_RESULT_FILE: resultFile,
|
|
215
220
|
SWARM_SCRIPT_ERROR_FILE: errorFile,
|
|
216
221
|
SWARM_SCRIPT_STARTED_FILE: startedFile,
|
|
222
|
+
...(input.hostValidatedArgs ? { SWARM_SCRIPT_HOST_VALIDATED_ARGS: "1" } : {}),
|
|
217
223
|
};
|
|
218
224
|
|
|
219
225
|
proc = registerProcessGroup(
|
|
@@ -308,14 +308,116 @@ define("__swarm_ctx", ctx);
|
|
|
308
308
|
* zod `argsSchema` check, the same contract as `eval-harness.ts`.
|
|
309
309
|
*/
|
|
310
310
|
export const SANDBOX_EPILOGUE = String.raw`(async () => {
|
|
311
|
+
const isStructuralSchemaNode = (schema) => {
|
|
312
|
+
if (!schema || typeof schema !== "object") return false;
|
|
313
|
+
const def = schema._zod && schema._zod.def;
|
|
314
|
+
if (!def || typeof def !== "object") return false;
|
|
315
|
+
if (def.coerce) return false;
|
|
316
|
+
if (Array.isArray(def.checks) && def.checks.length > 0) return false;
|
|
317
|
+
switch (def.type) {
|
|
318
|
+
case "string":
|
|
319
|
+
case "number":
|
|
320
|
+
return !def.format;
|
|
321
|
+
case "boolean":
|
|
322
|
+
case "literal":
|
|
323
|
+
case "enum":
|
|
324
|
+
return true;
|
|
325
|
+
case "optional":
|
|
326
|
+
case "nullable":
|
|
327
|
+
return isStructuralSchemaNode(def.innerType);
|
|
328
|
+
case "array":
|
|
329
|
+
return isStructuralSchemaNode(def.element);
|
|
330
|
+
case "object": {
|
|
331
|
+
const rawShape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
332
|
+
if (!rawShape || typeof rawShape !== "object") return false;
|
|
333
|
+
return Object.values(rawShape).every(isStructuralSchemaNode);
|
|
334
|
+
}
|
|
335
|
+
default:
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
const isHostValidationEquivalent = (schema, value) => {
|
|
340
|
+
if (!schema || typeof schema !== "object") return false;
|
|
341
|
+
const def = schema._zod && schema._zod.def;
|
|
342
|
+
if (!def || typeof def !== "object") return false;
|
|
343
|
+
if (def.coerce) return false;
|
|
344
|
+
if (Array.isArray(def.checks) && def.checks.length > 0) return false;
|
|
345
|
+
switch (def.type) {
|
|
346
|
+
case "string":
|
|
347
|
+
return typeof value === "string" && !def.format;
|
|
348
|
+
case "number":
|
|
349
|
+
return typeof value === "number" && Number.isFinite(value) && !def.format;
|
|
350
|
+
case "boolean":
|
|
351
|
+
return typeof value === "boolean";
|
|
352
|
+
case "literal": {
|
|
353
|
+
const rawValues = def.values;
|
|
354
|
+
const values = Array.isArray(rawValues)
|
|
355
|
+
? rawValues
|
|
356
|
+
: rawValues instanceof Set
|
|
357
|
+
? Array.from(rawValues)
|
|
358
|
+
: [];
|
|
359
|
+
return (
|
|
360
|
+
values.length > 0 &&
|
|
361
|
+
values.some((v) => v === value && typeof v !== "bigint" && typeof v !== "symbol")
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
case "enum": {
|
|
365
|
+
if (schema._zod && schema._zod.values instanceof Set) {
|
|
366
|
+
return schema._zod.values.has(value);
|
|
367
|
+
}
|
|
368
|
+
const entriesObj = def.entries && typeof def.entries === "object" ? def.entries : null;
|
|
369
|
+
if (!entriesObj) return false;
|
|
370
|
+
const entries = Object.values(entriesObj).filter(
|
|
371
|
+
(v) => !(typeof v === "string" && typeof entriesObj[v] === "number"),
|
|
372
|
+
);
|
|
373
|
+
return entries.length > 0 && entries.includes(value);
|
|
374
|
+
}
|
|
375
|
+
case "optional":
|
|
376
|
+
return value === undefined
|
|
377
|
+
? isStructuralSchemaNode(def.innerType)
|
|
378
|
+
: isHostValidationEquivalent(def.innerType, value);
|
|
379
|
+
case "nullable":
|
|
380
|
+
return value === null
|
|
381
|
+
? isStructuralSchemaNode(def.innerType)
|
|
382
|
+
: isHostValidationEquivalent(def.innerType, value);
|
|
383
|
+
case "array":
|
|
384
|
+
return (
|
|
385
|
+
Array.isArray(value) &&
|
|
386
|
+
isStructuralSchemaNode(def.element) &&
|
|
387
|
+
value.every((item) => isHostValidationEquivalent(def.element, item))
|
|
388
|
+
);
|
|
389
|
+
case "object": {
|
|
390
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
391
|
+
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
392
|
+
if (!shape || typeof shape !== "object") return false;
|
|
393
|
+
for (const key of Object.keys(value)) {
|
|
394
|
+
if (!Object.hasOwn(shape, key)) return false;
|
|
395
|
+
}
|
|
396
|
+
for (const [key, propSchema] of Object.entries(shape)) {
|
|
397
|
+
if (!Object.hasOwn(value, key) && key in value) return false;
|
|
398
|
+
const propValue = value[key];
|
|
399
|
+
if (!isHostValidationEquivalent(propSchema, propValue)) return false;
|
|
400
|
+
}
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
default:
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
};
|
|
311
407
|
const mod = globalThis.__swarm_module;
|
|
312
408
|
if (!mod || typeof mod.default !== "function") {
|
|
313
409
|
throw new Error(
|
|
314
410
|
"Swarm script must export a default function. Script must export default async function (args, ctx): args FIRST, ctx second.",
|
|
315
411
|
);
|
|
316
412
|
}
|
|
413
|
+
const hostValidatedArgs = globalThis.__swarm_host_validated_args === true;
|
|
317
414
|
let args = globalThis.__swarm_args;
|
|
318
|
-
if (
|
|
415
|
+
if (
|
|
416
|
+
mod.argsSchema &&
|
|
417
|
+
typeof mod.argsSchema === "object" &&
|
|
418
|
+
"parse" in mod.argsSchema &&
|
|
419
|
+
!(hostValidatedArgs && isHostValidationEquivalent(mod.argsSchema, args))
|
|
420
|
+
) {
|
|
319
421
|
try {
|
|
320
422
|
args = mod.argsSchema.parse(args);
|
|
321
423
|
} catch (error) {
|
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
export type QuickJSJob = {
|
|
30
30
|
source: string;
|
|
31
31
|
args: unknown;
|
|
32
|
+
hostValidatedArgs?: boolean;
|
|
32
33
|
configPayload: SwarmConfigPayload;
|
|
33
34
|
resources: ScriptResourcePolicy;
|
|
34
35
|
network: ExecutorInput["network"];
|
|
@@ -656,7 +657,7 @@ async function evaluateJob(
|
|
|
656
657
|
|
|
657
658
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
658
659
|
try {
|
|
659
|
-
const init = `globalThis.__swarm_shape = ${JSON.stringify(shape)};\nglobalThis.__swarm_args = ${JSON.stringify(args)};`;
|
|
660
|
+
const init = `globalThis.__swarm_shape = ${JSON.stringify(shape)};\nglobalThis.__swarm_args = ${JSON.stringify(args)};\nglobalThis.__swarm_host_validated_args = ${Boolean(job.hostValidatedArgs)};`;
|
|
660
661
|
const ok =
|
|
661
662
|
evaluate(init, "swarm-init.js") &&
|
|
662
663
|
evaluate(SANDBOX_WEB_SHIMS, "swarm-web-shims.js") &&
|
|
@@ -146,6 +146,12 @@ export class QuickJSScriptExecutor implements ScriptExecutor {
|
|
|
146
146
|
`quickjs worker failed to start: ${error instanceof Error ? error.message : String(error)}`,
|
|
147
147
|
);
|
|
148
148
|
}
|
|
149
|
+
// An abort while the worker booted fired before the listener below
|
|
150
|
+
// exists. From here to postMessage nothing awaits.
|
|
151
|
+
if (input.signal?.aborted) {
|
|
152
|
+
pool.release(slot);
|
|
153
|
+
return emptyOutput("killed");
|
|
154
|
+
}
|
|
149
155
|
|
|
150
156
|
const id = ++requestSeq;
|
|
151
157
|
const start = performance.now();
|
|
@@ -196,6 +202,7 @@ export class QuickJSScriptExecutor implements ScriptExecutor {
|
|
|
196
202
|
job: {
|
|
197
203
|
source: input.source,
|
|
198
204
|
args: input.args,
|
|
205
|
+
...(input.hostValidatedArgs ? { hostValidatedArgs: true } : {}),
|
|
199
206
|
configPayload: input.configPayload,
|
|
200
207
|
resources: input.resources,
|
|
201
208
|
network: input.network,
|
|
@@ -7,6 +7,27 @@ const EXECUTORS: Record<string, () => ScriptExecutor> = {
|
|
|
7
7
|
quickjs: () => new QuickJSScriptExecutor(),
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
export function getDeploymentScriptExecutorName(env: NodeJS.ProcessEnv = process.env): string {
|
|
11
|
+
return (env.SCRIPT_EXECUTOR ?? "native").trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Operator sandbox ceiling: when the deployment sets `SCRIPT_EXECUTOR=quickjs`,
|
|
16
|
+
* individual scripts or agent calls may not escalate to the less-restricted
|
|
17
|
+
* `native` executor. When the deployment runs `native` (the default), scripts
|
|
18
|
+
* may opt down into `quickjs`.
|
|
19
|
+
*/
|
|
20
|
+
export function isExecutorAllowedByDeployment(
|
|
21
|
+
requested: string | null | undefined,
|
|
22
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
23
|
+
): boolean {
|
|
24
|
+
if (!requested) return true;
|
|
25
|
+
if (getDeploymentScriptExecutorName(env) === "quickjs" && requested.trim() === "native") {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
export function getScriptExecutor(name = process.env.SCRIPT_EXECUTOR ?? "native"): ScriptExecutor {
|
|
11
32
|
const factory = EXECUTORS[name.trim()];
|
|
12
33
|
if (!factory) {
|
|
@@ -16,3 +37,14 @@ export function getScriptExecutor(name = process.env.SCRIPT_EXECUTOR ?? "native"
|
|
|
16
37
|
}
|
|
17
38
|
return factory();
|
|
18
39
|
}
|
|
40
|
+
|
|
41
|
+
export function resolveScriptExecutor(
|
|
42
|
+
requested?: string | null,
|
|
43
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
44
|
+
): ScriptExecutor {
|
|
45
|
+
if (!isExecutorAllowedByDeployment(requested, env)) {
|
|
46
|
+
throw new Error('Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"');
|
|
47
|
+
}
|
|
48
|
+
const effective = requested ?? env.SCRIPT_EXECUTOR ?? "native";
|
|
49
|
+
return getScriptExecutor(effective);
|
|
50
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { ScriptApiConnectionDescriptor, ScriptMcpConnectionDescriptor } fro
|
|
|
3
3
|
import type { FailedCredentialBinding, ResolvedCredentialBinding } from "../credential-broker";
|
|
4
4
|
|
|
5
5
|
export type ScriptFsMode = "none" | "workspace-rw";
|
|
6
|
+
export type ScriptExecutorName = "native" | "quickjs";
|
|
6
7
|
|
|
7
8
|
export type EgressSecretEntry = ResolvedCredentialBinding;
|
|
8
9
|
|
|
@@ -49,6 +50,12 @@ export type ScriptResourcePolicy = {
|
|
|
49
50
|
export type ExecutorInput = {
|
|
50
51
|
source: string;
|
|
51
52
|
args: unknown;
|
|
53
|
+
/**
|
|
54
|
+
* Trusted host-only flag indicating `args` already passed host JSON Schema
|
|
55
|
+
* validation for this run. Executors may skip `argsSchema.parse(args)` only
|
|
56
|
+
* when this flag is true AND the runtime `argsSchema` is purely structural.
|
|
57
|
+
*/
|
|
58
|
+
hostValidatedArgs?: boolean;
|
|
52
59
|
configPayload: SwarmConfigPayload;
|
|
53
60
|
resources: ScriptResourcePolicy;
|
|
54
61
|
fsMode: ScriptFsMode;
|