@desplega.ai/agent-swarm 2.5.4 → 2.7.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 +4 -2
- package/dist/{acp-adapter-ek38cwsv.js → acp-adapter-ma1js5n7.js} +9 -9
- package/dist/{actions-92mepq03.js → actions-1vhmtvg9.js} +21 -21
- package/dist/{amp-adapter-9gaxg015.js → amp-adapter-sxqqvmdk.js} +4 -4
- package/dist/{app-ctn8gsgx.js → app-mwx1d5a9.js} +3 -3
- package/dist/{assistant-zyr5kz47.js → assistant-yx1p6g82.js} +30 -26
- package/dist/{boot-reembed-w75maga2.js → boot-reembed-5h37a2c2.js} +1 -1
- package/dist/{boot-reembed-dwzfttdr.js → boot-reembed-7h78vmvv.js} +2 -1
- package/dist/{boot-scrub-sweep-e9kq43kf.js → boot-scrub-sweep-8mawd4gw.js} +4 -4
- package/dist/{boot-seeds-x28v3fhb.js → boot-seeds-ca84dhnn.js} +4 -4
- package/dist/{claude-adapter-f0afqnne.js → claude-adapter-wqt4hfkq.js} +9 -9
- package/dist/{claude-managed-adapter-x81a7r65.js → claude-managed-adapter-6fjqtr2z.js} +2 -2
- package/dist/{claude-managed-setup-bqzwjd9x.js → claude-managed-setup-rqv98sea.js} +10 -3
- package/dist/{claude-sdk-session-7b7whkaq.js → claude-sdk-session-f29f3b2x.js} +11 -11
- package/dist/{cli-sxgtf5fw.js → cli-07q03xm2.js} +1 -1
- package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
- package/dist/{cli-g9vd9ece.js → cli-1hhbzkbb.js} +14 -16
- package/dist/{cli-qqzmjxkf.js → cli-1m9x8dr5.js} +11 -6
- package/dist/{cli-jbnn4vxb.js → cli-2pvzmas1.js} +3 -3
- package/dist/{cli-x77gen2p.js → cli-2y7v133v.js} +7 -7
- package/dist/{cli-dew6x255.js → cli-39aet655.js} +2 -2
- package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
- package/dist/{cli-jb30dzvk.js → cli-48gxjmcz.js} +530 -190
- package/dist/{cli-pzatvw94.js → cli-54sj64fc.js} +2 -2
- package/dist/{cli-bvpgr9ny.js → cli-60sty27p.js} +5 -5
- package/dist/{cli-asq5ydm4.js → cli-6a9qfa8b.js} +411 -69
- package/dist/{cli-277c31dw.js → cli-6mgdba42.js} +225 -3
- package/dist/{cli-19202kew.js → cli-6srv653c.js} +5 -5
- package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
- package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
- package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
- package/dist/{cli-hh5we352.js → cli-86ehn4s5.js} +7 -7
- package/dist/{cli-9s05422w.js → cli-8mbc9za9.js} +1 -1
- package/dist/{cli-ff1tm9n9.js → cli-8wmj18cz.js} +1 -1
- package/dist/{cli-1r5ad7j5.js → cli-9gsm2rzp.js} +12 -12
- package/dist/{cli-mz9afxxf.js → cli-9pshx6rd.js} +17 -3
- package/dist/{cli-s682zgqz.js → cli-a6ds2epe.js} +1 -1
- package/dist/{cli-6a1xg1p7.js → cli-a89zdqz9.js} +2 -2
- package/dist/{cli-03vpq45j.js → cli-ay40dnj3.js} +2 -2
- package/dist/{cli-tsma7p8v.js → cli-aypd09nf.js} +2 -2
- package/dist/{cli-ethgy7ha.js → cli-b3yzyc57.js} +2 -2
- package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
- package/dist/{cli-mmhj8vd7.js → cli-c668vvcf.js} +11 -2
- package/dist/{cli-sbwsxvtd.js → cli-d20qvpr2.js} +2 -2
- package/dist/{cli-c952c7ac.js → cli-e1595bgx.js} +3 -3
- package/dist/{cli-621ce7kw.js → cli-f12mr20z.js} +3 -3
- package/dist/{cli-dqygeeh5.js → cli-f1e0ptjj.js} +10 -1
- package/dist/{cli-xzfq4at3.js → cli-f4dbh7a5.js} +16 -12
- package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
- package/dist/{cli-5bnsc0e1.js → cli-gsfk58nw.js} +5 -5
- package/dist/cli-gt4h8cxw.js +895 -0
- package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
- package/dist/{cli-25n3mv5d.js → cli-h5jeg46p.js} +6 -6
- package/dist/{cli-gn5af0x5.js → cli-he9gbdx0.js} +62 -12
- package/dist/{cli-gbfxp48k.js → cli-j0ppywdr.js} +42 -35
- package/dist/{cli-k4tjsdx9.js → cli-j3y0x2n4.js} +277 -199
- package/dist/{cli-7p4jxgtt.js → cli-j9bpmykh.js} +75 -27
- package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
- package/dist/{cli-wx2nj19m.js → cli-kv7sbc2c.js} +6 -6
- package/dist/{cli-abs8ndtr.js → cli-m30k9777.js} +26 -26
- package/dist/{cli-cz5nmdxt.js → cli-m5e802r7.js} +2 -2
- package/dist/{cli-0shx9j93.js → cli-pfk92eqz.js} +2 -2
- package/dist/{cli-xtrz6bzs.js → cli-ptfq202x.js} +5 -3
- package/dist/{cli-6n8axjv1.js → cli-qj442fws.js} +2 -2
- package/dist/{cli-c61mbdds.js → cli-rd5m70gj.js} +4 -4
- package/dist/{cli-eftzyh9y.js → cli-s09j9vp5.js} +2 -2
- package/dist/{cli-m4ecdxvz.js → cli-s0mgx214.js} +7 -7
- package/dist/{cli-wghjkr0e.js → cli-sgqm2582.js} +10 -7
- package/dist/{cli-2655k16q.js → cli-sjctjr48.js} +2 -2
- package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
- package/dist/{cli-x0f2v69c.js → cli-twctnkng.js} +12 -7
- package/dist/{cli-j6rktc91.js → cli-v6shg7na.js} +1 -1
- package/dist/{cli-gx4rm0qx.js → cli-vz78s5wm.js} +1 -1
- package/dist/{cli-gwhjmh8g.js → cli-wqr7cea4.js} +5 -5
- package/dist/{cli-e42vss7b.js → cli-x37r7qwf.js} +16 -8
- package/dist/{cli-4b2z6n0m.js → cli-yd2nreqw.js} +17 -8
- package/dist/{cli-64mh9mf3.js → cli-ymjpkxgn.js} +69 -17
- package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
- package/dist/{cli-9j129brq.js → cli-yxbsmx56.js} +6 -6
- package/dist/cli.js +22 -20
- package/dist/{codex-adapter-wch12q99.js → codex-adapter-zk59x2zh.js} +7 -7
- package/dist/{codex-hook-brpnycn5.js → codex-hook-xyjhvxwd.js} +1 -1
- package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
- package/dist/{codex-session-runner-41pfcr95.js → codex-session-runner-kh6s4j3n.js} +8 -8
- package/dist/{commands-9849dkj6.js → commands-68et1qv2.js} +2 -2
- package/dist/{controller-ja0sd95p.js → controller-fyrbnzg4.js} +4 -4
- package/dist/{controllers-connect-xp05dj6x.js → controllers-connect-nep9h2xv.js} +23 -23
- package/dist/{cursor-adapter-623qxqew.js → cursor-adapter-yss3pg7t.js} +2 -2
- package/dist/{db-w759qmx0.js → db-28gjyvxj.js} +4 -2
- package/dist/{db-47vj40dy.js → db-8ftwvzba.js} +3 -3
- package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
- package/dist/{dispatcher-7b8e4z2j.js → dispatcher-hayexmkr.js} +20 -20
- package/dist/{docker-s84hjs91.js → docker-fdzyewpz.js} +2 -2
- package/dist/{dsh-adapter-2ezw3xea.js → dsh-adapter-46wawff9.js} +2 -2
- package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
- package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
- package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-8d1e0h4m.js} +1 -1
- package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
- package/dist/{execute-0xpz8950.js → execute-cjrfxfnm.js} +1 -1
- package/dist/{external-channel-e2s028da.js → external-channel-xbmxcg09.js} +2 -2
- package/dist/{grok-adapter-ys7gaqee.js → grok-adapter-ag4wks2a.js} +10 -10
- package/dist/handlers-tzmevqb5.js +41 -0
- package/dist/{heartbeat-w3mntghj.js → heartbeat-psfvcgwp.js} +23 -23
- package/dist/{hook-g7kvv6x9.js → hook-8pz04697.js} +6 -6
- package/dist/{hook-3jjywnpb.js → hook-cyq4mryn.js} +8 -8
- package/dist/{http-tkp7d4kb.js → http-haj1nd6k.js} +921 -169
- package/dist/{index-q7m26kvs.js → index-jwt2bj6f.js} +265 -97
- package/dist/{index-3n8m9ea2.js → index-q52f47pe.js} +1 -1
- package/dist/{index-31ceyf42.js → index-syvhnvtw.js} +1 -1
- package/dist/index-y1ajx04a.js +43 -0
- package/dist/{index-1ef1myq2.js → index-z5h22pes.js} +20 -20
- package/dist/{index-xdaahthb.js → index-zyq8ct52.js} +20 -20
- package/dist/{keepalive-v4ta8wgg.js → keepalive-xdvsamvj.js} +4 -4
- package/dist/lead-hqg57kdp.js +79 -0
- package/dist/{maintenance-84n1ex21.js → maintenance-4y2xzh3a.js} +1 -1
- package/dist/{oauth-refresh-sweep-vjnnandw.js → oauth-refresh-sweep-jd4r7zbs.js} +9 -4
- package/dist/{onboard-sfmpe4np.js → onboard-18447q9q.js} +6 -6
- package/dist/{opencode-adapter-jmpst4q4.js → opencode-adapter-26b2frdf.js} +7 -7
- package/dist/{otel-impl-v6cc0zve.js → otel-impl-f9tgr8yw.js} +2 -2
- package/dist/{pi-mono-adapter-fk8fkcf6.js → pi-mono-adapter-qn6qbga1.js} +38 -17
- package/dist/{pricing-refresh-fsk1e1zc.js → pricing-refresh-dw2tgb53.js} +3 -3
- package/dist/{rbac-roles-prmkdnkw.js → rbac-roles-aygm2760.js} +2 -2
- package/dist/{rbac-roles-zxmxqa39.js → rbac-roles-s4nwj2m3.js} +1 -1
- package/dist/render-v2-yfvdfr0x.js +16 -0
- package/dist/{resume-frdtgfa0.js → resume-1bmvjbf3.js} +9 -9
- package/dist/{runtime-bt5pkpm1.js → runtime-f7tpzedy.js} +1 -1
- package/dist/{session-access-fpez4y5q.js → session-access-r5garej6.js} +4 -4
- package/dist/session-source-backfill-424wzv0r.js +110 -0
- package/dist/{setup-mq6m3m8q.js → setup-8tygvxkq.js} +1 -1
- package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-xsw323b3.js} +2 -2
- package/dist/{work-objects-kfahhjsq.js → work-objects-ggnghpgf.js} +23 -23
- package/dist/worker-sqjd1nqf.js +79 -0
- package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
- package/openapi.json +1324 -14
- package/package.json +5 -3
- package/src/assets/source-key.ts +95 -0
- package/src/be/automation-preflight.ts +2 -0
- package/src/be/db/api-keys.ts +89 -0
- package/src/be/db/session-labels.ts +28 -0
- package/src/be/db/session-moves.ts +5 -6
- package/src/be/db/session-tree.ts +153 -14
- package/src/be/db/tasks/read.ts +11 -0
- package/src/be/db/tasks/write.ts +6 -1
- package/src/be/db/workflow-runs.ts +219 -6
- package/src/be/db-retention.ts +61 -6
- package/src/be/db.ts +135 -132
- package/src/be/memory/providers/openai-embedding.ts +5 -1
- package/src/be/memory/task-learning.ts +155 -0
- package/src/be/migrations/244_api_key_validation.sql +4 -0
- package/src/be/migrations/245_script_executor.sql +3 -0
- package/src/be/oauth-refresh-sweep.ts +2 -1
- package/src/be/onboarding.ts +4 -0
- package/src/be/scripts/boot-reembed.ts +2 -0
- package/src/be/scripts/db.ts +14 -4
- package/src/be/scripts/embeddings.ts +2 -0
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -4
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/session-source-backfill.ts +163 -0
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/comb/review-batch.ts +28 -1
- package/src/comb/templates.ts +7 -2
- package/src/commands/claude-managed-setup.ts +7 -1
- package/src/commands/credential-refresh.ts +76 -1
- package/src/commands/credential-wait.ts +2 -2
- package/src/commands/onboard/compose-generator.ts +5 -3
- package/src/commands/provider-credentials.ts +212 -171
- package/src/commands/runner.ts +25 -4
- package/src/extensions/apply-task-create.ts +8 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +5 -0
- package/src/heartbeat/heartbeat.ts +14 -1
- package/src/heartbeat/script-runner-probe.ts +47 -0
- package/src/http/all-routes.ts +2 -0
- package/src/http/api-keys.ts +77 -9
- package/src/http/assets.ts +15 -0
- package/src/http/codex-oauth-accounts.ts +191 -0
- package/src/http/comb.ts +15 -2
- package/src/http/config.ts +1 -1
- package/src/http/core.ts +6 -0
- package/src/http/fleet-benchmark.ts +5 -2
- package/src/http/idempotency-key.ts +1 -1
- package/src/http/index.ts +14 -3
- package/src/http/integrations.ts +5 -1
- package/src/http/kv.ts +8 -3
- package/src/http/onboarding.ts +6 -1
- package/src/http/pages-public.ts +38 -5
- package/src/http/pool-keys.ts +354 -0
- package/src/http/scripts.ts +27 -0
- package/src/http/sessions.ts +37 -12
- package/src/http/stats.ts +1 -0
- package/src/http/status.ts +26 -12
- package/src/http/tasks.ts +3 -0
- package/src/http/used-by.ts +7 -2
- package/src/http/workflows.ts +88 -9
- package/src/http/x.ts +5 -0
- package/src/integrations/chat-sdk/inbound.ts +27 -0
- package/src/kv-reserved-namespaces.ts +19 -0
- package/src/prompts/base-prompt.ts +21 -1
- package/src/prompts/session-templates.ts +17 -3
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +5 -1
- package/src/providers/claude-managed-adapter.ts +16 -9
- package/src/providers/codex-adapter.ts +71 -11
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +41 -11
- package/src/scheduler/scheduler.ts +5 -3
- 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 +16 -3
- package/src/scripts-runtime/types/stdlib.d.ts +10 -2
- package/src/scripts-runtime/types/swarm-extension.d.ts +17 -8
- package/src/scripts-runtime/types/swarm-sdk.d.ts +10 -2
- package/src/slack/assistant.ts +7 -0
- package/src/slack/channel-labels.ts +74 -0
- package/src/slack/handlers.ts +8 -0
- package/src/slack/inbound-files.ts +5 -2
- package/src/slack/thread-buffer.ts +4 -0
- package/src/tasks/sibling-awareness.ts +12 -3
- package/src/telemetry-context.ts +5 -6
- package/src/telemetry-identity.ts +3 -3
- package/src/tests/api-key-status-by-suffix.test.ts +242 -0
- package/src/tests/api-keys-validation.test.ts +170 -0
- package/src/tests/base-prompt.test.ts +70 -2
- package/src/tests/claude-managed-adapter.test.ts +46 -0
- package/src/tests/claude-routes-e2e.test.ts +7 -2
- package/src/tests/codex-credential-pools.test.ts +120 -0
- package/src/tests/codex-gateway-route.test.ts +165 -0
- package/src/tests/codex-oauth-accounts.test.ts +357 -0
- package/src/tests/comb-review-batch.test.ts +63 -2
- package/src/tests/community-linear-delivery-loop.test.ts +2099 -0
- package/src/tests/config-pool-keys.test.ts +533 -0
- package/src/tests/credential-check.test.ts +294 -4
- package/src/tests/credential-refresh.test.ts +172 -1
- package/src/tests/db-retention.test.ts +9 -3
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +1 -3
- 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/extensions-pre-task.test.ts +53 -1
- package/src/tests/fetch-resolved-env.test.ts +16 -2
- package/src/tests/fixtures/extensions/record-task-create/hooks.ts +9 -0
- package/src/tests/fixtures/extensions/record-task-create/manifest.json +7 -0
- package/src/tests/fleet-benchmark.test.ts +8 -0
- package/src/tests/get-workflow-run-tool.test.ts +98 -0
- package/src/tests/heartbeat-checklist.test.ts +89 -0
- package/src/tests/heartbeat-script-runner-probe.test.ts +83 -0
- package/src/tests/integrations-http.test.ts +32 -2
- package/src/tests/internal-ai/complete-structured.test.ts +37 -1
- package/src/tests/internal-ai/credentials.test.ts +23 -0
- package/src/tests/kv-http.test.ts +32 -0
- package/src/tests/kv-tool.test.ts +25 -0
- package/src/tests/multi-runtime-registration.test.ts +12 -12
- package/src/tests/oauth-refresh-sweep.test.ts +34 -1
- package/src/tests/onboard-compose.test.ts +20 -0
- package/src/tests/onboarding.test.ts +108 -1
- package/src/tests/openai-embedding-credentials.test.ts +35 -0
- package/src/tests/opencode-adapter.test.ts +2 -1
- package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
- package/src/tests/org-website.test.ts +36 -0
- 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-native-mcp.test.ts +13 -1
- package/src/tests/pi-tool-exposure.test.ts +8 -8
- package/src/tests/probe-tool-schema-tokens.test.ts +144 -0
- package/src/tests/prompt-template-session.test.ts +4 -3
- package/src/tests/provider-key-probes.test.ts +181 -0
- package/src/tests/rbac-e2e-helpers.test.ts +88 -1
- package/src/tests/rbac-e2e-helpers.ts +36 -11
- package/src/tests/request-composition-derive.test.ts +329 -0
- package/src/tests/script-connections.test.ts +4 -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/script-runs-retention.test.ts +212 -0
- package/src/tests/scripts-external-api.test.ts +45 -0
- package/src/tests/sdk-allowlist.test.ts +42 -2
- package/src/tests/self-improvement.test.ts +4 -4
- package/src/tests/session-source-backfill.test.ts +429 -0
- package/src/tests/session-source-keys.test.ts +236 -0
- package/src/tests/session-source-labels.test.ts +419 -0
- package/src/tests/sessions-detail-batch.test.ts +2 -0
- package/src/tests/sessions-move.test.ts +131 -0
- package/src/tests/sessions-tree.test.ts +299 -2
- package/src/tests/slack-inbound-files.test.ts +103 -23
- package/src/tests/status.test.ts +101 -18
- package/src/tests/store-progress-learning.test.ts +288 -0
- package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
- package/src/tests/test-net.ts +31 -0
- package/src/tests/transcription.test.ts +8 -0
- package/src/tests/ui-logs-parser.test.ts +180 -0
- package/src/tests/used-by-route.test.ts +11 -0
- package/src/tests/workflow-cascade-cancel.test.ts +172 -0
- package/src/tests/workflow-engine-v2.test.ts +116 -1
- package/src/tests/workflow-http-v2.test.ts +131 -0
- 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-step-order.test.ts +92 -0
- package/src/tests/workflow-sub-workflow.test.ts +30 -0
- package/src/tests/workflow-swarm-script.test.ts +34 -0
- package/src/tools/get-tasks.ts +8 -0
- package/src/tools/kv/kv-read-auth.ts +4 -2
- 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 +67 -1
- package/src/tools/task-action.ts +1 -1
- package/src/tools/workflows/get-workflow-run.ts +14 -4
- package/src/tools/workflows/trigger-workflow.ts +104 -10
- package/src/types.ts +36 -1
- package/src/utils/company-profile.ts +51 -1
- package/src/utils/credentials.ts +10 -4
- package/src/utils/internal-ai/complete-structured.ts +5 -0
- package/src/utils/internal-ai/credentials.ts +4 -3
- package/src/utils/provider-key-probes.ts +328 -0
- package/src/utils/transcription.ts +4 -1
- package/src/workflows/engine.ts +18 -16
- package/src/workflows/executors/sub-workflow.ts +8 -1
- 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/ai-toolbox.manifest.json +2 -2
- 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/researching/content.md +2 -0
- package/templates/skills/swarm-docs/config.json +14 -0
- package/templates/skills/swarm-docs/content.md +144 -0
- package/templates/skills/swarm-scripts/SKILL.md +1 -0
- package/templates/skills/swarm-scripts/content.md +1 -0
- package/dist/cli-7421jzsw.js +0 -84
- package/dist/cli-e45e4m6b.js +0 -413
- package/dist/cli-zw88zjba.js +0 -307
- package/dist/handlers-wy1dr6ja.js +0 -41
- package/dist/index-nmm79qgr.js +0 -43
- package/dist/lead-sawnyqxk.js +0 -79
- package/dist/render-v2-pjwxvnkw.js +0 -12
- package/dist/worker-v5e5rxj3.js +0 -79
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unforgeable host-only capability symbol set on `RunScriptInput` strictly at
|
|
3
|
+
* the host boundary (`POST /api/x/script/{endpointId}`) after `validateJsonSchema`
|
|
4
|
+
* succeeds. Because `Symbol` keys cannot be produced by JSON deserialization,
|
|
5
|
+
* callers that forward request-shaped JSON fields into `RunScriptInput` can
|
|
6
|
+
* never opt out of `argsSchema` validation.
|
|
7
|
+
*/
|
|
8
|
+
export const HOST_VALIDATED_ARGS = Symbol("swarm.hostValidatedArgs");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Checks whether a runtime `argsSchema` (Zod v4 / `zod/mini` schema) and its
|
|
12
|
+
* candidate `value` are semantically equivalent to the host-side JSON Schema
|
|
13
|
+
* validation performed by `validateJsonSchema` in `src/http/x.ts`.
|
|
14
|
+
*
|
|
15
|
+
* Returns `true` only when `schema.parse(value)` is guaranteed to succeed and
|
|
16
|
+
* return a value deeply identical to `value` without running any defaults,
|
|
17
|
+
* coercions, transforms, refinements, or unknown-key stripping.
|
|
18
|
+
*/
|
|
19
|
+
export function isHostValidationEquivalent(schema: unknown, value: unknown): boolean {
|
|
20
|
+
if (!schema || typeof schema !== "object") return false;
|
|
21
|
+
const zodInternal = (schema as { _zod?: { def?: Record<string, unknown>; values?: unknown } })
|
|
22
|
+
._zod;
|
|
23
|
+
const def = zodInternal?.def;
|
|
24
|
+
if (!def || typeof def !== "object") return false;
|
|
25
|
+
|
|
26
|
+
if (def.coerce) return false;
|
|
27
|
+
if (Array.isArray(def.checks) && def.checks.length > 0) return false;
|
|
28
|
+
|
|
29
|
+
switch (def.type) {
|
|
30
|
+
case "string":
|
|
31
|
+
return typeof value === "string" && !def.format;
|
|
32
|
+
case "number":
|
|
33
|
+
return typeof value === "number" && Number.isFinite(value) && !def.format;
|
|
34
|
+
case "boolean":
|
|
35
|
+
return typeof value === "boolean";
|
|
36
|
+
case "literal": {
|
|
37
|
+
const rawValues = def.values;
|
|
38
|
+
const values = Array.isArray(rawValues)
|
|
39
|
+
? rawValues
|
|
40
|
+
: rawValues instanceof Set
|
|
41
|
+
? Array.from(rawValues)
|
|
42
|
+
: [];
|
|
43
|
+
return (
|
|
44
|
+
values.length > 0 &&
|
|
45
|
+
values.some((v) => v === value && typeof v !== "bigint" && typeof v !== "symbol")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
case "enum": {
|
|
49
|
+
if (zodInternal?.values instanceof Set) {
|
|
50
|
+
return zodInternal.values.has(value);
|
|
51
|
+
}
|
|
52
|
+
const entriesObj =
|
|
53
|
+
def.entries && typeof def.entries === "object"
|
|
54
|
+
? (def.entries as Record<string, unknown>)
|
|
55
|
+
: null;
|
|
56
|
+
if (!entriesObj) return false;
|
|
57
|
+
const entries = Object.values(entriesObj).filter(
|
|
58
|
+
(v) => !(typeof v === "string" && typeof entriesObj[v] === "number"),
|
|
59
|
+
);
|
|
60
|
+
return entries.length > 0 && entries.includes(value);
|
|
61
|
+
}
|
|
62
|
+
case "optional":
|
|
63
|
+
return value === undefined
|
|
64
|
+
? isStructuralSchemaNode(def.innerType)
|
|
65
|
+
: isHostValidationEquivalent(def.innerType, value);
|
|
66
|
+
case "nullable":
|
|
67
|
+
return value === null
|
|
68
|
+
? isStructuralSchemaNode(def.innerType)
|
|
69
|
+
: isHostValidationEquivalent(def.innerType, value);
|
|
70
|
+
case "array":
|
|
71
|
+
return (
|
|
72
|
+
Array.isArray(value) &&
|
|
73
|
+
isStructuralSchemaNode(def.element) &&
|
|
74
|
+
value.every((item) => isHostValidationEquivalent(def.element, item))
|
|
75
|
+
);
|
|
76
|
+
case "object": {
|
|
77
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
78
|
+
const rawShape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
79
|
+
if (!rawShape || typeof rawShape !== "object") return false;
|
|
80
|
+
const shape = rawShape as Record<string, unknown>;
|
|
81
|
+
const obj = value as Record<string, unknown>;
|
|
82
|
+
|
|
83
|
+
// If `value` carries extra keys not declared in `shape`, let `.parse()`
|
|
84
|
+
// handle key stripping (`z.object`), passthrough (`z.looseObject`), or
|
|
85
|
+
// rejection (`z.strictObject`).
|
|
86
|
+
for (const key of Object.keys(obj)) {
|
|
87
|
+
if (!Object.hasOwn(shape, key)) return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const [key, propSchema] of Object.entries(shape)) {
|
|
91
|
+
// Retain Zod's property lookup semantics: if `key` is absent as an own
|
|
92
|
+
// property on `obj` but resolves via `Object.prototype` (e.g. `constructor`,
|
|
93
|
+
// `toString`), fall back to `.parse()` so Zod validates/rejects the
|
|
94
|
+
// inherited prototype value identically to `main`.
|
|
95
|
+
if (!Object.hasOwn(obj, key) && key in obj) return false;
|
|
96
|
+
const propValue = obj[key];
|
|
97
|
+
if (!isHostValidationEquivalent(propSchema, propValue)) return false;
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isStructuralSchemaNode(schema: unknown): boolean {
|
|
107
|
+
if (!schema || typeof schema !== "object") return false;
|
|
108
|
+
const def = (schema as { _zod?: { def?: Record<string, unknown> } })._zod?.def;
|
|
109
|
+
if (!def || typeof def !== "object") return false;
|
|
110
|
+
if (def.coerce) return false;
|
|
111
|
+
if (Array.isArray(def.checks) && def.checks.length > 0) return false;
|
|
112
|
+
switch (def.type) {
|
|
113
|
+
case "string":
|
|
114
|
+
case "number":
|
|
115
|
+
return !def.format;
|
|
116
|
+
case "boolean":
|
|
117
|
+
case "literal":
|
|
118
|
+
case "enum":
|
|
119
|
+
return true;
|
|
120
|
+
case "optional":
|
|
121
|
+
case "nullable":
|
|
122
|
+
return isStructuralSchemaNode(def.innerType);
|
|
123
|
+
case "array":
|
|
124
|
+
return isStructuralSchemaNode(def.element);
|
|
125
|
+
case "object": {
|
|
126
|
+
const rawShape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
127
|
+
if (!rawShape || typeof rawShape !== "object") return false;
|
|
128
|
+
return Object.values(rawShape as Record<string, unknown>).every(isStructuralSchemaNode);
|
|
129
|
+
}
|
|
130
|
+
default:
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -6,16 +6,18 @@ import { createValueScrubber, scrubObject, scrubSecrets } from "../utils/secret-
|
|
|
6
6
|
import type { ScriptApiConnectionDescriptor, ScriptMcpConnectionDescriptor } from "./api-types";
|
|
7
7
|
import type { FailedCredentialBinding } from "./credential-broker";
|
|
8
8
|
import { buildEgressSecrets } from "./egress-secrets";
|
|
9
|
-
import {
|
|
9
|
+
import { isExecutorAllowedByDeployment, resolveScriptExecutor } from "./executors/registry";
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_SCRIPT_RESOURCES,
|
|
12
12
|
type EgressSecretEntry,
|
|
13
13
|
type ExecutorOutput,
|
|
14
14
|
type ScriptAgentFsDescriptor,
|
|
15
|
+
type ScriptExecutorName,
|
|
15
16
|
type ScriptFsMode,
|
|
16
17
|
type ScriptResourcePolicy,
|
|
17
18
|
type SwarmConfigPayload,
|
|
18
19
|
} from "./executors/types";
|
|
20
|
+
import { HOST_VALIDATED_ARGS } from "./host-validated-args";
|
|
19
21
|
import { validateScriptImports } from "./import-allowlist";
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -38,7 +40,19 @@ const CAPACITY_EXCEEDED_RETRY_DELAYS_MS = [200, 750];
|
|
|
38
40
|
export type RunScriptInput = {
|
|
39
41
|
source: string;
|
|
40
42
|
args?: unknown;
|
|
43
|
+
/**
|
|
44
|
+
* Unforgeable host-only capability symbol set only when the host has already
|
|
45
|
+
* validated `args` against the script's `argsJsonSchema` (e.g. `POST /api/x/script/{endpointId}`).
|
|
46
|
+
* Keyed by a `Symbol` so request-shaped JSON inputs forwarded into `RunScriptInput`
|
|
47
|
+
* can never opt out of `argsSchema` validation.
|
|
48
|
+
*/
|
|
49
|
+
[HOST_VALIDATED_ARGS]?: boolean;
|
|
41
50
|
fsMode?: ScriptFsMode;
|
|
51
|
+
/**
|
|
52
|
+
* Optional per-script executor override ("native" | "quickjs"). When null or
|
|
53
|
+
* undefined, `getScriptExecutor` falls back to `SCRIPT_EXECUTOR ?? "native"`.
|
|
54
|
+
*/
|
|
55
|
+
executor?: ScriptExecutorName | null;
|
|
42
56
|
agentId: string;
|
|
43
57
|
/**
|
|
44
58
|
* Bearer for the run's `ctx.swarm` SDK calls. Api-side callers pass a
|
|
@@ -118,6 +132,18 @@ export async function runScript(input: RunScriptInput): Promise<RunScriptOutput>
|
|
|
118
132
|
};
|
|
119
133
|
}
|
|
120
134
|
|
|
135
|
+
if (!isExecutorAllowedByDeployment(input.executor)) {
|
|
136
|
+
return {
|
|
137
|
+
result: undefined,
|
|
138
|
+
stdout: "",
|
|
139
|
+
stderr: 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"',
|
|
140
|
+
truncated: { stdout: false, stderr: false },
|
|
141
|
+
durationMs: 0,
|
|
142
|
+
exitCode: 1,
|
|
143
|
+
error: "executor_error",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
121
147
|
// The global scrubber skips values under its length floor, so this run's own
|
|
122
148
|
// secret config is redacted here at any length before the global pass. Built
|
|
123
149
|
// before the import check: its diagnostic quotes source, which can hold a value.
|
|
@@ -150,6 +176,7 @@ export async function runScript(input: RunScriptInput): Promise<RunScriptOutput>
|
|
|
150
176
|
const executorInput = {
|
|
151
177
|
source: input.source,
|
|
152
178
|
args: input.args ?? null,
|
|
179
|
+
...(input[HOST_VALIDATED_ARGS] === true ? { hostValidatedArgs: true } : {}),
|
|
153
180
|
configPayload,
|
|
154
181
|
resources,
|
|
155
182
|
fsMode: input.fsMode ?? "none",
|
|
@@ -157,11 +184,11 @@ export async function runScript(input: RunScriptInput): Promise<RunScriptOutput>
|
|
|
157
184
|
signal: input.signal,
|
|
158
185
|
};
|
|
159
186
|
|
|
160
|
-
let output = await
|
|
187
|
+
let output = await resolveScriptExecutor(input.executor).run(executorInput);
|
|
161
188
|
for (const delayMs of CAPACITY_EXCEEDED_RETRY_DELAYS_MS) {
|
|
162
189
|
if (output.error !== "capacity_exceeded" || input.signal?.aborted) break;
|
|
163
190
|
await Bun.sleep(delayMs);
|
|
164
|
-
output = await
|
|
191
|
+
output = await resolveScriptExecutor(input.executor).run(executorInput);
|
|
165
192
|
}
|
|
166
193
|
|
|
167
194
|
return {
|
|
@@ -8,6 +8,7 @@ type BridgeRequest = {
|
|
|
8
8
|
method: string;
|
|
9
9
|
path: string;
|
|
10
10
|
body?: unknown;
|
|
11
|
+
headers?: Record<string, string>;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
function headers(config: SwarmConfig): Record<string, string> {
|
|
@@ -319,7 +320,13 @@ function bridgeRequestFor(name: string, args: unknown): BridgeRequest | null {
|
|
|
319
320
|
case "workflow_getRun": {
|
|
320
321
|
const id = typeof body.id === "string" ? body.id : undefined;
|
|
321
322
|
if (!id) throw new Error("workflow_getRun requires string `id`");
|
|
322
|
-
|
|
323
|
+
if (body.fields !== undefined && body.fields !== "full" && body.fields !== "slim") {
|
|
324
|
+
throw new Error('workflow_getRun `fields` must be "full" or "slim"');
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
method: "GET",
|
|
328
|
+
path: appendQuery(`/api/workflow-runs/${encodeURIComponent(id)}`, { fields: body.fields }),
|
|
329
|
+
};
|
|
323
330
|
}
|
|
324
331
|
case "workflow_delete": {
|
|
325
332
|
const id = typeof body.id === "string" ? body.id : undefined;
|
|
@@ -356,10 +363,16 @@ function bridgeRequestFor(name: string, args: unknown): BridgeRequest | null {
|
|
|
356
363
|
case "workflow_trigger": {
|
|
357
364
|
const id = typeof body.id === "string" ? body.id : undefined;
|
|
358
365
|
if (!id) throw new Error("workflow_trigger requires string `id`");
|
|
366
|
+
const path = `/api/workflows/${encodeURIComponent(id)}/trigger`;
|
|
359
367
|
return {
|
|
360
368
|
method: "POST",
|
|
361
|
-
path:
|
|
369
|
+
path: body.wait === false ? `${path}?wait=false` : path,
|
|
362
370
|
body: body.triggerData ?? {},
|
|
371
|
+
// The route's own Idempotency-Key: recorded in the run's transaction,
|
|
372
|
+
// so a retry after a kill replays the run instead of starting another.
|
|
373
|
+
...(typeof body.idempotencyKey === "string"
|
|
374
|
+
? { headers: { "Idempotency-Key": body.idempotencyKey } }
|
|
375
|
+
: {}),
|
|
363
376
|
};
|
|
364
377
|
}
|
|
365
378
|
case "workflow_retryRun": {
|
|
@@ -485,7 +498,7 @@ async function callBridgeApi(
|
|
|
485
498
|
|
|
486
499
|
const res = await fetch(`${baseUrl}${request.path}`, {
|
|
487
500
|
method: request.method,
|
|
488
|
-
headers: headers(config),
|
|
501
|
+
headers: { ...headers(config), ...request.headers },
|
|
489
502
|
body: request.body === undefined ? undefined : JSON.stringify(request.body),
|
|
490
503
|
});
|
|
491
504
|
const data = await readScriptSdkJsonResponse(res, `ctx.swarm.${name}`);
|
|
@@ -26,6 +26,7 @@ declare module "swarm-sdk" {
|
|
|
26
26
|
| { [key: string]: JsonValue };
|
|
27
27
|
export type ScriptScope = "agent" | "global";
|
|
28
28
|
export type ScriptFsMode = "none" | "workspace-rw";
|
|
29
|
+
export type ScriptExecutorName = "native" | "quickjs";
|
|
29
30
|
export type ScriptApiRawOptions = { raw: true };
|
|
30
31
|
export type ScriptApiDefaultOptions = { raw?: false };
|
|
31
32
|
export type RoutingReason =
|
|
@@ -304,6 +305,7 @@ declare module "swarm-sdk" {
|
|
|
304
305
|
intent?: string;
|
|
305
306
|
scope?: ScriptScope;
|
|
306
307
|
fsMode?: ScriptFsMode;
|
|
308
|
+
executor?: ScriptExecutorName | null;
|
|
307
309
|
idempotencyKey?: string;
|
|
308
310
|
}): Promise<unknown>;
|
|
309
311
|
// --- swarm / agent ---
|
|
@@ -378,7 +380,7 @@ declare module "swarm-sdk" {
|
|
|
378
380
|
limit?: number;
|
|
379
381
|
offset?: number;
|
|
380
382
|
}): Promise<unknown>;
|
|
381
|
-
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
383
|
+
workflow_getRun(args: { id: string; fields?: "full" | "slim" }): Promise<unknown>;
|
|
382
384
|
// --- prompt templates ---
|
|
383
385
|
prompt_list(args?: {
|
|
384
386
|
eventType?: string;
|
|
@@ -535,7 +537,12 @@ declare module "swarm-sdk" {
|
|
|
535
537
|
workflow_patch(args: Record<string, unknown>): Promise<unknown>;
|
|
536
538
|
workflow_patchNode(args: Record<string, unknown>): Promise<unknown>;
|
|
537
539
|
workflow_delete(args: { id: string }): Promise<unknown>;
|
|
538
|
-
workflow_trigger(args: {
|
|
540
|
+
workflow_trigger(args: {
|
|
541
|
+
id: string;
|
|
542
|
+
triggerData?: Record<string, unknown>;
|
|
543
|
+
wait?: boolean;
|
|
544
|
+
idempotencyKey?: string;
|
|
545
|
+
}): Promise<unknown>;
|
|
539
546
|
workflow_retryRun(args: { id: string }): Promise<unknown>;
|
|
540
547
|
workflow_cancelRun(args: { id: string }): Promise<unknown>;
|
|
541
548
|
|
|
@@ -552,6 +559,7 @@ declare module "swarm-sdk" {
|
|
|
552
559
|
intent?: string;
|
|
553
560
|
scope?: ScriptScope;
|
|
554
561
|
fsMode?: ScriptFsMode;
|
|
562
|
+
executor?: ScriptExecutorName | null;
|
|
555
563
|
}): Promise<unknown>;
|
|
556
564
|
script_delete(args: { name: string; scope?: ScriptScope }): Promise<unknown>;
|
|
557
565
|
script_queryTypes(args: { name: string; scope?: ScriptScope }): Promise<unknown>;
|
|
@@ -9,16 +9,16 @@ declare module "swarm-extension" {
|
|
|
9
9
|
| "schedule"
|
|
10
10
|
| "slack"
|
|
11
11
|
| "agentmail"
|
|
12
|
-
| "mcp"
|
|
13
|
-
| "api"
|
|
14
|
-
| "ui"
|
|
15
12
|
| "github"
|
|
16
13
|
| "gitlab"
|
|
17
14
|
| "azure-devops"
|
|
18
15
|
| "bitbucket"
|
|
19
|
-
| "system"
|
|
20
16
|
| "linear"
|
|
21
17
|
| "jira"
|
|
18
|
+
| "mcp"
|
|
19
|
+
| "api"
|
|
20
|
+
| "ui"
|
|
21
|
+
| "system"
|
|
22
22
|
| "comb"
|
|
23
23
|
| "chat"
|
|
24
24
|
| undefined;
|
|
@@ -127,16 +127,16 @@ declare module "swarm-extension" {
|
|
|
127
127
|
| "schedule"
|
|
128
128
|
| "slack"
|
|
129
129
|
| "agentmail"
|
|
130
|
-
| "mcp"
|
|
131
|
-
| "api"
|
|
132
|
-
| "ui"
|
|
133
130
|
| "github"
|
|
134
131
|
| "gitlab"
|
|
135
132
|
| "azure-devops"
|
|
136
133
|
| "bitbucket"
|
|
137
|
-
| "system"
|
|
138
134
|
| "linear"
|
|
139
135
|
| "jira"
|
|
136
|
+
| "mcp"
|
|
137
|
+
| "api"
|
|
138
|
+
| "ui"
|
|
139
|
+
| "system"
|
|
140
140
|
| "comb"
|
|
141
141
|
| "chat";
|
|
142
142
|
tags: string[];
|
|
@@ -401,6 +401,15 @@ declare module "swarm-extension" {
|
|
|
401
401
|
description: string;
|
|
402
402
|
origin: TaskCreateOrigin;
|
|
403
403
|
requestInfo?: RequestInfo;
|
|
404
|
+
/** Slack ingress metadata; not persisted or writable through modify. */
|
|
405
|
+
slack?: {
|
|
406
|
+
trigger: "mention" | "thread-buffer";
|
|
407
|
+
messages: {
|
|
408
|
+
ts: string;
|
|
409
|
+
userId: string;
|
|
410
|
+
text: string;
|
|
411
|
+
}[];
|
|
412
|
+
};
|
|
404
413
|
}
|
|
405
414
|
/** A pre.task.create hook blocked a task before it was created. */
|
|
406
415
|
export interface TaskBlockedEvent {
|
|
@@ -8,6 +8,7 @@ declare module "swarm-sdk" {
|
|
|
8
8
|
| { [key: string]: JsonValue };
|
|
9
9
|
export type ScriptScope = "agent" | "global";
|
|
10
10
|
export type ScriptFsMode = "none" | "workspace-rw";
|
|
11
|
+
export type ScriptExecutorName = "native" | "quickjs";
|
|
11
12
|
export type ScriptApiRawOptions = { raw: true };
|
|
12
13
|
export type ScriptApiDefaultOptions = { raw?: false };
|
|
13
14
|
export type RoutingReason =
|
|
@@ -286,6 +287,7 @@ declare module "swarm-sdk" {
|
|
|
286
287
|
intent?: string;
|
|
287
288
|
scope?: ScriptScope;
|
|
288
289
|
fsMode?: ScriptFsMode;
|
|
290
|
+
executor?: ScriptExecutorName | null;
|
|
289
291
|
idempotencyKey?: string;
|
|
290
292
|
}): Promise<unknown>;
|
|
291
293
|
// --- swarm / agent ---
|
|
@@ -360,7 +362,7 @@ declare module "swarm-sdk" {
|
|
|
360
362
|
limit?: number;
|
|
361
363
|
offset?: number;
|
|
362
364
|
}): Promise<unknown>;
|
|
363
|
-
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
365
|
+
workflow_getRun(args: { id: string; fields?: "full" | "slim" }): Promise<unknown>;
|
|
364
366
|
// --- prompt templates ---
|
|
365
367
|
prompt_list(args?: {
|
|
366
368
|
eventType?: string;
|
|
@@ -517,7 +519,12 @@ declare module "swarm-sdk" {
|
|
|
517
519
|
workflow_patch(args: Record<string, unknown>): Promise<unknown>;
|
|
518
520
|
workflow_patchNode(args: Record<string, unknown>): Promise<unknown>;
|
|
519
521
|
workflow_delete(args: { id: string }): Promise<unknown>;
|
|
520
|
-
workflow_trigger(args: {
|
|
522
|
+
workflow_trigger(args: {
|
|
523
|
+
id: string;
|
|
524
|
+
triggerData?: Record<string, unknown>;
|
|
525
|
+
wait?: boolean;
|
|
526
|
+
idempotencyKey?: string;
|
|
527
|
+
}): Promise<unknown>;
|
|
521
528
|
workflow_retryRun(args: { id: string }): Promise<unknown>;
|
|
522
529
|
workflow_cancelRun(args: { id: string }): Promise<unknown>;
|
|
523
530
|
|
|
@@ -534,6 +541,7 @@ declare module "swarm-sdk" {
|
|
|
534
541
|
intent?: string;
|
|
535
542
|
scope?: ScriptScope;
|
|
536
543
|
fsMode?: ScriptFsMode;
|
|
544
|
+
executor?: ScriptExecutorName | null;
|
|
537
545
|
}): Promise<unknown>;
|
|
538
546
|
script_delete(args: { name: string; scope?: ScriptScope }): Promise<unknown>;
|
|
539
547
|
script_queryTypes(args: { name: string; scope?: ScriptScope }): Promise<unknown>;
|
package/src/slack/assistant.ts
CHANGED
|
@@ -213,6 +213,10 @@ export function createAssistant(): Assistant {
|
|
|
213
213
|
buildEffectiveText(messageText, inbound.files, inbound.failed, inbound.notes),
|
|
214
214
|
cachedBotUserId ?? undefined,
|
|
215
215
|
);
|
|
216
|
+
const slack = {
|
|
217
|
+
trigger: "mention" as const,
|
|
218
|
+
messages: [{ ts: message.ts, userId, text: messageText }],
|
|
219
|
+
};
|
|
216
220
|
|
|
217
221
|
if (workingAgent && workingAgent.status !== "offline") {
|
|
218
222
|
// Otherwise, create a follow-up task for the working agent
|
|
@@ -236,6 +240,7 @@ export function createAssistant(): Assistant {
|
|
|
236
240
|
contextKey: slackContextKey({ channelId, threadTs }),
|
|
237
241
|
},
|
|
238
242
|
inbound,
|
|
243
|
+
slack,
|
|
239
244
|
);
|
|
240
245
|
await ackSlackMessage(
|
|
241
246
|
client,
|
|
@@ -285,6 +290,7 @@ export function createAssistant(): Assistant {
|
|
|
285
290
|
contextKey: slackContextKey({ channelId, threadTs }),
|
|
286
291
|
},
|
|
287
292
|
inbound,
|
|
293
|
+
slack,
|
|
288
294
|
);
|
|
289
295
|
await ackSlackMessage(
|
|
290
296
|
client,
|
|
@@ -318,6 +324,7 @@ export function createAssistant(): Assistant {
|
|
|
318
324
|
contextKey: slackContextKey({ channelId, threadTs }),
|
|
319
325
|
},
|
|
320
326
|
inbound,
|
|
327
|
+
slack,
|
|
321
328
|
);
|
|
322
329
|
await ackSlackMessage(client, channelId, message.ts, reactionName("accepted"), "accepted");
|
|
323
330
|
await notifySlackFileFailures(client, channelId, threadTs, unattached);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { WebClient } from "@slack/web-api";
|
|
2
|
+
import { rememberSessionLabel } from "../be/db/session-labels";
|
|
3
|
+
import { getSlackApp } from "./app";
|
|
4
|
+
import { callSlackWithRetry, slackErrorCode } from "./render-v2";
|
|
5
|
+
|
|
6
|
+
const LABEL_TTL_MS = 24 * 60 * 60 * 1000;
|
|
7
|
+
const FAILURE_TTL_MS = 10 * 60 * 1000;
|
|
8
|
+
const FAILURE_CACHE_MAX = 500;
|
|
9
|
+
const LOOKUP_QUEUE_MAX = 50;
|
|
10
|
+
const inFlight = new Set<string>();
|
|
11
|
+
const failedUntil = new Map<string, number>();
|
|
12
|
+
let pending = Promise.resolve();
|
|
13
|
+
|
|
14
|
+
async function channelLabel(client: WebClient, id: string): Promise<string> {
|
|
15
|
+
const result = await callSlackWithRetry(client, "conversations.info", {
|
|
16
|
+
channel: id.toUpperCase(),
|
|
17
|
+
});
|
|
18
|
+
const channel = result.channel as
|
|
19
|
+
| { name?: string; is_im?: boolean; is_mpim?: boolean; user?: string }
|
|
20
|
+
| undefined;
|
|
21
|
+
if (result.ok === false || !channel) throw new Error("Channel lookup failed");
|
|
22
|
+
if (channel.is_mpim) return "Group DM";
|
|
23
|
+
if (channel.is_im && channel.user) {
|
|
24
|
+
const result = await callSlackWithRetry(client, "users.info", { user: channel.user });
|
|
25
|
+
const user = result.user as
|
|
26
|
+
| { profile?: { display_name?: string; real_name?: string }; real_name?: string }
|
|
27
|
+
| undefined;
|
|
28
|
+
const name = user?.profile?.display_name || user?.real_name || user?.profile?.real_name;
|
|
29
|
+
if (result.ok !== false && name) return `DM · ${name}`;
|
|
30
|
+
} else if (channel.name) {
|
|
31
|
+
return `#${channel.name}`;
|
|
32
|
+
}
|
|
33
|
+
throw new Error("Channel label unavailable");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CHANNEL_GROUP_KEY = /^shared\/slack\/([^/]+)\/$/;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Queue a Slack lookup for each channel group key (`shared/slack/<channel>/`)
|
|
40
|
+
* without delaying the tree response. Other keys are ignored.
|
|
41
|
+
*/
|
|
42
|
+
export function warmSlackChannelLabels(groupKeys: string[]): void {
|
|
43
|
+
const client = getSlackApp()?.client;
|
|
44
|
+
if (!client) return;
|
|
45
|
+
for (const groupKey of groupKeys) {
|
|
46
|
+
const id = CHANNEL_GROUP_KEY.exec(groupKey)?.[1];
|
|
47
|
+
if (!id) continue;
|
|
48
|
+
if (inFlight.has(id) || (failedUntil.get(id) ?? 0) > Date.now()) continue;
|
|
49
|
+
failedUntil.delete(id);
|
|
50
|
+
if (inFlight.size >= LOOKUP_QUEUE_MAX) continue;
|
|
51
|
+
// Reserve failure capacity for queued work. Live failures must retain their TTL.
|
|
52
|
+
if (failedUntil.size + inFlight.size >= FAILURE_CACHE_MAX) {
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
for (const [failedId, until] of failedUntil) {
|
|
55
|
+
if (until <= now) failedUntil.delete(failedId);
|
|
56
|
+
}
|
|
57
|
+
if (failedUntil.size + inFlight.size >= FAILURE_CACHE_MAX) continue;
|
|
58
|
+
}
|
|
59
|
+
inFlight.add(id);
|
|
60
|
+
pending = pending.then(async () => {
|
|
61
|
+
try {
|
|
62
|
+
const label = await channelLabel(client, id);
|
|
63
|
+
await rememberSessionLabel(groupKey, label, LABEL_TTL_MS);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
failedUntil.set(id, Date.now() + FAILURE_TTL_MS);
|
|
66
|
+
console.warn(
|
|
67
|
+
`[Slack] Could not cache a session channel label: ${slackErrorCode(error) ?? "unknown error"}`,
|
|
68
|
+
);
|
|
69
|
+
} finally {
|
|
70
|
+
inFlight.delete(id);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/slack/handlers.ts
CHANGED
|
@@ -679,6 +679,11 @@ export function registerMessageHandler(app: App): void {
|
|
|
679
679
|
routingThreadContext,
|
|
680
680
|
);
|
|
681
681
|
|
|
682
|
+
const slack = {
|
|
683
|
+
trigger: "mention" as const,
|
|
684
|
+
messages: [{ ts: msg.ts, userId: msg.user, text: msg.text ?? "" }],
|
|
685
|
+
};
|
|
686
|
+
|
|
682
687
|
if (matches.length === 0) {
|
|
683
688
|
if (!botMentioned && !isImplicitMention) return ignoreSlackInbound("not_addressed");
|
|
684
689
|
|
|
@@ -742,6 +747,7 @@ export function registerMessageHandler(app: App): void {
|
|
|
742
747
|
contextKey: slackContextKey({ channelId: msg.channel, threadTs }),
|
|
743
748
|
},
|
|
744
749
|
inbound,
|
|
750
|
+
slack,
|
|
745
751
|
);
|
|
746
752
|
await ackSlackMessage(client, msg.channel, msg.ts, reactionName("accepted"), "accepted");
|
|
747
753
|
await notifySlackFileFailures(client, msg.channel, threadTs, unattached);
|
|
@@ -864,6 +870,7 @@ export function registerMessageHandler(app: App): void {
|
|
|
864
870
|
contextKey: slackContextKey({ channelId: msg.channel, threadTs }),
|
|
865
871
|
},
|
|
866
872
|
inbound,
|
|
873
|
+
slack,
|
|
867
874
|
);
|
|
868
875
|
const { task } = created;
|
|
869
876
|
unattached.push(...created.unattached);
|
|
@@ -888,6 +895,7 @@ export function registerMessageHandler(app: App): void {
|
|
|
888
895
|
contextKey: slackContextKey({ channelId: msg.channel, threadTs }),
|
|
889
896
|
},
|
|
890
897
|
inbound,
|
|
898
|
+
slack,
|
|
891
899
|
);
|
|
892
900
|
const { task } = created;
|
|
893
901
|
unattached.push(...created.unattached);
|
|
@@ -22,6 +22,7 @@ import { join } from "node:path";
|
|
|
22
22
|
import type { WebClient } from "@slack/web-api";
|
|
23
23
|
import { getTaskAttachments, getTaskById, promoteDraftTask, refreshDraftTaskLease } from "../be/db";
|
|
24
24
|
import { MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload } from "../be/task-attachment-store";
|
|
25
|
+
import type { TaskCreateEvent } from "../extensions/contract";
|
|
25
26
|
import { providerPath } from "../fs/provider";
|
|
26
27
|
import { getFileStorageProvider } from "../fs/registry";
|
|
27
28
|
import { resolveTemplate } from "../prompts/resolver";
|
|
@@ -320,17 +321,19 @@ export async function createSlackTaskWithFiles(
|
|
|
320
321
|
description: string,
|
|
321
322
|
options: CreateTaskOptions,
|
|
322
323
|
inbound: InboundSlackFiles,
|
|
324
|
+
slack?: TaskCreateEvent["slack"],
|
|
323
325
|
): Promise<{ task: AgentTask; unattached: SlackFileFailure[] }> {
|
|
324
326
|
noteSlackInboundSideEffect("task_created");
|
|
327
|
+
const context = { origin: "slack" as const, slack };
|
|
325
328
|
if (inbound.fetched.length === 0) {
|
|
326
|
-
const task = await createTaskWithSiblingAwareness(description, options,
|
|
329
|
+
const task = await createTaskWithSiblingAwareness(description, options, context);
|
|
327
330
|
return { task, unattached: inbound.failed };
|
|
328
331
|
}
|
|
329
332
|
|
|
330
333
|
const task = await createTaskWithSiblingAwareness(
|
|
331
334
|
description,
|
|
332
335
|
{ ...options, status: "draft" },
|
|
333
|
-
|
|
336
|
+
context,
|
|
334
337
|
);
|
|
335
338
|
const unattached = [...inbound.failed];
|
|
336
339
|
// Uploads run one after another and can outlast the abandoned-draft sweep's
|
|
@@ -313,6 +313,10 @@ async function slackFlush(
|
|
|
313
313
|
contextKey: slackContextKey({ channelId, threadTs }),
|
|
314
314
|
},
|
|
315
315
|
inbound,
|
|
316
|
+
{
|
|
317
|
+
trigger: "thread-buffer",
|
|
318
|
+
messages: items.map(({ ts, userId, text }) => ({ ts, userId, text })),
|
|
319
|
+
},
|
|
316
320
|
);
|
|
317
321
|
} catch (error) {
|
|
318
322
|
if (!(error instanceof TaskCreationBlockedError)) throw error;
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
getInProgressTasksByContextKey,
|
|
19
19
|
} from "../be/db";
|
|
20
20
|
import { applyPreTaskCreate } from "../extensions/apply-task-create";
|
|
21
|
-
import type { TaskCreateOrigin } from "../extensions/contract";
|
|
21
|
+
import type { TaskCreateEvent, TaskCreateOrigin } from "../extensions/contract";
|
|
22
22
|
import type { AgentTask } from "../types";
|
|
23
23
|
import { TaskCreationBlockedError } from "./errors";
|
|
24
24
|
import {
|
|
@@ -151,7 +151,11 @@ export type PreparedTaskCreate = { description: string; options: CreateTaskOptio
|
|
|
151
151
|
export async function prepareTaskWithSiblingAwareness(
|
|
152
152
|
description: string,
|
|
153
153
|
options: CreateTaskOptions,
|
|
154
|
-
args: {
|
|
154
|
+
args: {
|
|
155
|
+
origin?: TaskCreateOrigin;
|
|
156
|
+
allowCustomModel?: boolean;
|
|
157
|
+
slack?: TaskCreateEvent["slack"];
|
|
158
|
+
} = {},
|
|
155
159
|
): Promise<PreparedTaskCreate> {
|
|
156
160
|
const preCreate = await applyPreTaskCreate({
|
|
157
161
|
description,
|
|
@@ -159,6 +163,7 @@ export async function prepareTaskWithSiblingAwareness(
|
|
|
159
163
|
// Preserve the plan's REST default for callers without an explicit ingress origin.
|
|
160
164
|
origin: args.origin ?? "rest",
|
|
161
165
|
allowCustomModel: args.allowCustomModel,
|
|
166
|
+
slack: args.slack,
|
|
162
167
|
});
|
|
163
168
|
if (preCreate.kind === "blocked") {
|
|
164
169
|
throw new TaskCreationBlockedError(preCreate.reason, preCreate.extension);
|
|
@@ -169,7 +174,11 @@ export async function prepareTaskWithSiblingAwareness(
|
|
|
169
174
|
export async function createTaskWithSiblingAwareness(
|
|
170
175
|
description: string,
|
|
171
176
|
options: CreateTaskOptions,
|
|
172
|
-
args: {
|
|
177
|
+
args: {
|
|
178
|
+
origin?: TaskCreateOrigin;
|
|
179
|
+
allowCustomModel?: boolean;
|
|
180
|
+
slack?: TaskCreateEvent["slack"];
|
|
181
|
+
} = {},
|
|
173
182
|
): Promise<AgentTask> {
|
|
174
183
|
const { description: d, options: o } = await prepareTaskWithSiblingAwareness(
|
|
175
184
|
description,
|
package/src/telemetry-context.ts
CHANGED
|
@@ -12,8 +12,8 @@ import catalog from "./telemetry-contract/catalog.json";
|
|
|
12
12
|
import {
|
|
13
13
|
COMPANY_ACQUISITION_SOURCES,
|
|
14
14
|
COMPANY_TEAM_SIZES,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
reportedUseCase,
|
|
16
|
+
reportedUserFunction,
|
|
17
17
|
} from "./utils/company-profile";
|
|
18
18
|
|
|
19
19
|
/** `org_` + 16 lowercase hex (self-host, minted here) or 27 alphanumerics (cloud). Same pattern the proxy enforces. */
|
|
@@ -115,10 +115,9 @@ export function buildContext(input: ContextInput): EventContext {
|
|
|
115
115
|
const orgDomain = validOrgDomain(input.orgDomain);
|
|
116
116
|
const orgWebsite = validOrgDomain(input.orgWebsite);
|
|
117
117
|
const teamSize = COMPANY_TEAM_SIZES.find((value) => value === input.teamSize);
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
: undefined;
|
|
118
|
+
// A value the catalog does not list yet is left out, as if unset.
|
|
119
|
+
const useCase = reportedUseCase(input.useCase);
|
|
120
|
+
const userFunction = userId ? reportedUserFunction(input.userFunction) : undefined;
|
|
122
121
|
return {
|
|
123
122
|
org_id: input.orgId,
|
|
124
123
|
org_name: orgName ? orgName : null,
|