@desplega.ai/agent-swarm 2.5.3 → 2.6.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 +2 -2
- package/dist/{acp-adapter-gr2fcyyj.js → acp-adapter-dgfakfpw.js} +9 -9
- package/dist/{actions-wv766ghf.js → actions-fbqma8aa.js} +21 -21
- package/dist/{amp-adapter-speb906t.js → amp-adapter-en0jy6hs.js} +4 -4
- package/dist/{app-ag29n14f.js → app-k8a5cgpp.js} +3 -3
- package/dist/{assistant-3x8bz3eg.js → assistant-a16433gr.js} +30 -26
- package/dist/{boot-reembed-jsmfrpzf.js → boot-reembed-6c1sjfnr.js} +1 -1
- package/dist/{boot-reembed-5b3d2eea.js → boot-reembed-f4nn561n.js} +1 -1
- package/dist/{boot-scrub-sweep-s73gerxy.js → boot-scrub-sweep-d4w9gajf.js} +4 -4
- package/dist/{boot-seeds-5zmax2wr.js → boot-seeds-9bmkspyw.js} +4 -4
- package/dist/{claude-adapter-hswdnm3t.js → claude-adapter-nys1kjxa.js} +9 -9
- package/dist/{claude-managed-adapter-cvbzj1h6.js → claude-managed-adapter-55207973.js} +3 -3
- package/dist/{claude-managed-setup-3k8m3hhc.js → claude-managed-setup-3cm35gey.js} +11 -4
- package/dist/{claude-sdk-session-fkbyk66x.js → claude-sdk-session-nw5yd8cp.js} +9313 -9260
- package/dist/{cli-210xd1f4.js → cli-03gg9pd1.js} +4 -4
- package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
- package/dist/cli-1tem6ns9.js +894 -0
- package/dist/{cli-25j01dpj.js → cli-24j1jeeb.js} +3 -3
- package/dist/{cli-ta8bd7th.js → cli-2sjhpsns.js} +2 -2
- package/dist/{cli-p859hcc8.js → cli-39aet655.js} +2 -2
- package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
- package/dist/{cli-e2ar4bp1.js → cli-3aqd4jaa.js} +121 -47
- package/dist/{cli-jjznk3f7.js → cli-3fwqy71j.js} +69 -35
- package/dist/{cli-p9rafdrb.js → cli-3gfvmzht.js} +7 -7
- package/dist/{cli-03vpq45j.js → cli-3ndmpxxv.js} +2 -2
- package/dist/{cli-aecdcr77.js → cli-4hxrf0p4.js} +228 -74
- package/dist/{cli-mz9afxxf.js → cli-4rf0f5vg.js} +15 -3
- package/dist/{cli-qzme5949.js → cli-5rj83bam.js} +284 -202
- package/dist/{cli-fsdprwrg.js → cli-5sckpqcx.js} +2 -2
- package/dist/{cli-cz5nmdxt.js → cli-683y0b3a.js} +2 -2
- package/dist/{cli-3ngdk5te.js → cli-6y51ryva.js} +2 -2
- package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
- package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
- package/dist/{cli-gx4rm0qx.js → cli-7enjwya9.js} +1 -1
- package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
- package/dist/{cli-avdvgcay.js → cli-9abdgn5t.js} +28 -9
- package/dist/{cli-99xgw26r.js → cli-a2rr0fmg.js} +1 -1
- package/dist/{cli-e5bxnjps.js → cli-a34pr3w1.js} +7 -7
- package/dist/{cli-502eqv93.js → cli-abkm71vr.js} +1 -1
- package/dist/{cli-mmhj8vd7.js → cli-ag2yrnt5.js} +11 -2
- package/dist/{cli-n45mr7zh.js → cli-aj8djyqt.js} +5 -5
- package/dist/{cli-1fc85mvt.js → cli-art7c1zh.js} +5 -5
- package/dist/{cli-40jsnrjm.js → cli-az25fn5f.js} +10 -8
- package/dist/{cli-9s05422w.js → cli-bqztfyve.js} +1 -1
- package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
- package/dist/{cli-svrj71pg.js → cli-c2habvsf.js} +12 -12
- package/dist/{cli-s49hpn37.js → cli-ca6banwz.js} +85 -19
- package/dist/{cli-hhxjnjzs.js → cli-cz37jqss.js} +12 -10
- package/dist/{cli-6n8axjv1.js → cli-d2dpf95n.js} +2 -2
- package/dist/{cli-tx00c0h6.js → cli-dqygeeh5.js} +17 -1
- package/dist/{cli-z21whrrg.js → cli-emhjcj2y.js} +17 -17
- package/dist/{cli-e8jyq7d8.js → cli-esakngh8.js} +7 -3
- package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
- package/dist/{cli-35gtk1p6.js → cli-ffvsj2qw.js} +44 -13
- package/dist/{cli-ce0ak9ms.js → cli-g20jjwt4.js} +26 -26
- package/dist/{cli-kxawjrxg.js → cli-g8ka5j4j.js} +772 -194
- package/dist/{cli-vwn81jbs.js → cli-gf95q3bm.js} +5 -5
- package/dist/{cli-s53vp709.js → cli-gnsb1zxa.js} +2 -2
- package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
- package/dist/{cli-gpv60278.js → cli-hfeb68z4.js} +7 -7
- package/dist/{cli-0ebey9hg.js → cli-j6rktc91.js} +1 -1
- package/dist/{cli-ewm3pwbq.js → cli-k21gx5ht.js} +46 -23
- package/dist/{cli-egjggehm.js → cli-kf4jree9.js} +2 -2
- package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
- package/dist/{cli-p0rzjkya.js → cli-m5a9m0ak.js} +32 -13
- package/dist/{cli-fzcn3d87.js → cli-m70bajzr.js} +3 -3
- package/dist/{cli-w1zwctj2.js → cli-mtnj4fwa.js} +11 -5
- package/dist/{cli-gpsz7g88.js → cli-mvjz5an3.js} +16 -12
- package/dist/{cli-hcpj2xqz.js → cli-n7asmce6.js} +225 -3
- package/dist/{cli-y561h5a9.js → cli-nn6vx2mq.js} +5 -5
- package/dist/cli-nq677csy.js +140 -0
- package/dist/{cli-a5ebc95n.js → cli-pfk92eqz.js} +18 -15
- package/dist/{cli-p6zs9h4y.js → cli-rr7zx19j.js} +767 -249
- package/dist/{cli-qgf8emrn.js → cli-sqma6vw1.js} +10 -7
- package/dist/{cli-0xk505e8.js → cli-sxgtf5fw.js} +1 -1
- package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
- package/dist/{cli-qqzmjxkf.js → cli-v49fkghp.js} +11 -6
- package/dist/{cli-x77gen2p.js → cli-w2656ka1.js} +7 -7
- package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
- package/dist/{cli-8s5wx3nz.js → cli-zqne1qcj.js} +44 -17
- package/dist/cli.js +22 -22
- package/dist/{codex-adapter-n8ka66vf.js → codex-adapter-d95q4qsn.js} +7 -7
- package/dist/{codex-hook-e2he7aca.js → codex-hook-brpnycn5.js} +1 -1
- package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
- package/dist/{codex-session-runner-fsebts37.js → codex-session-runner-gdwd8h0c.js} +8 -8
- package/dist/{commands-t04rt2pc.js → commands-jqmgk54b.js} +2 -2
- package/dist/{controller-rgna04r2.js → controller-z3jq589f.js} +30 -4
- package/dist/{controllers-connect-bqm1rtft.js → controllers-connect-r2za39ef.js} +23 -23
- package/dist/{cursor-adapter-swr2k95y.js → cursor-adapter-4mr4jgkw.js} +2 -3
- package/dist/{db-a4m7haw0.js → db-ppv2tze7.js} +3 -3
- package/dist/{db-24ck09xy.js → db-w36wwb5g.js} +4 -2
- package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
- package/dist/{dispatcher-nwf9ss0q.js → dispatcher-pv5h77vf.js} +20 -20
- package/dist/{docker-nfy2gc8t.js → docker-fdzyewpz.js} +4 -4
- package/dist/{dsh-adapter-kpdnhjst.js → dsh-adapter-d4pdpb3r.js} +2 -3
- 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-4sp4dvmc.js} +1 -1
- package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
- package/dist/{execute-0xpz8950.js → execute-jev839y1.js} +1 -1
- package/dist/{external-channel-j1e2p34p.js → external-channel-y6nkzhnn.js} +2 -2
- package/dist/{grok-adapter-qtjz0whk.js → grok-adapter-t08b9ntm.js} +10 -10
- package/dist/handlers-eqsnmv95.js +41 -0
- package/dist/{heartbeat-vtesda5d.js → heartbeat-vn31xwdk.js} +23 -23
- package/dist/{hook-b2hhj6rd.js → hook-6d0zbvvt.js} +6 -5
- package/dist/{hook-8wqaszda.js → hook-cpjs8q51.js} +13 -7
- package/dist/{http-mxcqhhcs.js → http-9c6medda.js} +1085 -136
- package/dist/{index-spwxjgay.js → index-38t35h0n.js} +20 -20
- package/dist/{index-1r8wfpzs.js → index-g6k9tctj.js} +1 -1
- package/dist/{index-srg522m6.js → index-k0yt1tvq.js} +20 -20
- package/dist/{index-31ceyf42.js → index-pkma1yf8.js} +1 -1
- package/dist/{index-n1vbvta9.js → index-qhjf2htm.js} +29 -24
- package/dist/index-yqgbfgaj.js +43 -0
- package/dist/{keepalive-dsd8rtgx.js → keepalive-em0117bp.js} +4 -4
- package/dist/lead-23e7z59t.js +79 -0
- package/dist/{maintenance-jqmqwnet.js → maintenance-kbme3qy9.js} +1 -1
- package/dist/{oauth-refresh-sweep-q2c3bnvm.js → oauth-refresh-sweep-xysj4yse.js} +3 -3
- package/dist/{onboard-w4yd7s8t.js → onboard-p6q0vz97.js} +3 -3
- package/dist/{opencode-adapter-9tppvxar.js → opencode-adapter-esv3k9yn.js} +7 -7
- package/dist/{otel-impl-f36byzbd.js → otel-impl-54qhqh1z.js} +2 -2
- package/dist/{pi-mono-adapter-tqsge1ay.js → pi-mono-adapter-mymbwhj0.js} +41 -14
- package/dist/{pricing-refresh-xvak5p4v.js → pricing-refresh-yb75wv33.js} +3 -3
- package/dist/{rbac-roles-gfn30fb8.js → rbac-roles-1vp2mw4p.js} +2 -2
- package/dist/{rbac-roles-682k2mt5.js → rbac-roles-dexhc9x8.js} +1 -1
- package/dist/render-v2-tjay5hhf.js +16 -0
- package/dist/{resume-2dvq348g.js → resume-8ayf37g5.js} +11 -9
- package/dist/{runtime-bt5pkpm1.js → runtime-hqe5cqcd.js} +1 -1
- package/dist/{session-access-7f21ekq9.js → session-access-fdhp987s.js} +4 -4
- package/dist/session-source-backfill-qgtc86z1.js +110 -0
- package/dist/{setup-epffxtbk.js → setup-4rrmqcq3.js} +1 -1
- package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-52km00d6.js} +2 -2
- package/dist/{work-objects-xz1a5rqk.js → work-objects-p28fgd70.js} +23 -23
- package/dist/worker-e3w7vye1.js +79 -0
- package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
- package/openapi.json +1323 -16
- package/package.json +5 -5
- package/plugin/commands/create-pr.md +2 -2
- package/plugin/pi-skills/create-pr/SKILL.md +2 -2
- package/src/assets/source-key.ts +95 -0
- package/src/be/db/api-keys.ts +80 -0
- package/src/be/db/approvals.ts +48 -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 +21 -6
- package/src/be/db/workflow-idempotency.ts +183 -0
- package/src/be/db/workflow-runs.ts +500 -7
- package/src/be/db-retention.ts +61 -6
- package/src/be/db.ts +126 -131
- package/src/be/memory/providers/openai-embedding.ts +5 -1
- package/src/be/migrations/242_workflow_idempotency_keys.sql +40 -0
- package/src/be/migrations/244_api_key_validation.sql +4 -0
- package/src/be/onboarding.ts +4 -0
- package/src/be/scripts/typecheck.ts +1 -1
- package/src/be/sealed-json.ts +1 -0
- package/src/be/seed-scripts/catalog/compound-insights.inline.ts +2 -2
- package/src/be/seed-scripts/catalog/compound-insights.ts +2 -2
- package/src/be/seed-skills/bundled-files.generated.json +1 -1
- package/src/be/session-source-backfill.ts +163 -0
- package/src/be/sql-connections.ts +7 -1
- package/src/be/swarm-config-guard.ts +3 -0
- package/src/be/users.ts +9 -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/controller.ts +33 -0
- package/src/commands/credential-refresh.ts +76 -1
- package/src/commands/credential-wait.ts +2 -2
- package/src/commands/provider-credentials.ts +210 -170
- package/src/commands/runner.ts +31 -6
- package/src/extensions/apply-task-create.ts +64 -11
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +30 -0
- package/src/extensions/dispatcher.ts +4 -0
- package/src/extensions/post-bridge.ts +8 -0
- package/src/hooks/context-bound-note.ts +196 -0
- package/src/hooks/hook.ts +12 -0
- package/src/http/all-routes.ts +2 -0
- package/src/http/api-keys.ts +53 -0
- 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 +49 -17
- package/src/http/core.ts +6 -0
- package/src/http/fleet-benchmark.ts +5 -2
- package/src/http/idempotency-key.ts +117 -0
- package/src/http/index.ts +11 -0
- package/src/http/integrations.ts +5 -1
- package/src/http/kv.ts +8 -3
- package/src/http/onboarding.ts +6 -1
- package/src/http/pool-keys.ts +354 -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 +207 -33
- package/src/integrations/chat-sdk/inbound.ts +27 -0
- package/src/kv-reserved-namespaces.ts +19 -0
- package/src/prompts/context-bound-note.ts +48 -0
- package/src/prompts/session-templates.ts +25 -1
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +30 -8
- package/src/providers/claude-adapter.ts +34 -5
- package/src/providers/claude-managed-adapter.ts +42 -9
- package/src/providers/claude-sdk-session.ts +10 -0
- package/src/providers/claude-session-events.ts +13 -0
- package/src/providers/codex-adapter.ts +83 -11
- package/src/providers/opencode-adapter.ts +18 -0
- package/src/providers/pi-mono-adapter.ts +35 -0
- package/src/runtime-providers/docker.ts +6 -2
- package/src/scheduler/scheduler.ts +3 -2
- package/src/scripts-runtime/swarm-sdk.ts +7 -1
- package/src/scripts-runtime/types/stdlib.d.ts +1 -1
- package/src/scripts-runtime/types/swarm-extension.d.ts +52 -8
- package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -1
- 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/amp-adapter.test.ts +97 -0
- package/src/tests/api-keys-validation.test.ts +170 -0
- package/src/tests/approval-requests.test.ts +10 -7
- package/src/tests/approval-sweeps.test.ts +12 -6
- package/src/tests/base-prompt.test.ts +1 -1
- package/src/tests/claude-hook-output.test.ts +79 -1
- package/src/tests/claude-managed-adapter.test.ts +321 -0
- package/src/tests/claude-routes-e2e.test.ts +7 -2
- package/src/tests/codex-adapter.test.ts +163 -0
- 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/config-pool-keys.test.ts +533 -0
- package/src/tests/context-bound-note.test.ts +269 -0
- package/src/tests/credential-check.test.ts +290 -2
- 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/extensions-pre-task.test.ts +325 -0
- package/src/tests/fetch-resolved-env.test.ts +17 -0
- package/src/tests/fixtures/extensions/record-blocks/hooks.ts +10 -0
- package/src/tests/fixtures/extensions/record-blocks/manifest.json +7 -0
- 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/fixtures/fake-amp.ts +22 -8
- package/src/tests/fixtures/held-template-render.ts +42 -0
- package/src/tests/fixtures/workflow-idempotency-trigger.child.ts +73 -0
- package/src/tests/fleet-benchmark.test.ts +8 -0
- package/src/tests/get-workflow-run-tool.test.ts +98 -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/onboarding.test.ts +108 -1
- package/src/tests/openai-embedding-credentials.test.ts +35 -0
- package/src/tests/openapi-route-headers.test.ts +2 -0
- package/src/tests/opencode-adapter.test.ts +134 -0
- package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
- package/src/tests/org-website.test.ts +36 -0
- package/src/tests/pi-mono-adapter.test.ts +105 -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/runner-push-delivery.test.ts +25 -0
- package/src/tests/runtime-controller-liveness.test.ts +133 -0
- package/src/tests/runtime-providers-docker.test.ts +2 -0
- package/src/tests/script-connections.test.ts +5 -0
- package/src/tests/script-run-config-scope.test.ts +91 -3
- package/src/tests/script-runs-retention.test.ts +212 -0
- package/src/tests/sdk-allowlist.test.ts +39 -0
- package/src/tests/session-logs.test.ts +70 -0
- 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 +336 -2
- package/src/tests/slack-inbound-files.test.ts +103 -23
- package/src/tests/status.test.ts +101 -18
- 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/used-by-route.test.ts +11 -0
- package/src/tests/workflow-cascade-cancel.test.ts +1341 -0
- package/src/tests/workflow-foreach-supersede-retry.test.ts +488 -0
- package/src/tests/workflow-http-v2.test.ts +131 -0
- package/src/tests/workflow-idempotency.test.ts +915 -0
- package/src/tests/workflow-step-order.test.ts +92 -0
- package/src/tests/workflow-sub-workflow.test.ts +30 -0
- package/src/tools/get-tasks.ts +8 -0
- package/src/tools/kv/kv-read-auth.ts +4 -2
- package/src/tools/task-action.ts +1 -1
- package/src/tools/workflows/cancel-workflow-run.ts +1 -1
- package/src/tools/workflows/get-workflow-run.ts +14 -4
- package/src/types.ts +24 -0
- package/src/utils/company-profile.ts +51 -1
- package/src/utils/context-window.ts +8 -6
- package/src/utils/credentials.ts +5 -2
- 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/approval-cancel.ts +15 -13
- package/src/workflows/approval-notifications.ts +5 -1
- package/src/workflows/checkpoint.ts +6 -3
- package/src/workflows/engine.ts +30 -8
- package/src/workflows/executors/foreach.ts +2 -2
- package/src/workflows/executors/sub-workflow.ts +8 -1
- package/src/workflows/foreach-driver.ts +10 -3
- package/src/workflows/foreach-join.ts +29 -6
- package/src/workflows/recovery.ts +6 -1
- package/src/workflows/resume.ts +168 -56
- package/src/workflows/retry-poller.ts +49 -3
- package/src/workflows/task-step-routing.ts +29 -7
- package/templates/ai-toolbox.manifest.json +8 -8
- package/templates/community/open-prompt-showreel/PLAYBOOK.md +5 -6
- package/templates/community/open-prompt-showreel/lead-prompt.md +1 -1
- package/templates/community/open-prompt-showreel/skills/open-prompt-showreel/SKILL.md +4 -4
- package/templates/skills/agent-browser/SKILL.md +4 -4
- package/templates/skills/agent-browser/content.md +4 -4
- package/templates/skills/code-quality/config.json +1 -1
- package/templates/skills/code-quality/content.md +2 -2
- package/templates/skills/delegate-work/content.md +29 -25
- package/templates/skills/delegate-work/files/scripts/codex-exec.sh +5 -5
- package/templates/skills/qa/content.md +2 -2
- package/templates/skills/researching/content.md +4 -0
- package/templates/skills/swarm-scripts/SKILL.md +1 -0
- package/templates/skills/swarm-scripts/content.md +1 -0
- package/templates/skills/work-on-task/SKILL.md +1 -1
- package/templates/skills/work-on-task/content.md +1 -1
- package/dist/cli-7421jzsw.js +0 -84
- package/dist/cli-e45e4m6b.js +0 -413
- package/dist/cli-zw88zjba.js +0 -307
- package/dist/handlers-19xr6dnz.js +0 -41
- package/dist/index-kw2mmat7.js +0 -43
- package/dist/lead-zyerk1x2.js +0 -79
- package/dist/render-v2-hgytz8nn.js +0 -12
- package/dist/worker-42t8emjt.js +0 -79
|
@@ -150,6 +150,8 @@ import {
|
|
|
150
150
|
TelegramBotApiError,
|
|
151
151
|
callTelegramBotApi,
|
|
152
152
|
isTrustedTeamsServiceUrl,
|
|
153
|
+
getSessionLabels,
|
|
154
|
+
rememberSessionLabel,
|
|
153
155
|
isChatSdkStopping,
|
|
154
156
|
startChatSdk,
|
|
155
157
|
getChatInstance,
|
|
@@ -176,6 +178,7 @@ import {
|
|
|
176
178
|
extractAndVerifyCookie,
|
|
177
179
|
pageSessionSetCookies,
|
|
178
180
|
resolveHttpRequestAuth,
|
|
181
|
+
getDeploymentEnvValue,
|
|
179
182
|
loadGlobalConfigsIntoEnv,
|
|
180
183
|
reloadGlobalConfigsAndIntegrations,
|
|
181
184
|
scheduleIntegrationsReload,
|
|
@@ -227,6 +230,7 @@ import {
|
|
|
227
230
|
getTasksOutputSchema,
|
|
228
231
|
getTasksHandler,
|
|
229
232
|
reservedNamespaceError,
|
|
233
|
+
privateNamespaceError,
|
|
230
234
|
reservedRoomKeyError,
|
|
231
235
|
updateMcpServerChecked,
|
|
232
236
|
updateTouchesStdioExecution,
|
|
@@ -289,17 +293,23 @@ import {
|
|
|
289
293
|
hasCapability,
|
|
290
294
|
getEnabledCapabilities,
|
|
291
295
|
createServer
|
|
292
|
-
} from "./cli-
|
|
296
|
+
} from "./cli-4hxrf0p4.js";
|
|
293
297
|
import {
|
|
294
298
|
chatThreadOfContextKey,
|
|
295
299
|
agentContextKey,
|
|
296
300
|
pageContextKey,
|
|
297
301
|
init_context_key,
|
|
302
|
+
sourceOfKey,
|
|
303
|
+
SOURCE_GROUPS_READ_ONLY,
|
|
304
|
+
sourceMoveError,
|
|
305
|
+
init_source_key,
|
|
298
306
|
init_catalog,
|
|
299
307
|
catalog_default,
|
|
300
308
|
COMPANY_TEAM_SIZES,
|
|
301
309
|
COMPANY_USE_CASES,
|
|
302
310
|
USER_FUNCTIONS,
|
|
311
|
+
reportedUseCase,
|
|
312
|
+
reportedUserFunction,
|
|
303
313
|
init_company_profile,
|
|
304
314
|
TELEMETRY_PROXY_ORIGIN,
|
|
305
315
|
normalizeOrgWebsite,
|
|
@@ -347,6 +357,7 @@ import {
|
|
|
347
357
|
resolveTriggerSurface,
|
|
348
358
|
emitTaskTelemetry,
|
|
349
359
|
init_telemetry_trigger,
|
|
360
|
+
CODEX_AUTH_FAILURE_BENCH_THRESHOLD,
|
|
350
361
|
CODEX_AUTH_WATCH_NAMESPACE,
|
|
351
362
|
codexAuthBenchMarkerKey,
|
|
352
363
|
init_codex_auth_failure,
|
|
@@ -410,6 +421,7 @@ import {
|
|
|
410
421
|
listPrefixRoots,
|
|
411
422
|
listSharedPrefixRoots,
|
|
412
423
|
init_session_moves,
|
|
424
|
+
getSessionGroupKey,
|
|
413
425
|
getSessionReadState,
|
|
414
426
|
getSessionTree,
|
|
415
427
|
triageSessionList,
|
|
@@ -440,6 +452,17 @@ import {
|
|
|
440
452
|
getPausedTasksForAgent2,
|
|
441
453
|
resetOrphanedInProgressTasksForAgent2,
|
|
442
454
|
updateTaskProgress2,
|
|
455
|
+
IdempotencyKeyTakenError,
|
|
456
|
+
workflowRequestFingerprint,
|
|
457
|
+
findAcceptedWorkflowOperation,
|
|
458
|
+
assertWorkflowIdempotencyKeyUnused,
|
|
459
|
+
recordAcceptedWorkflowOperation,
|
|
460
|
+
init_workflow_idempotency,
|
|
461
|
+
getWorkflowRunSummary,
|
|
462
|
+
getWorkflowRunStepsSlimByRunId,
|
|
463
|
+
WORKFLOW_RUN_TREE_MAX_DEPTH,
|
|
464
|
+
WorkflowRunTreeError,
|
|
465
|
+
getWorkflowRunTree,
|
|
443
466
|
getWorkflowRunParent,
|
|
444
467
|
init_workflow_runs,
|
|
445
468
|
CHAT_SDK_ADAPTER_NAMES,
|
|
@@ -531,6 +554,9 @@ import {
|
|
|
531
554
|
init_steering,
|
|
532
555
|
refreshActiveSessionOnActivity2,
|
|
533
556
|
recordKeySeatMismatch2,
|
|
557
|
+
recordKeyValidation2,
|
|
558
|
+
retirePoolKeyStatus,
|
|
559
|
+
init_api_keys,
|
|
534
560
|
getScriptRunExecutionArgs2,
|
|
535
561
|
updateTaskVcs2,
|
|
536
562
|
upsertAssetKeyMapping2,
|
|
@@ -737,7 +763,7 @@ import {
|
|
|
737
763
|
countScriptRunJournalSteps2,
|
|
738
764
|
countScriptRunJournalAgentTaskSteps2,
|
|
739
765
|
init_db3
|
|
740
|
-
} from "./cli-
|
|
766
|
+
} from "./cli-g8ka5j4j.js";
|
|
741
767
|
import {
|
|
742
768
|
PRIMARY_ROLE_NAMES2,
|
|
743
769
|
getUserGrant2,
|
|
@@ -748,22 +774,26 @@ import {
|
|
|
748
774
|
assertNotLastAdmin2,
|
|
749
775
|
setUserRoles2,
|
|
750
776
|
init_rbac_roles
|
|
751
|
-
} from "./cli-
|
|
752
|
-
import"./cli-
|
|
777
|
+
} from "./cli-a2rr0fmg.js";
|
|
778
|
+
import"./cli-03gg9pd1.js";
|
|
753
779
|
import {
|
|
754
780
|
normalizeModelKey
|
|
755
|
-
} from "./cli-
|
|
781
|
+
} from "./cli-5sckpqcx.js";
|
|
756
782
|
import {
|
|
757
783
|
upsertModelCatalogOverlay,
|
|
758
784
|
deleteModelCatalogOverlay,
|
|
759
785
|
loadModelsCatalog,
|
|
760
786
|
requestModelCatalogRefresh2
|
|
761
|
-
} from "./cli-
|
|
787
|
+
} from "./cli-aj8djyqt.js";
|
|
762
788
|
import {
|
|
763
789
|
AMP_ESTIMATE_MODELS,
|
|
764
790
|
ampBillsCacheWrites,
|
|
765
791
|
resolveAmpModel
|
|
766
|
-
} from "./cli-
|
|
792
|
+
} from "./cli-bqztfyve.js";
|
|
793
|
+
import {
|
|
794
|
+
workflowEventBus2,
|
|
795
|
+
init_event_bus
|
|
796
|
+
} from "./cli-kt907da6.js";
|
|
767
797
|
import {
|
|
768
798
|
automationIntegrationFixUrl,
|
|
769
799
|
preflightAutomation,
|
|
@@ -799,7 +829,7 @@ import {
|
|
|
799
829
|
generateEdges,
|
|
800
830
|
definitionNodeIds,
|
|
801
831
|
validateDefinition
|
|
802
|
-
} from "./cli-
|
|
832
|
+
} from "./cli-3fwqy71j.js";
|
|
803
833
|
import {
|
|
804
834
|
require_dist2,
|
|
805
835
|
isInvalidClientError,
|
|
@@ -879,14 +909,14 @@ import {
|
|
|
879
909
|
typecheckWithAmbient,
|
|
880
910
|
typecheckScript,
|
|
881
911
|
parseSkillContent
|
|
882
|
-
} from "./cli-
|
|
912
|
+
} from "./cli-3gfvmzht.js";
|
|
883
913
|
import {
|
|
884
914
|
buildAuthorizationUrl,
|
|
885
915
|
exchangeAuthorizationCode,
|
|
886
916
|
oauthAppRowToProviderConfig,
|
|
887
917
|
forceRefreshAuthorizationOrThrow,
|
|
888
918
|
forceRefreshTokenOrThrow
|
|
889
|
-
} from "./cli-
|
|
919
|
+
} from "./cli-kf4jree9.js";
|
|
890
920
|
import {
|
|
891
921
|
signalProcessGroup,
|
|
892
922
|
detachedProcessGroup,
|
|
@@ -914,31 +944,31 @@ import {
|
|
|
914
944
|
getTaskCitationsForTasks,
|
|
915
945
|
initialize,
|
|
916
946
|
ensure,
|
|
947
|
+
callSlackWithRetry2,
|
|
948
|
+
slackErrorCode2,
|
|
917
949
|
getSlackApp2,
|
|
918
950
|
startSlackApp2,
|
|
919
951
|
stopSlackApp2
|
|
920
|
-
} from "./cli-
|
|
921
|
-
import"./cli-
|
|
922
|
-
import"./cli-
|
|
952
|
+
} from "./cli-g20jjwt4.js";
|
|
953
|
+
import"./cli-gnsb1zxa.js";
|
|
954
|
+
import"./cli-v49fkghp.js";
|
|
923
955
|
import {
|
|
924
956
|
_fetchHolder,
|
|
925
957
|
CLIENT_ID,
|
|
958
|
+
decodeJwt,
|
|
926
959
|
exchangeAuthorizationCode2,
|
|
927
960
|
getAccountId,
|
|
961
|
+
extractChatgptPlanType,
|
|
928
962
|
deriveCodexKeySuffix,
|
|
929
963
|
MAX_CODEX_OAUTH_SLOT,
|
|
930
964
|
codexOAuthKeyForSlot,
|
|
931
965
|
loadAllCodexOAuthSlots,
|
|
932
966
|
getValidCodexOAuth
|
|
933
|
-
} from "./cli-
|
|
934
|
-
import {
|
|
935
|
-
workflowEventBus2,
|
|
936
|
-
init_event_bus
|
|
937
|
-
} from "./cli-dabehxhp.js";
|
|
967
|
+
} from "./cli-0z1xjzwa.js";
|
|
938
968
|
import {
|
|
939
969
|
retryFailedRun2,
|
|
940
970
|
cancelWorkflowRun2
|
|
941
|
-
} from "./cli-
|
|
971
|
+
} from "./cli-3aqd4jaa.js";
|
|
942
972
|
import {
|
|
943
973
|
duplicateGuardedQueryKey,
|
|
944
974
|
warnIfCorsAllowsAnyOrigin,
|
|
@@ -983,7 +1013,7 @@ import {
|
|
|
983
1013
|
bodyListTask,
|
|
984
1014
|
describeRequestRoute,
|
|
985
1015
|
route
|
|
986
|
-
} from "./cli-
|
|
1016
|
+
} from "./cli-art7c1zh.js";
|
|
987
1017
|
import {
|
|
988
1018
|
FilesError,
|
|
989
1019
|
normalizeFilesError,
|
|
@@ -1011,13 +1041,13 @@ import {
|
|
|
1011
1041
|
resolvePoolDelivery2,
|
|
1012
1042
|
createPoolAgent2,
|
|
1013
1043
|
init_db
|
|
1014
|
-
} from "./cli-
|
|
1044
|
+
} from "./cli-gf95q3bm.js";
|
|
1015
1045
|
import {
|
|
1016
1046
|
RATING_MODEL_MAX_LENGTH,
|
|
1017
1047
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
1018
1048
|
sanitizeReferencesSource
|
|
1019
1049
|
} from "./cli-3h26v7yj.js";
|
|
1020
|
-
import"./cli-
|
|
1050
|
+
import"./cli-737pyqxr.js";
|
|
1021
1051
|
import {
|
|
1022
1052
|
startPoolRouting,
|
|
1023
1053
|
stopPoolRouting,
|
|
@@ -1027,8 +1057,8 @@ import {
|
|
|
1027
1057
|
checkHeartbeatChecklist2,
|
|
1028
1058
|
runHeartbeatSweep2,
|
|
1029
1059
|
stopHeartbeat2
|
|
1030
|
-
} from "./cli-
|
|
1031
|
-
import"./cli-
|
|
1060
|
+
} from "./cli-emhjcj2y.js";
|
|
1061
|
+
import"./cli-d2dpf95n.js";
|
|
1032
1062
|
import {
|
|
1033
1063
|
import_websocket,
|
|
1034
1064
|
import_websocket_server
|
|
@@ -1037,18 +1067,18 @@ import {
|
|
|
1037
1067
|
runtimeSupervisorStatus,
|
|
1038
1068
|
startRuntimeSupervisor,
|
|
1039
1069
|
stopRuntimeSupervisor
|
|
1040
|
-
} from "./cli-
|
|
1070
|
+
} from "./cli-c2habvsf.js";
|
|
1041
1071
|
import"./cli-ns59dc6r.js";
|
|
1042
1072
|
import {
|
|
1043
1073
|
ACP_TARGET_IDS
|
|
1044
|
-
} from "./cli-
|
|
1074
|
+
} from "./cli-yvy48785.js";
|
|
1045
1075
|
import {
|
|
1046
1076
|
reasoningCapability,
|
|
1047
1077
|
supportedReasoningLevels
|
|
1048
|
-
} from "./cli-
|
|
1078
|
+
} from "./cli-c081bj3b.js";
|
|
1049
1079
|
import {
|
|
1050
1080
|
MAX_RATE_LIMIT_RESET_MS
|
|
1051
|
-
} from "./cli-
|
|
1081
|
+
} from "./cli-7enjwya9.js";
|
|
1052
1082
|
import {
|
|
1053
1083
|
isLeadChannelMonitoringEnabled,
|
|
1054
1084
|
ORG_IDENTITY_KEYS,
|
|
@@ -1056,15 +1086,16 @@ import {
|
|
|
1056
1086
|
SIMILARITY_THRESHOLD,
|
|
1057
1087
|
memoryRelevance,
|
|
1058
1088
|
isUnknownModelError,
|
|
1089
|
+
checkProviderPoolKey,
|
|
1059
1090
|
writeSkillsToFilesystem
|
|
1060
|
-
} from "./cli-
|
|
1091
|
+
} from "./cli-n7asmce6.js";
|
|
1061
1092
|
import {
|
|
1062
1093
|
inviteEmailToSharedOrg,
|
|
1063
1094
|
ensureAgentFsCredentialsForAgent
|
|
1064
|
-
} from "./cli-
|
|
1095
|
+
} from "./cli-6y51ryva.js";
|
|
1065
1096
|
import {
|
|
1066
1097
|
Anthropic
|
|
1067
|
-
} from "./cli-
|
|
1098
|
+
} from "./cli-rr7zx19j.js";
|
|
1068
1099
|
import {
|
|
1069
1100
|
isCodexOAuthConfigKey
|
|
1070
1101
|
} from "./cli-j4bwnpkm.js";
|
|
@@ -1093,6 +1124,7 @@ import {
|
|
|
1093
1124
|
InvalidRuntimeTokenError,
|
|
1094
1125
|
mintSessionToken,
|
|
1095
1126
|
mintRuntimeToken,
|
|
1127
|
+
isScriptRunToken,
|
|
1096
1128
|
revokeSessionToken,
|
|
1097
1129
|
AgentTokenExistsError,
|
|
1098
1130
|
mintAgentToken,
|
|
@@ -1100,7 +1132,7 @@ import {
|
|
|
1100
1132
|
revokeAgentTokens,
|
|
1101
1133
|
fingerprintApiKey,
|
|
1102
1134
|
init_users
|
|
1103
|
-
} from "./cli-
|
|
1135
|
+
} from "./cli-esakngh8.js";
|
|
1104
1136
|
import"./cli-v41kn3cd.js";
|
|
1105
1137
|
import"./cli-wgtk7xxr.js";
|
|
1106
1138
|
import"./cli-1f0gp9vz.js";
|
|
@@ -1228,6 +1260,7 @@ import {
|
|
|
1228
1260
|
ScriptRunListItemSchema,
|
|
1229
1261
|
ScriptRunJournalEntrySchema,
|
|
1230
1262
|
WorkflowRunStepSchema,
|
|
1263
|
+
WorkflowRunStepSlimSchema,
|
|
1231
1264
|
PromptTemplateSchema,
|
|
1232
1265
|
PromptTemplateHistorySchema,
|
|
1233
1266
|
ScriptScopeSchema,
|
|
@@ -1264,45 +1297,49 @@ import {
|
|
|
1264
1297
|
KvKeySchema,
|
|
1265
1298
|
KvEntrySchema,
|
|
1266
1299
|
init_types
|
|
1267
|
-
} from "./cli-
|
|
1300
|
+
} from "./cli-4rf0f5vg.js";
|
|
1268
1301
|
import {
|
|
1269
1302
|
IDENTITY_FIELD_BUDGETS,
|
|
1270
1303
|
IdentityFieldBudgetError,
|
|
1271
1304
|
init_identity_field_budget
|
|
1272
|
-
} from "./cli-
|
|
1273
|
-
import {
|
|
1274
|
-
getSlackConfiguration,
|
|
1275
|
-
init_config
|
|
1276
|
-
} from "./cli-qeaq3j6t.js";
|
|
1305
|
+
} from "./cli-hfeb68z4.js";
|
|
1277
1306
|
import {
|
|
1278
1307
|
isSteeringEnabled2,
|
|
1279
1308
|
init_steering_enabled
|
|
1280
1309
|
} from "./cli-4sydckyj.js";
|
|
1281
1310
|
import {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
getAllTemplateDefinitions,
|
|
1286
|
-
init_registry,
|
|
1287
|
-
resolveTemplate,
|
|
1288
|
-
init_resolver,
|
|
1289
|
-
init_session_templates
|
|
1290
|
-
} from "./cli-tx00c0h6.js";
|
|
1291
|
-
import {
|
|
1292
|
-
MODEL_SCOPED_WINDOWS,
|
|
1293
|
-
activeModelBlocks,
|
|
1294
|
-
init_model_rate_limit_windows
|
|
1295
|
-
} from "./cli-7421jzsw.js";
|
|
1311
|
+
getSlackConfiguration,
|
|
1312
|
+
init_config
|
|
1313
|
+
} from "./cli-qeaq3j6t.js";
|
|
1296
1314
|
import {
|
|
1297
1315
|
SUBSCRIPTION_PLANS_CHECKED_AT,
|
|
1298
1316
|
SUBSCRIPTION_PLANS,
|
|
1299
1317
|
isSubscriptionPlanId,
|
|
1300
1318
|
init_subscription_plans
|
|
1301
1319
|
} from "./cli-7akn6ze9.js";
|
|
1320
|
+
import {
|
|
1321
|
+
MODEL_SCOPED_WINDOWS,
|
|
1322
|
+
activeModelBlocks,
|
|
1323
|
+
init_model_rate_limit_windows,
|
|
1324
|
+
CREDENTIAL_POOL_VARS,
|
|
1325
|
+
splitCredentialPool,
|
|
1326
|
+
selectCredential,
|
|
1327
|
+
init_credentials
|
|
1328
|
+
} from "./cli-1tem6ns9.js";
|
|
1302
1329
|
import {
|
|
1303
1330
|
getOpenRouterAttributionHeaders,
|
|
1304
1331
|
init_openrouter_base_url
|
|
1305
1332
|
} from "./cli-dfyv0jdy.js";
|
|
1333
|
+
import {
|
|
1334
|
+
interpolate,
|
|
1335
|
+
init_template,
|
|
1336
|
+
getTemplateDefinition,
|
|
1337
|
+
getAllTemplateDefinitions,
|
|
1338
|
+
init_registry,
|
|
1339
|
+
resolveTemplate,
|
|
1340
|
+
init_resolver,
|
|
1341
|
+
init_session_templates
|
|
1342
|
+
} from "./cli-dqygeeh5.js";
|
|
1306
1343
|
import {
|
|
1307
1344
|
init_zod
|
|
1308
1345
|
} from "./cli-4chz1hye.js";
|
|
@@ -1337,7 +1374,7 @@ import {
|
|
|
1337
1374
|
import {
|
|
1338
1375
|
init_package,
|
|
1339
1376
|
package_default
|
|
1340
|
-
} from "./cli-
|
|
1377
|
+
} from "./cli-nn6vx2mq.js";
|
|
1341
1378
|
import {
|
|
1342
1379
|
realtimeBus,
|
|
1343
1380
|
init_bus
|
|
@@ -1365,12 +1402,15 @@ import {
|
|
|
1365
1402
|
findSecretsIn,
|
|
1366
1403
|
scrubObject,
|
|
1367
1404
|
registerVolatileSecret,
|
|
1405
|
+
registerEnvSecrets,
|
|
1368
1406
|
init_secret_scrubber
|
|
1369
|
-
} from "./cli-
|
|
1407
|
+
} from "./cli-708wdy32.js";
|
|
1370
1408
|
import {
|
|
1371
1409
|
isAlias,
|
|
1410
|
+
baseUrlEnvVar,
|
|
1411
|
+
providerForKeyVar,
|
|
1372
1412
|
init_src2
|
|
1373
|
-
} from "./cli-
|
|
1413
|
+
} from "./cli-gxee0bqa.js";
|
|
1374
1414
|
import {
|
|
1375
1415
|
__toESM
|
|
1376
1416
|
} from "./cli-242037k3.js";
|
|
@@ -1428,6 +1468,7 @@ init_db3();
|
|
|
1428
1468
|
|
|
1429
1469
|
// src/be/db-retention.ts
|
|
1430
1470
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1471
|
+
init_types();
|
|
1431
1472
|
init_env_flag();
|
|
1432
1473
|
init_secret_scrubber();
|
|
1433
1474
|
init_db3();
|
|
@@ -1472,6 +1513,19 @@ var DB_RETENTION_TABLES = [
|
|
|
1472
1513
|
metricsKey: "contextVersions",
|
|
1473
1514
|
initialBatchSize: 50,
|
|
1474
1515
|
maxBatchSize: 100
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
table: "script_runs",
|
|
1519
|
+
policy: "age",
|
|
1520
|
+
timeColumn: "startedAt",
|
|
1521
|
+
cutoffFormat: "sqliteDatetime",
|
|
1522
|
+
statusColumn: "status",
|
|
1523
|
+
terminalStatuses: TERMINAL_SCRIPT_RUN_STATUSES,
|
|
1524
|
+
keepWhenSet: "idempotencyKey",
|
|
1525
|
+
envKey: "SCRIPT_RUNS_RETENTION_DAYS",
|
|
1526
|
+
metricsKey: "scriptRuns",
|
|
1527
|
+
initialBatchSize: 100,
|
|
1528
|
+
maxBatchSize: 500
|
|
1475
1529
|
}
|
|
1476
1530
|
];
|
|
1477
1531
|
|
|
@@ -1605,13 +1659,26 @@ function sweepStatements(table, value, now) {
|
|
|
1605
1659
|
params: [value]
|
|
1606
1660
|
};
|
|
1607
1661
|
}
|
|
1608
|
-
const
|
|
1662
|
+
const iso = new Date(now.getTime() - value * DAY_MS).toISOString();
|
|
1663
|
+
const cutoff = "cutoffFormat" in table ? `${iso.slice(0, 10)} ${iso.slice(11, 19)}` : iso;
|
|
1664
|
+
const conditions = [];
|
|
1665
|
+
const params = [];
|
|
1666
|
+
if ("terminalStatuses" in table) {
|
|
1667
|
+
conditions.push(`${table.statusColumn} IN (${table.terminalStatuses.map(() => "?").join(", ")})`);
|
|
1668
|
+
params.push(...table.terminalStatuses);
|
|
1669
|
+
}
|
|
1670
|
+
conditions.push(`${table.timeColumn} < ?`);
|
|
1671
|
+
params.push(cutoff);
|
|
1672
|
+
if ("keepWhenSet" in table) {
|
|
1673
|
+
conditions.push(`rowid NOT IN (SELECT rowid FROM ${table.table} WHERE ${table.keepWhenSet} IS NOT NULL)`);
|
|
1674
|
+
}
|
|
1675
|
+
const where = conditions.join(" AND ");
|
|
1609
1676
|
return {
|
|
1610
|
-
backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${
|
|
1677
|
+
backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${where}`,
|
|
1611
1678
|
deleteSql: `DELETE FROM ${table.table} WHERE rowid IN (
|
|
1612
|
-
SELECT rowid FROM ${table.table} WHERE ${
|
|
1679
|
+
SELECT rowid FROM ${table.table} WHERE ${where} ORDER BY ${table.timeColumn} LIMIT ?
|
|
1613
1680
|
)`,
|
|
1614
|
-
params
|
|
1681
|
+
params
|
|
1615
1682
|
};
|
|
1616
1683
|
}
|
|
1617
1684
|
function dryRunEnabled(env = process.env) {
|
|
@@ -5448,6 +5515,33 @@ var reportRateLimit = route({
|
|
|
5448
5515
|
},
|
|
5449
5516
|
auth: { apiKey: true }
|
|
5450
5517
|
});
|
|
5518
|
+
var reportValidation = route({
|
|
5519
|
+
method: "post",
|
|
5520
|
+
path: "/api/keys/report-validation",
|
|
5521
|
+
pattern: ["api", "keys", "report-validation"],
|
|
5522
|
+
summary: "Record live validation results for a credential pool",
|
|
5523
|
+
tags: ["API Keys"],
|
|
5524
|
+
body: object2({
|
|
5525
|
+
keyType: string2(),
|
|
5526
|
+
keys: array2(object2({
|
|
5527
|
+
keyIndex: number2().int().min(0),
|
|
5528
|
+
keySuffix: string2().min(1).max(10),
|
|
5529
|
+
ok: boolean(),
|
|
5530
|
+
httpStatus: number2().int().optional()
|
|
5531
|
+
})).min(1).max(100),
|
|
5532
|
+
scope: string2().optional(),
|
|
5533
|
+
scopeId: string2().optional()
|
|
5534
|
+
}),
|
|
5535
|
+
responses: {
|
|
5536
|
+
200: { description: "Validation recorded", schema: successMessageSchema },
|
|
5537
|
+
400: { description: "Validation error" },
|
|
5538
|
+
401: { description: "Unauthorized" }
|
|
5539
|
+
},
|
|
5540
|
+
auth: { apiKey: true },
|
|
5541
|
+
rbac: {
|
|
5542
|
+
ungated: "worker credential telemetry, same posture as POST /api/keys/report-rate-limit"
|
|
5543
|
+
}
|
|
5544
|
+
});
|
|
5451
5545
|
var reportAuthFailure = route({
|
|
5452
5546
|
method: "post",
|
|
5453
5547
|
path: "/api/keys/report-auth-failure",
|
|
@@ -5565,6 +5659,7 @@ var getAvailable = route({
|
|
|
5565
5659
|
schema: object2({
|
|
5566
5660
|
success: literal2(true),
|
|
5567
5661
|
availableIndices: array2(number2().int()),
|
|
5662
|
+
rejectedIndices: array2(number2().int()).optional(),
|
|
5568
5663
|
totalKeys: number2().int(),
|
|
5569
5664
|
modelBlockedIndices: array2(number2().int()).optional(),
|
|
5570
5665
|
earliestModelResetAt: string2().nullable().optional(),
|
|
@@ -5599,6 +5694,8 @@ var ApiKeyStatusSchema = object2({
|
|
|
5599
5694
|
lastSeatMismatchModel: string2().nullable(),
|
|
5600
5695
|
consecutiveAuthFailures: number2().int(),
|
|
5601
5696
|
lastAuthFailureAt: string2().nullable(),
|
|
5697
|
+
lastValidationError: string2().nullable(),
|
|
5698
|
+
lastValidationFailedAt: string2().nullable(),
|
|
5602
5699
|
modelLimits: array2(object2({
|
|
5603
5700
|
model: string2(),
|
|
5604
5701
|
window: string2(),
|
|
@@ -5821,6 +5918,19 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
|
|
|
5821
5918
|
}
|
|
5822
5919
|
return true;
|
|
5823
5920
|
}
|
|
5921
|
+
if (reportValidation.match(req.method, pathSegments)) {
|
|
5922
|
+
const parsed = await reportValidation.parse(req, res, pathSegments, queryParams);
|
|
5923
|
+
if (!parsed)
|
|
5924
|
+
return true;
|
|
5925
|
+
const { keyType, keys, scope, scopeId } = parsed.body;
|
|
5926
|
+
try {
|
|
5927
|
+
await recordKeyValidation2(keyType, keys, scope, scopeId ?? null);
|
|
5928
|
+
reportValidation.respond(res, 200, { success: true, message: "Key validation recorded" });
|
|
5929
|
+
} catch (err) {
|
|
5930
|
+
jsonError(res, err instanceof Error ? err.message : "Failed to record key validation", 500);
|
|
5931
|
+
}
|
|
5932
|
+
return true;
|
|
5933
|
+
}
|
|
5824
5934
|
if (reportAuthFailure.match(req.method, pathSegments)) {
|
|
5825
5935
|
const parsed = await reportAuthFailure.parse(req, res, pathSegments, queryParams);
|
|
5826
5936
|
if (!parsed)
|
|
@@ -5882,6 +5992,7 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
|
|
|
5882
5992
|
getAvailable.respond(res, 200, {
|
|
5883
5993
|
success: true,
|
|
5884
5994
|
availableIndices: result.availableIndices,
|
|
5995
|
+
rejectedIndices: result.rejectedIndices,
|
|
5885
5996
|
totalKeys,
|
|
5886
5997
|
authFailureFence: result.authFailureFence,
|
|
5887
5998
|
...model !== undefined ? {
|
|
@@ -6044,6 +6155,7 @@ async function fillOrgLogoFromWebsite(website) {
|
|
|
6044
6155
|
// src/http/config.ts
|
|
6045
6156
|
init_rbac_roles();
|
|
6046
6157
|
init_swarm_config_guard();
|
|
6158
|
+
init_users();
|
|
6047
6159
|
init_rbac();
|
|
6048
6160
|
init_types();
|
|
6049
6161
|
init_request_auth_context();
|
|
@@ -6152,7 +6264,11 @@ async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
6152
6264
|
org_website: orgWebsite,
|
|
6153
6265
|
...orgDomain ? { org_domain: orgDomain } : {},
|
|
6154
6266
|
granted,
|
|
6155
|
-
...granted ? {
|
|
6267
|
+
...granted ? {
|
|
6268
|
+
contact_email: contactEmail,
|
|
6269
|
+
contact_function: reportedUserFunction(contactFunction),
|
|
6270
|
+
quote
|
|
6271
|
+
} : {},
|
|
6156
6272
|
changed_at: changedAt
|
|
6157
6273
|
}),
|
|
6158
6274
|
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
@@ -6513,6 +6629,28 @@ async function resolveSecretsRead(req, includeSecrets, resolvedScope) {
|
|
|
6513
6629
|
secretsNote: includeSecrets && scope === "none" ? SECRETS_FORCE_MASK_NOTE : ""
|
|
6514
6630
|
};
|
|
6515
6631
|
}
|
|
6632
|
+
async function scriptRunHeldConfigIds(req) {
|
|
6633
|
+
const auth = getRequestAuth(req);
|
|
6634
|
+
if (auth?.kind !== "agent" || auth.tokenKind !== "agent")
|
|
6635
|
+
return;
|
|
6636
|
+
if (!await isScriptRunToken(auth.tokenId))
|
|
6637
|
+
return;
|
|
6638
|
+
const held = stripApiOnlyKeys(await getResolvedConfig2(auth.agentId, undefined, { includeRepoSecrets: false }));
|
|
6639
|
+
return new Set(held.map((config) => config.id));
|
|
6640
|
+
}
|
|
6641
|
+
async function maskConfigRead(req, configs, includeSecrets) {
|
|
6642
|
+
const { effectiveIncludeSecrets, secretsNote } = await resolveSecretsRead(req, includeSecrets);
|
|
6643
|
+
const held = includeSecrets && !effectiveIncludeSecrets ? await scriptRunHeldConfigIds(req) : undefined;
|
|
6644
|
+
const reveal = (config) => effectiveIncludeSecrets || !!held?.has(config.id);
|
|
6645
|
+
const result = configs.map((config) => config.isSecret && !reveal(config) ? maskSecrets2([config])[0] : config);
|
|
6646
|
+
for (const config of result) {
|
|
6647
|
+
if (config.isSecret && config.value && reveal(config)) {
|
|
6648
|
+
registerVolatileSecret(config.value, `config:${config.key}`);
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
const anyMasked = result.some((config) => config.isSecret && !reveal(config));
|
|
6652
|
+
return { result, secretsNote: held && !anyMasked ? "" : secretsNote };
|
|
6653
|
+
}
|
|
6516
6654
|
async function ensureConfigAdmin(req, res, verb) {
|
|
6517
6655
|
return ensureHttpPermission(req, res, verb, verb === "config.write.any" ? "Writing swarm config requires the lead agent" : "Deleting swarm config requires the lead agent");
|
|
6518
6656
|
}
|
|
@@ -6757,13 +6895,9 @@ async function handleConfig(req, res, pathSegments, queryParams) {
|
|
|
6757
6895
|
jsonError(res, "Config not found", 404);
|
|
6758
6896
|
return true;
|
|
6759
6897
|
}
|
|
6760
|
-
const {
|
|
6761
|
-
const singleResult = effectiveIncludeSecrets ? config : maskSecrets2([config])[0];
|
|
6762
|
-
if (effectiveIncludeSecrets && singleResult.isSecret && singleResult.value) {
|
|
6763
|
-
registerVolatileSecret(singleResult.value, `config:${singleResult.key}`);
|
|
6764
|
-
}
|
|
6898
|
+
const { result, secretsNote } = await maskConfigRead(req, [config], includeSecrets);
|
|
6765
6899
|
getConfigById.respond(res, 200, {
|
|
6766
|
-
...
|
|
6900
|
+
...result[0],
|
|
6767
6901
|
...secretsNote ? { message: `Found 1 config(s).${secretsNote}` } : {}
|
|
6768
6902
|
});
|
|
6769
6903
|
return true;
|
|
@@ -6773,20 +6907,12 @@ async function handleConfig(req, res, pathSegments, queryParams) {
|
|
|
6773
6907
|
if (!parsed)
|
|
6774
6908
|
return true;
|
|
6775
6909
|
const includeSecrets = parsed.query.includeSecrets === "true";
|
|
6776
|
-
const { effectiveIncludeSecrets, secretsNote } = await resolveSecretsRead(req, includeSecrets);
|
|
6777
6910
|
const configs = stripApiOnlyKeys(await getSwarmConfigs2({
|
|
6778
6911
|
scope: parsed.query.scope || undefined,
|
|
6779
6912
|
scopeId: parsed.query.scopeId || undefined,
|
|
6780
6913
|
key: parsed.query.key
|
|
6781
6914
|
}));
|
|
6782
|
-
const listResult =
|
|
6783
|
-
if (effectiveIncludeSecrets) {
|
|
6784
|
-
for (const c of listResult) {
|
|
6785
|
-
if (c.isSecret && c.value) {
|
|
6786
|
-
registerVolatileSecret(c.value, `config:${c.key}`);
|
|
6787
|
-
}
|
|
6788
|
-
}
|
|
6789
|
-
}
|
|
6915
|
+
const { result: listResult, secretsNote } = await maskConfigRead(req, configs, includeSecrets);
|
|
6790
6916
|
listConfig.respond(res, 200, {
|
|
6791
6917
|
configs: listResult,
|
|
6792
6918
|
...secretsNote ? { message: `Found ${listResult.length} config(s).${secretsNote}` } : {}
|
|
@@ -7550,6 +7676,8 @@ async function approvalQuorumMet(approvers, votes) {
|
|
|
7550
7676
|
|
|
7551
7677
|
// src/http/assets.ts
|
|
7552
7678
|
init_zod();
|
|
7679
|
+
init_key();
|
|
7680
|
+
init_source_key();
|
|
7553
7681
|
init_asset_key_audit();
|
|
7554
7682
|
init_db3();
|
|
7555
7683
|
init_db2();
|
|
@@ -7809,6 +7937,16 @@ async function handleAssets(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
7809
7937
|
jsonError(res, await canReadSession2(req, myAgentId, task.id) ? "You can view this session but not move it." : SESSION_READ_DENIED2, 403);
|
|
7810
7938
|
return true;
|
|
7811
7939
|
}
|
|
7940
|
+
const destination = normalizeAssetKey(parsed.body.key);
|
|
7941
|
+
if (sourceOfKey(destination)) {
|
|
7942
|
+
const rootId = task.parentTaskId ? (await getSessionRoot(task.id))?.id : task.id;
|
|
7943
|
+
const root = rootId === task.id ? task : rootId ? await getTaskById2(rootId) : null;
|
|
7944
|
+
const sourceError = sourceMoveError(destination, root ?? { id: task.id });
|
|
7945
|
+
if (sourceError) {
|
|
7946
|
+
jsonError(res, sourceError, 400);
|
|
7947
|
+
return true;
|
|
7948
|
+
}
|
|
7949
|
+
}
|
|
7812
7950
|
const tasks = parsed.body.cascade ? await getRootTaskChain2(task.id) : [task];
|
|
7813
7951
|
for (const target of tasks) {
|
|
7814
7952
|
if (!await canMutateTaskNamespace(target, myAgentId, req)) {
|
|
@@ -8034,6 +8172,165 @@ async function handleBudgets(req, res, pathSegments, queryParams, _myAgentId) {
|
|
|
8034
8172
|
return false;
|
|
8035
8173
|
}
|
|
8036
8174
|
|
|
8175
|
+
// src/http/codex-oauth-accounts.ts
|
|
8176
|
+
init_zod();
|
|
8177
|
+
init_crypto();
|
|
8178
|
+
init_db3();
|
|
8179
|
+
init_api_keys();
|
|
8180
|
+
init_codex_auth_failure();
|
|
8181
|
+
var CodexAccountSchema = object2({
|
|
8182
|
+
slot: number2().int().min(0),
|
|
8183
|
+
configKey: string2(),
|
|
8184
|
+
legacy: boolean(),
|
|
8185
|
+
suffix: string2().nullable(),
|
|
8186
|
+
plan: string2().nullable(),
|
|
8187
|
+
email: string2().nullable(),
|
|
8188
|
+
status: _enum2(["ok", "needs_login", "unchecked"])
|
|
8189
|
+
});
|
|
8190
|
+
var CodexAccountsResponseSchema = object2({ accounts: array2(CodexAccountSchema) });
|
|
8191
|
+
var listAccounts = route({
|
|
8192
|
+
method: "get",
|
|
8193
|
+
path: "/api/codex-oauth/accounts",
|
|
8194
|
+
pattern: ["api", "codex-oauth", "accounts"],
|
|
8195
|
+
summary: "List stored Codex ChatGPT accounts",
|
|
8196
|
+
tags: ["Codex OAuth"],
|
|
8197
|
+
responses: {
|
|
8198
|
+
200: { description: "Stored account metadata", schema: CodexAccountsResponseSchema },
|
|
8199
|
+
403: { description: "Caller cannot read all secrets" }
|
|
8200
|
+
}
|
|
8201
|
+
});
|
|
8202
|
+
var deleteAccount = route({
|
|
8203
|
+
method: "delete",
|
|
8204
|
+
path: "/api/codex-oauth/accounts/{slot}",
|
|
8205
|
+
pattern: ["api", "codex-oauth", "accounts", null],
|
|
8206
|
+
summary: "Remove a stored Codex ChatGPT account",
|
|
8207
|
+
tags: ["Codex OAuth"],
|
|
8208
|
+
rbac: { permission: "config.delete.any" },
|
|
8209
|
+
params: object2({ slot: exports_coerce.number().int().min(0).max(MAX_CODEX_OAUTH_SLOT) }),
|
|
8210
|
+
responses: {
|
|
8211
|
+
200: { description: "Remaining accounts", schema: CodexAccountsResponseSchema },
|
|
8212
|
+
403: { description: "Config administration and permission to read all secrets required" },
|
|
8213
|
+
404: { description: "Account slot does not exist" }
|
|
8214
|
+
}
|
|
8215
|
+
});
|
|
8216
|
+
async function accountRows() {
|
|
8217
|
+
const rows = await getDbClient2().query("SELECT key, value, encrypted FROM swarm_config WHERE scope = 'global' AND (key = 'codex_oauth' OR key GLOB 'codex_oauth_[0-9]*')");
|
|
8218
|
+
const hasSlotZero = rows.some((row) => row.key === "codex_oauth_0");
|
|
8219
|
+
return rows.flatMap((row) => {
|
|
8220
|
+
if (row.key === "codex_oauth") {
|
|
8221
|
+
return hasSlotZero ? [] : [{ ...row, slot: 0, legacy: true }];
|
|
8222
|
+
}
|
|
8223
|
+
const match = /^codex_oauth_(0|[1-9]\d*)$/.exec(row.key);
|
|
8224
|
+
if (!match)
|
|
8225
|
+
return [];
|
|
8226
|
+
const slot = Number(match[1]);
|
|
8227
|
+
return slot <= MAX_CODEX_OAUTH_SLOT ? [{ ...row, slot, legacy: false }] : [];
|
|
8228
|
+
}).sort((a, b) => a.slot - b.slot);
|
|
8229
|
+
}
|
|
8230
|
+
var AccountCredentialsSchema = object2({
|
|
8231
|
+
access: string2().min(1),
|
|
8232
|
+
refresh: string2().min(1),
|
|
8233
|
+
expires: number2().finite(),
|
|
8234
|
+
accountId: string2().min(1)
|
|
8235
|
+
});
|
|
8236
|
+
function readCredentials(row) {
|
|
8237
|
+
try {
|
|
8238
|
+
const value = row.encrypted ? decryptSecret(row.value, getEncryptionKey()) : row.value;
|
|
8239
|
+
return AccountCredentialsSchema.parse(JSON.parse(value));
|
|
8240
|
+
} catch {
|
|
8241
|
+
return null;
|
|
8242
|
+
}
|
|
8243
|
+
}
|
|
8244
|
+
function accountSuffix(row) {
|
|
8245
|
+
const credentials = readCredentials(row);
|
|
8246
|
+
return credentials ? deriveCodexKeySuffix(credentials.access, credentials.accountId) : null;
|
|
8247
|
+
}
|
|
8248
|
+
async function accountsResponse() {
|
|
8249
|
+
const rows = await accountRows();
|
|
8250
|
+
const statuses = await getKeyStatuses2("CODEX_OAUTH", "global", null);
|
|
8251
|
+
const accounts = [];
|
|
8252
|
+
for (const row of rows) {
|
|
8253
|
+
const account = {
|
|
8254
|
+
slot: row.slot,
|
|
8255
|
+
configKey: row.key,
|
|
8256
|
+
legacy: row.legacy,
|
|
8257
|
+
suffix: null,
|
|
8258
|
+
plan: null,
|
|
8259
|
+
email: null,
|
|
8260
|
+
status: "needs_login"
|
|
8261
|
+
};
|
|
8262
|
+
const credentials = readCredentials(row);
|
|
8263
|
+
if (!credentials) {
|
|
8264
|
+
accounts.push(account);
|
|
8265
|
+
continue;
|
|
8266
|
+
}
|
|
8267
|
+
account.suffix = deriveCodexKeySuffix(credentials.access, credentials.accountId);
|
|
8268
|
+
account.plan = extractChatgptPlanType(credentials.access);
|
|
8269
|
+
const profile = decodeJwt(credentials.access)?.["https://api.openai.com/profile"];
|
|
8270
|
+
if (profile && typeof profile === "object" && "email" in profile) {
|
|
8271
|
+
account.email = typeof profile.email === "string" && profile.email ? profile.email : null;
|
|
8272
|
+
}
|
|
8273
|
+
const status = statuses.find((entry) => entry.keySuffix === account.suffix);
|
|
8274
|
+
const marker = await getKv2(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(account.suffix));
|
|
8275
|
+
const statusBenched = status && status.consecutiveAuthFailures >= CODEX_AUTH_FAILURE_BENCH_THRESHOLD && status.status === "rate_limited";
|
|
8276
|
+
account.status = marker || statusBenched ? "needs_login" : status ? "ok" : "unchecked";
|
|
8277
|
+
accounts.push(account);
|
|
8278
|
+
}
|
|
8279
|
+
return { accounts };
|
|
8280
|
+
}
|
|
8281
|
+
async function ensureSecretRead(req, res) {
|
|
8282
|
+
if (await requestSecretReadScope(req) === "all")
|
|
8283
|
+
return true;
|
|
8284
|
+
jsonError(res, "Reading Codex accounts requires access to all secrets", 403);
|
|
8285
|
+
return false;
|
|
8286
|
+
}
|
|
8287
|
+
async function handleCodexOAuthAccounts(req, res, pathSegments, queryParams) {
|
|
8288
|
+
if (listAccounts.match(req.method, pathSegments)) {
|
|
8289
|
+
const parsed = await listAccounts.parse(req, res, pathSegments, queryParams);
|
|
8290
|
+
if (!parsed)
|
|
8291
|
+
return true;
|
|
8292
|
+
if (!await ensureSecretRead(req, res))
|
|
8293
|
+
return true;
|
|
8294
|
+
listAccounts.respond(res, 200, await accountsResponse());
|
|
8295
|
+
return true;
|
|
8296
|
+
}
|
|
8297
|
+
if (deleteAccount.match(req.method, pathSegments)) {
|
|
8298
|
+
const parsed = await deleteAccount.parse(req, res, pathSegments, queryParams);
|
|
8299
|
+
if (!parsed)
|
|
8300
|
+
return true;
|
|
8301
|
+
if (!await ensureConfigAdmin(req, res, "config.delete.any"))
|
|
8302
|
+
return true;
|
|
8303
|
+
if (!await ensureSecretRead(req, res))
|
|
8304
|
+
return true;
|
|
8305
|
+
const deletedKey = await getDbClient2().transaction(async () => {
|
|
8306
|
+
const rows = await accountRows();
|
|
8307
|
+
const account = rows.find((row) => row.slot === parsed.params.slot);
|
|
8308
|
+
if (!account || !await deleteSwarmConfigByKey2("global", null, account.key))
|
|
8309
|
+
return null;
|
|
8310
|
+
const suffix = accountSuffix(account);
|
|
8311
|
+
if (suffix) {
|
|
8312
|
+
const remaining = rows.flatMap((row) => {
|
|
8313
|
+
const keySuffix = row === account ? null : accountSuffix(row);
|
|
8314
|
+
return keySuffix ? [{ keySuffix, keyIndex: row.slot }] : [];
|
|
8315
|
+
});
|
|
8316
|
+
await retirePoolKeyStatus("CODEX_OAUTH", suffix, remaining);
|
|
8317
|
+
if (!remaining.some((row) => row.keySuffix === suffix)) {
|
|
8318
|
+
await deleteKv2(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(suffix));
|
|
8319
|
+
}
|
|
8320
|
+
}
|
|
8321
|
+
return account.key;
|
|
8322
|
+
});
|
|
8323
|
+
if (deletedKey === null) {
|
|
8324
|
+
jsonError(res, "Codex account slot does not exist", 404);
|
|
8325
|
+
return true;
|
|
8326
|
+
}
|
|
8327
|
+
await runConfigWriteSideEffects("global", deletedKey, "");
|
|
8328
|
+
deleteAccount.respond(res, 200, await accountsResponse());
|
|
8329
|
+
return true;
|
|
8330
|
+
}
|
|
8331
|
+
return false;
|
|
8332
|
+
}
|
|
8333
|
+
|
|
8037
8334
|
// src/http/codex-oauth-device.ts
|
|
8038
8335
|
init_zod();
|
|
8039
8336
|
init_crypto();
|
|
@@ -8174,7 +8471,9 @@ var OnboardingSignalsSchema = object2({
|
|
|
8174
8471
|
provider: ProviderNameSchema,
|
|
8175
8472
|
state: _enum2(["unverified", "configured", "verified"]),
|
|
8176
8473
|
workers: number2().int().nonnegative(),
|
|
8177
|
-
verifiedWorkers: number2().int().nonnegative()
|
|
8474
|
+
verifiedWorkers: number2().int().nonnegative(),
|
|
8475
|
+
error: string2().nullable(),
|
|
8476
|
+
warning: string2().nullable()
|
|
8178
8477
|
})),
|
|
8179
8478
|
embeddings: object2({
|
|
8180
8479
|
configured: boolean(),
|
|
@@ -9099,6 +9398,7 @@ function sentTaskId(thread, replies, serviceUserId) {
|
|
|
9099
9398
|
// src/comb/review-batch.ts
|
|
9100
9399
|
init_templates();
|
|
9101
9400
|
var REVIEW_BATCH_MAX = 50;
|
|
9401
|
+
var REVIEW_NOTE_MAX = 4000;
|
|
9102
9402
|
var REVIEW_BATCH_READ_CONCURRENCY = 5;
|
|
9103
9403
|
var SENT_KV_NAMESPACE = "comb:sent";
|
|
9104
9404
|
var PENDING_CLAIM_MS = 5 * 60000;
|
|
@@ -9129,6 +9429,9 @@ async function sendReviewBatch(input, deps = {}) {
|
|
|
9129
9429
|
if (ids.length === 0 || ids.length > REVIEW_BATCH_MAX) {
|
|
9130
9430
|
throw new ReviewBatchError(400, `Send between 1 and ${REVIEW_BATCH_MAX} comments`);
|
|
9131
9431
|
}
|
|
9432
|
+
if ((input.note?.length ?? 0) > REVIEW_NOTE_MAX) {
|
|
9433
|
+
throw new ReviewBatchError(400, `The note is longer than ${REVIEW_NOTE_MAX} characters`);
|
|
9434
|
+
}
|
|
9132
9435
|
const agentFs = combAgentFs();
|
|
9133
9436
|
if (!agentFs)
|
|
9134
9437
|
throw new ReviewBatchError(503, "agent-fs is not set up for this swarm");
|
|
@@ -9162,6 +9465,7 @@ async function sendReviewBatch(input, deps = {}) {
|
|
|
9162
9465
|
}
|
|
9163
9466
|
const wonIds = won.map((read) => read.id);
|
|
9164
9467
|
let taskId = null;
|
|
9468
|
+
let leadState = "none";
|
|
9165
9469
|
if (won.length > 0) {
|
|
9166
9470
|
try {
|
|
9167
9471
|
const text = await renderTaskText(input, won);
|
|
@@ -9172,6 +9476,7 @@ async function sendReviewBatch(input, deps = {}) {
|
|
|
9172
9476
|
]);
|
|
9173
9477
|
}
|
|
9174
9478
|
const lead = await getLeadAgent2();
|
|
9479
|
+
leadState = !lead ? "none" : lead.status === "offline" ? "offline" : "online";
|
|
9175
9480
|
const task = await createTask(text, {
|
|
9176
9481
|
agentId: lead?.id ?? "",
|
|
9177
9482
|
routingReason: lead ? "skill" : undefined,
|
|
@@ -9208,7 +9513,7 @@ async function sendReviewBatch(input, deps = {}) {
|
|
|
9208
9513
|
if (taskId === null && repaired.length === 0) {
|
|
9209
9514
|
throw new ReviewBatchError(409, "Nothing to send", skipped);
|
|
9210
9515
|
}
|
|
9211
|
-
return { taskId, sent: wonIds, skipped, repaired };
|
|
9516
|
+
return taskId === null ? { taskId, sent: wonIds, skipped, repaired } : { taskId, sent: wonIds, skipped, repaired, lead: leadState };
|
|
9212
9517
|
}
|
|
9213
9518
|
async function mapLimited(items, limit, fn) {
|
|
9214
9519
|
const results = new Array(items.length);
|
|
@@ -9353,6 +9658,7 @@ async function renderTaskText(input, reads) {
|
|
|
9353
9658
|
requested_by: await requesterLabel(input.requestedByUserId),
|
|
9354
9659
|
org_id: input.orgId,
|
|
9355
9660
|
drive_id: input.driveId,
|
|
9661
|
+
note_block: noteBlock(input.note),
|
|
9356
9662
|
comments_block: blocks.join(`
|
|
9357
9663
|
`)
|
|
9358
9664
|
});
|
|
@@ -9367,6 +9673,13 @@ function lineRange(comment) {
|
|
|
9367
9673
|
const end = comment.lineEnd ?? comment.lineStart;
|
|
9368
9674
|
return end === comment.lineStart ? `line ${comment.lineStart}` : `lines ${comment.lineStart}-${end}`;
|
|
9369
9675
|
}
|
|
9676
|
+
function noteBlock(note) {
|
|
9677
|
+
const text = note?.trim();
|
|
9678
|
+
return text ? `
|
|
9679
|
+
Note from the sender, about all the comments:
|
|
9680
|
+
${fenced(text)}
|
|
9681
|
+
` : "";
|
|
9682
|
+
}
|
|
9370
9683
|
function fenced(text) {
|
|
9371
9684
|
const longest = (text.match(/`+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
|
|
9372
9685
|
const fence = "`".repeat(Math.max(3, longest + 1));
|
|
@@ -9407,7 +9720,8 @@ var resultSchema = object2({
|
|
|
9407
9720
|
taskId: string2().nullable(),
|
|
9408
9721
|
sent: array2(string2()),
|
|
9409
9722
|
skipped: array2(skippedSchema),
|
|
9410
|
-
repaired: array2(object2({ id: string2(), taskId: string2() }))
|
|
9723
|
+
repaired: array2(object2({ id: string2(), taskId: string2() })),
|
|
9724
|
+
lead: _enum2(["online", "offline", "none"]).optional()
|
|
9411
9725
|
});
|
|
9412
9726
|
var batchErrorSchema = object2({ error: string2(), skipped: array2(skippedSchema) });
|
|
9413
9727
|
function isDrivePath(path) {
|
|
@@ -9418,13 +9732,14 @@ var reviewBatchRoute = route({
|
|
|
9418
9732
|
path: "/api/comb/review-batches",
|
|
9419
9733
|
pattern: ["api", "comb", "review-batches"],
|
|
9420
9734
|
summary: "Send agent-fs comments to the swarm as one lead task",
|
|
9421
|
-
description: "Comb's 'Send to swarm'. The server reads each comment again from agent-fs with its bootstrap key, skips replies, resolved comments, and comments already sent, and creates ONE task for the lead. Each sent comment gets a `[comb:sent task=<id>]` reply from the swarm service account. A comment is sent at most once. When an earlier send lost its reply, the batch posts that reply again (`repaired`). Answers 404 while COMB_ENABLED is off.",
|
|
9735
|
+
description: "Comb's 'Send to swarm'. The server reads each comment again from agent-fs with its bootstrap key, skips replies, resolved comments, and comments already sent, and creates ONE task for the lead. Each sent comment gets a `[comb:sent task=<id>]` reply from the swarm service account. A comment is sent at most once. An optional `note` from the sender goes into the task text. When an earlier send lost its reply, the batch posts that reply again (`repaired`). Answers 404 while COMB_ENABLED is off.",
|
|
9422
9736
|
tags: ["Comb"],
|
|
9423
9737
|
body: object2({
|
|
9424
9738
|
orgId: string2().min(1),
|
|
9425
9739
|
driveId: string2().min(1),
|
|
9426
9740
|
commentIds: array2(uuid()).min(1).max(REVIEW_BATCH_MAX),
|
|
9427
|
-
scopePath: string2().min(1).max(1024).refine(isDrivePath, "scopePath must start with '/' and have no '.' or '..' segment")
|
|
9741
|
+
scopePath: string2().min(1).max(1024).refine(isDrivePath, "scopePath must start with '/' and have no '.' or '..' segment"),
|
|
9742
|
+
note: string2().max(REVIEW_NOTE_MAX).optional()
|
|
9428
9743
|
}),
|
|
9429
9744
|
responses: {
|
|
9430
9745
|
200: {
|
|
@@ -9814,16 +10129,16 @@ declare module "swarm-extension" {
|
|
|
9814
10129
|
| "schedule"
|
|
9815
10130
|
| "slack"
|
|
9816
10131
|
| "agentmail"
|
|
9817
|
-
| "mcp"
|
|
9818
|
-
| "api"
|
|
9819
|
-
| "ui"
|
|
9820
10132
|
| "github"
|
|
9821
10133
|
| "gitlab"
|
|
9822
10134
|
| "azure-devops"
|
|
9823
10135
|
| "bitbucket"
|
|
9824
|
-
| "system"
|
|
9825
10136
|
| "linear"
|
|
9826
10137
|
| "jira"
|
|
10138
|
+
| "mcp"
|
|
10139
|
+
| "api"
|
|
10140
|
+
| "ui"
|
|
10141
|
+
| "system"
|
|
9827
10142
|
| "comb"
|
|
9828
10143
|
| "chat"
|
|
9829
10144
|
| undefined;
|
|
@@ -9932,16 +10247,16 @@ declare module "swarm-extension" {
|
|
|
9932
10247
|
| "schedule"
|
|
9933
10248
|
| "slack"
|
|
9934
10249
|
| "agentmail"
|
|
9935
|
-
| "mcp"
|
|
9936
|
-
| "api"
|
|
9937
|
-
| "ui"
|
|
9938
10250
|
| "github"
|
|
9939
10251
|
| "gitlab"
|
|
9940
10252
|
| "azure-devops"
|
|
9941
10253
|
| "bitbucket"
|
|
9942
|
-
| "system"
|
|
9943
10254
|
| "linear"
|
|
9944
10255
|
| "jira"
|
|
10256
|
+
| "mcp"
|
|
10257
|
+
| "api"
|
|
10258
|
+
| "ui"
|
|
10259
|
+
| "system"
|
|
9945
10260
|
| "comb"
|
|
9946
10261
|
| "chat";
|
|
9947
10262
|
tags: string[];
|
|
@@ -10206,6 +10521,45 @@ declare module "swarm-extension" {
|
|
|
10206
10521
|
description: string;
|
|
10207
10522
|
origin: TaskCreateOrigin;
|
|
10208
10523
|
requestInfo?: RequestInfo;
|
|
10524
|
+
/** Slack ingress metadata; not persisted or writable through modify. */
|
|
10525
|
+
slack?: {
|
|
10526
|
+
trigger: "mention" | "thread-buffer";
|
|
10527
|
+
messages: {
|
|
10528
|
+
ts: string;
|
|
10529
|
+
userId: string;
|
|
10530
|
+
text: string;
|
|
10531
|
+
}[];
|
|
10532
|
+
};
|
|
10533
|
+
}
|
|
10534
|
+
/** A pre.task.create hook blocked a task before it was created. */
|
|
10535
|
+
export interface TaskBlockedEvent {
|
|
10536
|
+
/** The extension that blocked, or whose model/agent rewrite was rejected. */
|
|
10537
|
+
extension: {
|
|
10538
|
+
id: string;
|
|
10539
|
+
name: string;
|
|
10540
|
+
};
|
|
10541
|
+
/** The scrubbed block reason. */
|
|
10542
|
+
reason: string;
|
|
10543
|
+
origin: TaskCreateOrigin;
|
|
10544
|
+
source?: AgentTask["source"];
|
|
10545
|
+
requester: {
|
|
10546
|
+
userId?: string;
|
|
10547
|
+
agentId?: string;
|
|
10548
|
+
slackUserId?: string;
|
|
10549
|
+
};
|
|
10550
|
+
context?: {
|
|
10551
|
+
contextKey?: string;
|
|
10552
|
+
scheduleId?: string;
|
|
10553
|
+
workflowRunId?: string;
|
|
10554
|
+
workflowRunStepId?: string;
|
|
10555
|
+
parentTaskId?: string;
|
|
10556
|
+
vcsRepo?: string;
|
|
10557
|
+
vcsNumber?: number;
|
|
10558
|
+
slackChannelId?: string;
|
|
10559
|
+
slackThreadTs?: string;
|
|
10560
|
+
};
|
|
10561
|
+
/** The original task description, scrubbed and cut to 500 characters. */
|
|
10562
|
+
description: string;
|
|
10209
10563
|
}
|
|
10210
10564
|
export type TaskCreateModify = Partial<
|
|
10211
10565
|
Pick<
|
|
@@ -10509,6 +10863,11 @@ declare module "swarm-extension" {
|
|
|
10509
10863
|
modify: never;
|
|
10510
10864
|
result: void;
|
|
10511
10865
|
};
|
|
10866
|
+
"post.task.blocked": {
|
|
10867
|
+
event: TaskBlockedEvent;
|
|
10868
|
+
modify: never;
|
|
10869
|
+
result: void;
|
|
10870
|
+
};
|
|
10512
10871
|
"post.task.completed": {
|
|
10513
10872
|
event: TaskCompletedEvent;
|
|
10514
10873
|
modify: never;
|
|
@@ -13600,6 +13959,7 @@ async function buildFleetBenchmarkResponse(now = new Date) {
|
|
|
13600
13959
|
const team = _enum2(COMPANY_TEAM_SIZES).safeParse(teamSize);
|
|
13601
13960
|
const use = _enum2(COMPANY_USE_CASES).safeParse(useCase);
|
|
13602
13961
|
const peerGroup = normalizeOrgWebsite(website) && team.success && use.success ? { teamSize: team.data, useCase: use.data } : null;
|
|
13962
|
+
const proxyPeerGroup = peerGroup && reportedUseCase(peerGroup.useCase) ? peerGroup : null;
|
|
13603
13963
|
const empty = {
|
|
13604
13964
|
level: peerGroup ? "full" : "basic",
|
|
13605
13965
|
peerGroup: null,
|
|
@@ -13626,7 +13986,7 @@ async function buildFleetBenchmarkResponse(now = new Date) {
|
|
|
13626
13986
|
return { ...empty, state: "telemetry_off", local };
|
|
13627
13987
|
if (finishedTasks < FLEET_MIN_FINISHED_TASKS)
|
|
13628
13988
|
return { ...empty, state: "not_enough_tasks", local };
|
|
13629
|
-
const fleet = await fleetBenchmarks(now.getTime(),
|
|
13989
|
+
const fleet = await fleetBenchmarks(now.getTime(), proxyPeerGroup);
|
|
13630
13990
|
const responsePeerGroup = peerGroup && fleet?.peer_group ? {
|
|
13631
13991
|
teamSize: fleet.peer_group.team_size,
|
|
13632
13992
|
useCase: fleet.peer_group.use_case,
|
|
@@ -14683,6 +15043,9 @@ function buildSlackManifest(name) {
|
|
|
14683
15043
|
return manifest;
|
|
14684
15044
|
}
|
|
14685
15045
|
|
|
15046
|
+
// src/http/integrations.ts
|
|
15047
|
+
init_credentials();
|
|
15048
|
+
|
|
14686
15049
|
// src/http/config-values.ts
|
|
14687
15050
|
init_db3();
|
|
14688
15051
|
async function resolveConfigValue(key) {
|
|
@@ -14857,7 +15220,7 @@ function createIntegrationsHandler(deps = {}) {
|
|
|
14857
15220
|
return true;
|
|
14858
15221
|
}
|
|
14859
15222
|
try {
|
|
14860
|
-
const client = buildClient(apiKey);
|
|
15223
|
+
const client = buildClient(selectCredential(apiKey, undefined, "ANTHROPIC_API_KEY").selected);
|
|
14861
15224
|
const agent = await client.beta.agents.retrieve(agentId);
|
|
14862
15225
|
const modelId = typeof agent.model === "string" ? agent.model : agent.model?.id ?? null;
|
|
14863
15226
|
claudeManagedTestRoute.respond(res, 200, {
|
|
@@ -15134,8 +15497,8 @@ function authorizeWrite(namespace, ctx) {
|
|
|
15134
15497
|
return null;
|
|
15135
15498
|
}
|
|
15136
15499
|
function authorizeRead(namespace, ctx) {
|
|
15137
|
-
const
|
|
15138
|
-
return
|
|
15500
|
+
const readErr = privateNamespaceError(namespace) ?? mcpOverflowAuthError(namespace, ctx.callerAgentId);
|
|
15501
|
+
return readErr ? { status: 403, message: readErr } : null;
|
|
15139
15502
|
}
|
|
15140
15503
|
function encodeValueOrError(res, value, valueType) {
|
|
15141
15504
|
try {
|
|
@@ -21537,6 +21900,7 @@ init_db3();
|
|
|
21537
21900
|
init_memory();
|
|
21538
21901
|
init_constants();
|
|
21539
21902
|
init_types();
|
|
21903
|
+
init_credentials();
|
|
21540
21904
|
init_openrouter_base_url();
|
|
21541
21905
|
|
|
21542
21906
|
// src/http/status.ts
|
|
@@ -21605,6 +21969,7 @@ var StatusIdentitySchema = object2({
|
|
|
21605
21969
|
var StatusActivitySchema = object2({
|
|
21606
21970
|
agents_online: number2().int().nonnegative(),
|
|
21607
21971
|
leads_online: number2().int().nonnegative(),
|
|
21972
|
+
leads_ready: number2().int().nonnegative(),
|
|
21608
21973
|
recent_tasks_count: number2().int().nonnegative()
|
|
21609
21974
|
});
|
|
21610
21975
|
var StatusCombSchema = object2({
|
|
@@ -21985,7 +22350,7 @@ async function buildSetup(automationSetup) {
|
|
|
21985
22350
|
await firstTaskMilestone()
|
|
21986
22351
|
];
|
|
21987
22352
|
}
|
|
21988
|
-
function computeHealth(setup) {
|
|
22353
|
+
function computeHealth(setup, readyLeads) {
|
|
21989
22354
|
const byId = new Map(setup.map((m) => [m.id, m]));
|
|
21990
22355
|
const harness = byId.get("harness");
|
|
21991
22356
|
const workers = byId.get("workers");
|
|
@@ -21993,6 +22358,8 @@ function computeHealth(setup) {
|
|
|
21993
22358
|
return "broken";
|
|
21994
22359
|
if (!workers || workers.state === "unverified")
|
|
21995
22360
|
return "broken";
|
|
22361
|
+
if (readyLeads === 0)
|
|
22362
|
+
return "degraded";
|
|
21996
22363
|
if (harness.state === "configured")
|
|
21997
22364
|
return "degraded";
|
|
21998
22365
|
for (const id of ["slack", "github", "linear", "jira"]) {
|
|
@@ -22010,12 +22377,13 @@ async function buildStatusPayload() {
|
|
|
22010
22377
|
const toStatus = ({ failureReason: _, ...status }) => status;
|
|
22011
22378
|
const automations = automationInputs.map((automation) => toStatus(preflightAutomation(automation, automationSetup))).sort((a, b) => a.name.localeCompare(b.name) || a.kind.localeCompare(b.kind));
|
|
22012
22379
|
const activity = await getInstanceActivity2();
|
|
22380
|
+
const readyLeads = (await getReadyAgentCounts2()).leads;
|
|
22013
22381
|
const instance = await getInstanceFeedbackSignals();
|
|
22014
22382
|
return {
|
|
22015
22383
|
runtime_pools: { enabled: isRuntimePoolsEnabled(), supervisor: runtimeSupervisorStatus() },
|
|
22016
22384
|
identity: buildIdentity(),
|
|
22017
22385
|
setup,
|
|
22018
|
-
activity,
|
|
22386
|
+
activity: { ...activity, leads_ready: readyLeads },
|
|
22019
22387
|
agent_fs: {
|
|
22020
22388
|
configured: !!process.env.AGENT_FS_API_URL,
|
|
22021
22389
|
base_url: process.env.AGENT_FS_API_URL ?? null,
|
|
@@ -22023,7 +22391,7 @@ async function buildStatusPayload() {
|
|
|
22023
22391
|
comb: getCombStatus(await combServiceUserId)
|
|
22024
22392
|
},
|
|
22025
22393
|
automations,
|
|
22026
|
-
health: computeHealth(setup),
|
|
22394
|
+
health: computeHealth(setup, readyLeads),
|
|
22027
22395
|
telemetry: { enabled: isTelemetryEnabled() },
|
|
22028
22396
|
instance
|
|
22029
22397
|
};
|
|
@@ -22058,7 +22426,7 @@ var getStatus = route({
|
|
|
22058
22426
|
path: "/status",
|
|
22059
22427
|
pattern: ["status"],
|
|
22060
22428
|
summary: "Identity + setup readiness + live activity for the swarm dashboard",
|
|
22061
|
-
description: "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; setup milestones each emit `unverified | configured | verified`; automations report `running | needs_setup` from the same runtime preflight used at dispatch; activity counts agents alive in the last 5 min and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set, plus the Comb settings (COMB_ENABLED, the browser-facing agent-fs URL, the shared org and drive ids, and the agent-fs user id of the swarm service account); telemetry reports the effective ANONYMIZED_TELEMETRY opt-out state.",
|
|
22429
|
+
description: "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; setup milestones each emit `unverified | configured | verified`; automations report `running | needs_setup` from the same runtime preflight used at dispatch; activity counts agents alive in the last 5 min, leads that can take work (status idle or busy), and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set, plus the Comb settings (COMB_ENABLED, the browser-facing agent-fs URL, the shared org and drive ids, and the agent-fs user id of the swarm service account); telemetry reports the effective ANONYMIZED_TELEMETRY opt-out state.",
|
|
22062
22430
|
tags: ["Status"],
|
|
22063
22431
|
responses: {
|
|
22064
22432
|
200: { description: "Status payload", schema: StatusResponseSchema },
|
|
@@ -22131,11 +22499,14 @@ async function buildSignals(state) {
|
|
|
22131
22499
|
if (!provider.success)
|
|
22132
22500
|
continue;
|
|
22133
22501
|
const rollup = await rollupCredStatusForProvider(provider.data);
|
|
22502
|
+
const live = rollup.latestLiveTest;
|
|
22134
22503
|
providers.push({
|
|
22135
22504
|
provider: provider.data,
|
|
22136
22505
|
state: rollup.state,
|
|
22137
22506
|
workers: rollup.workers,
|
|
22138
|
-
verifiedWorkers: rollup.verifiedWorkers
|
|
22507
|
+
verifiedWorkers: rollup.verifiedWorkers,
|
|
22508
|
+
error: live && !live.ok ? live.error ?? null : null,
|
|
22509
|
+
warning: live?.ok ? live.warning ?? null : null
|
|
22139
22510
|
});
|
|
22140
22511
|
}
|
|
22141
22512
|
const integrations = await getAutomationSetupStates();
|
|
@@ -22281,7 +22652,7 @@ async function handleMemoryProbe(body) {
|
|
|
22281
22652
|
const canReuseKey = reuseHost === undefined || endpoint.hostname === reuseHost;
|
|
22282
22653
|
const reusedKey = !explicitKey && body.reuseKey && canReuseKey ? process.env[body.reuseKey] : undefined;
|
|
22283
22654
|
const implicitKey = body.preset === "existing" ? process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY : undefined;
|
|
22284
|
-
const apiKey = explicitKey ?? reusedKey ?? implicitKey;
|
|
22655
|
+
const apiKey = splitCredentialPool(explicitKey ?? reusedKey ?? implicitKey ?? "")[0];
|
|
22285
22656
|
if (!apiKey) {
|
|
22286
22657
|
return {
|
|
22287
22658
|
ok: false,
|
|
@@ -22741,6 +23112,7 @@ var listTasks = route({
|
|
|
22741
23112
|
status: string2().optional(),
|
|
22742
23113
|
agentId: string2().optional(),
|
|
22743
23114
|
scheduleId: string2().optional(),
|
|
23115
|
+
workflowRunId: string2().uuid().optional(),
|
|
22744
23116
|
key: AssetKeySchema.optional(),
|
|
22745
23117
|
keyPrefix: AssetKeySchema.optional(),
|
|
22746
23118
|
search: string2().optional(),
|
|
@@ -23343,6 +23715,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
23343
23715
|
status,
|
|
23344
23716
|
agentId: parsed.query.agentId || undefined,
|
|
23345
23717
|
scheduleId: parsed.query.scheduleId || undefined,
|
|
23718
|
+
workflowRunId: parsed.query.workflowRunId,
|
|
23346
23719
|
key: parsed.query.key,
|
|
23347
23720
|
keyPrefix: parsed.query.keyPrefix,
|
|
23348
23721
|
search: parsed.query.search || undefined,
|
|
@@ -27249,6 +27622,298 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
27249
27622
|
return false;
|
|
27250
27623
|
}
|
|
27251
27624
|
|
|
27625
|
+
// src/http/pool-keys.ts
|
|
27626
|
+
init_src2();
|
|
27627
|
+
init_zod();
|
|
27628
|
+
init_db3();
|
|
27629
|
+
init_api_keys();
|
|
27630
|
+
init_swarm_config_guard();
|
|
27631
|
+
init_credentials();
|
|
27632
|
+
init_secret_scrubber();
|
|
27633
|
+
var PoolKeyStatusSchema = _enum2(["ok", "rejected", "rate_limited", "unchecked"]);
|
|
27634
|
+
var PoolKeySchema = object2({
|
|
27635
|
+
index: number2().int().min(0),
|
|
27636
|
+
suffix: string2(),
|
|
27637
|
+
status: PoolKeyStatusSchema,
|
|
27638
|
+
error: string2().nullable(),
|
|
27639
|
+
checkedAt: string2().nullable(),
|
|
27640
|
+
rateLimitedUntil: string2().nullable()
|
|
27641
|
+
});
|
|
27642
|
+
var PoolKeysResponseSchema = object2({
|
|
27643
|
+
key: string2(),
|
|
27644
|
+
source: _enum2(["stored", "env", "none"]),
|
|
27645
|
+
readOnly: boolean(),
|
|
27646
|
+
keys: array2(PoolKeySchema)
|
|
27647
|
+
});
|
|
27648
|
+
var PoolKeyCheckResultSchema = _enum2(["verified", "rejected", "not_tested"]);
|
|
27649
|
+
var PoolKeyCheckSchema = object2({
|
|
27650
|
+
suffix: string2(),
|
|
27651
|
+
result: PoolKeyCheckResultSchema,
|
|
27652
|
+
httpStatus: number2().nullable(),
|
|
27653
|
+
error: string2().nullable()
|
|
27654
|
+
});
|
|
27655
|
+
var poolVar = string2().refine((key) => key !== "CODEX_OAUTH" && CREDENTIAL_POOL_VARS.includes(key), "Choose a credential pool variable.");
|
|
27656
|
+
var getPoolKeys = route({
|
|
27657
|
+
method: "get",
|
|
27658
|
+
path: "/api/config/pool-keys",
|
|
27659
|
+
pattern: ["api", "config", "pool-keys"],
|
|
27660
|
+
summary: "List credential pool suffixes and status",
|
|
27661
|
+
tags: ["Config"],
|
|
27662
|
+
query: object2({ key: poolVar }),
|
|
27663
|
+
responses: {
|
|
27664
|
+
200: { description: "Credential pool", schema: PoolKeysResponseSchema },
|
|
27665
|
+
400: { description: "Invalid pool variable" },
|
|
27666
|
+
403: { description: "Secret read permission required" }
|
|
27667
|
+
}
|
|
27668
|
+
});
|
|
27669
|
+
var addPoolKeys = route({
|
|
27670
|
+
method: "post",
|
|
27671
|
+
path: "/api/config/pool-keys",
|
|
27672
|
+
pattern: ["api", "config", "pool-keys"],
|
|
27673
|
+
summary: "Test and append keys to a credential pool",
|
|
27674
|
+
tags: ["Config"],
|
|
27675
|
+
rbac: { permission: "config.write.any" },
|
|
27676
|
+
body: object2({
|
|
27677
|
+
key: poolVar,
|
|
27678
|
+
value: string2(),
|
|
27679
|
+
baseUrl: string2().nullable().optional().describe("Base URL for the check only. Null tests the provider default. Omit to use the stored URL.")
|
|
27680
|
+
}),
|
|
27681
|
+
responses: {
|
|
27682
|
+
200: {
|
|
27683
|
+
description: "Updated credential pool and checks",
|
|
27684
|
+
schema: PoolKeysResponseSchema.extend({ checks: array2(PoolKeyCheckSchema) })
|
|
27685
|
+
},
|
|
27686
|
+
400: { description: "Invalid key" },
|
|
27687
|
+
403: { description: "Config administration and permission to read all secrets required" },
|
|
27688
|
+
409: { description: "Duplicate key or deployment env pool" },
|
|
27689
|
+
422: {
|
|
27690
|
+
description: "Provider rejected a key. Nothing was saved.",
|
|
27691
|
+
schema: object2({ error: string2(), checks: array2(PoolKeyCheckSchema) })
|
|
27692
|
+
}
|
|
27693
|
+
}
|
|
27694
|
+
});
|
|
27695
|
+
var deletePoolKey = route({
|
|
27696
|
+
method: "delete",
|
|
27697
|
+
path: "/api/config/pool-keys",
|
|
27698
|
+
pattern: ["api", "config", "pool-keys"],
|
|
27699
|
+
summary: "Remove one credential pool member",
|
|
27700
|
+
tags: ["Config"],
|
|
27701
|
+
rbac: { permission: "config.delete.any" },
|
|
27702
|
+
query: object2({
|
|
27703
|
+
key: poolVar,
|
|
27704
|
+
index: exports_coerce.number().int().min(0),
|
|
27705
|
+
suffix: string2().min(1).max(5)
|
|
27706
|
+
}),
|
|
27707
|
+
responses: {
|
|
27708
|
+
200: { description: "Updated credential pool", schema: PoolKeysResponseSchema },
|
|
27709
|
+
400: { description: "Invalid pool member" },
|
|
27710
|
+
403: { description: "Config administration and permission to read all secrets required" },
|
|
27711
|
+
409: { description: "The pool changed or comes from the deployment env" }
|
|
27712
|
+
}
|
|
27713
|
+
});
|
|
27714
|
+
var ENV_POOL_ERROR = "These keys come from the deployment env. Change them there.";
|
|
27715
|
+
async function readPool(key) {
|
|
27716
|
+
const [row] = await getSwarmConfigs2({ scope: "global", key });
|
|
27717
|
+
const envValue = getDeploymentEnvValue(key);
|
|
27718
|
+
const source = row ? "stored" : envValue ? "env" : "none";
|
|
27719
|
+
const value = row?.value ?? envValue ?? "";
|
|
27720
|
+
registerEnvSecrets({ [key]: value });
|
|
27721
|
+
return { row, source, members: splitCredentialPool(value) };
|
|
27722
|
+
}
|
|
27723
|
+
async function poolResponse(key) {
|
|
27724
|
+
const pool = await readPool(key);
|
|
27725
|
+
const statuses = await getKeyStatuses2(key, "global", null);
|
|
27726
|
+
return {
|
|
27727
|
+
key,
|
|
27728
|
+
source: pool.source,
|
|
27729
|
+
readOnly: pool.source === "env",
|
|
27730
|
+
keys: pool.members.map((member, index) => {
|
|
27731
|
+
const suffix = member.slice(-5);
|
|
27732
|
+
const row = statuses.find((status) => status.keySuffix === suffix);
|
|
27733
|
+
const rejected = !!row?.lastValidationFailedAt;
|
|
27734
|
+
const limited = row?.status === "rate_limited" && !!row.rateLimitedUntil && Date.parse(row.rateLimitedUntil) > Date.now();
|
|
27735
|
+
return {
|
|
27736
|
+
index,
|
|
27737
|
+
suffix,
|
|
27738
|
+
status: rejected ? "rejected" : limited ? "rate_limited" : row ? "ok" : "unchecked",
|
|
27739
|
+
error: rejected ? scrubSecrets(row?.lastValidationError) || null : null,
|
|
27740
|
+
checkedAt: rejected ? row.lastValidationFailedAt : row?.updatedAt ?? null,
|
|
27741
|
+
rateLimitedUntil: row?.rateLimitedUntil ?? null
|
|
27742
|
+
};
|
|
27743
|
+
})
|
|
27744
|
+
};
|
|
27745
|
+
}
|
|
27746
|
+
function duplicateError(members, additions) {
|
|
27747
|
+
const seen = new Set(members);
|
|
27748
|
+
for (const member of additions) {
|
|
27749
|
+
if (seen.has(member))
|
|
27750
|
+
return `The key ending ${member.slice(-5)} is already in the pool.`;
|
|
27751
|
+
seen.add(member);
|
|
27752
|
+
}
|
|
27753
|
+
return null;
|
|
27754
|
+
}
|
|
27755
|
+
async function savePool(key, members, row) {
|
|
27756
|
+
const value = members.join(",");
|
|
27757
|
+
const validationError = validateConfigEntry({
|
|
27758
|
+
scope: "global",
|
|
27759
|
+
key,
|
|
27760
|
+
value,
|
|
27761
|
+
exportToEnv: row?.exportToEnv
|
|
27762
|
+
});
|
|
27763
|
+
if (validationError)
|
|
27764
|
+
return validationError;
|
|
27765
|
+
await upsertSwarmConfigWithPolicyMirror({
|
|
27766
|
+
scope: "global",
|
|
27767
|
+
key,
|
|
27768
|
+
value,
|
|
27769
|
+
isSecret: true,
|
|
27770
|
+
description: row?.description ?? null,
|
|
27771
|
+
envPath: row?.envPath ?? null,
|
|
27772
|
+
exportToEnv: row?.exportToEnv
|
|
27773
|
+
});
|
|
27774
|
+
return null;
|
|
27775
|
+
}
|
|
27776
|
+
async function ensureSecretRead2(req, res) {
|
|
27777
|
+
if (await requestSecretReadScope(req) === "all")
|
|
27778
|
+
return true;
|
|
27779
|
+
jsonError(res, "Reading credential pools requires permission to read all secrets.", 403);
|
|
27780
|
+
return false;
|
|
27781
|
+
}
|
|
27782
|
+
async function handlePoolKeys(req, res, pathSegments, queryParams) {
|
|
27783
|
+
if (getPoolKeys.match(req.method, pathSegments)) {
|
|
27784
|
+
const parsed = await getPoolKeys.parse(req, res, pathSegments, queryParams);
|
|
27785
|
+
if (!parsed)
|
|
27786
|
+
return true;
|
|
27787
|
+
if (!await ensureSecretRead2(req, res))
|
|
27788
|
+
return true;
|
|
27789
|
+
getPoolKeys.respond(res, 200, await poolResponse(parsed.query.key));
|
|
27790
|
+
return true;
|
|
27791
|
+
}
|
|
27792
|
+
if (addPoolKeys.match(req.method, pathSegments)) {
|
|
27793
|
+
const parsed = await addPoolKeys.parse(req, res, pathSegments, queryParams);
|
|
27794
|
+
if (!parsed)
|
|
27795
|
+
return true;
|
|
27796
|
+
if (!await ensureConfigAdmin(req, res, "config.write.any"))
|
|
27797
|
+
return true;
|
|
27798
|
+
if (!await ensureSecretRead2(req, res))
|
|
27799
|
+
return true;
|
|
27800
|
+
const { key, value, baseUrl } = parsed.body;
|
|
27801
|
+
const additions = value.split(",").map((part) => part.trim()).filter(Boolean);
|
|
27802
|
+
if (!additions.length) {
|
|
27803
|
+
jsonError(res, "Enter a key.", 400);
|
|
27804
|
+
return true;
|
|
27805
|
+
}
|
|
27806
|
+
if (additions.some((part) => /\s/.test(part))) {
|
|
27807
|
+
jsonError(res, "A key cannot contain spaces or line breaks.", 400);
|
|
27808
|
+
return true;
|
|
27809
|
+
}
|
|
27810
|
+
registerEnvSecrets({ [key]: additions.join(",") });
|
|
27811
|
+
const initial = await readPool(key);
|
|
27812
|
+
if (initial.source === "env") {
|
|
27813
|
+
jsonError(res, ENV_POOL_ERROR, 409);
|
|
27814
|
+
return true;
|
|
27815
|
+
}
|
|
27816
|
+
const duplicate = duplicateError(initial.members, additions);
|
|
27817
|
+
if (duplicate) {
|
|
27818
|
+
jsonError(res, scrubSecrets(duplicate), 409);
|
|
27819
|
+
return true;
|
|
27820
|
+
}
|
|
27821
|
+
const env = { ...process.env };
|
|
27822
|
+
const provider = providerForKeyVar(key);
|
|
27823
|
+
const baseUrlKey = key === "OPENROUTER_API_KEY" ? "OPENROUTER_BASE_URL" : provider ? baseUrlEnvVar(provider) : undefined;
|
|
27824
|
+
if (baseUrlKey && baseUrl !== undefined) {
|
|
27825
|
+
env[baseUrlKey] = baseUrl ?? "";
|
|
27826
|
+
} else if (baseUrlKey) {
|
|
27827
|
+
const [row] = await getSwarmConfigs2({ scope: "global", key: baseUrlKey });
|
|
27828
|
+
if (row)
|
|
27829
|
+
env[baseUrlKey] = row.value;
|
|
27830
|
+
}
|
|
27831
|
+
const checks = await Promise.all(additions.map(async (member) => {
|
|
27832
|
+
try {
|
|
27833
|
+
const probe = await checkProviderPoolKey(key, member, env);
|
|
27834
|
+
return {
|
|
27835
|
+
suffix: member.slice(-5),
|
|
27836
|
+
result: probe.skipped ? "not_tested" : probe.ok ? "verified" : probe.httpStatus === 401 ? "rejected" : "not_tested",
|
|
27837
|
+
httpStatus: probe.httpStatus ?? null,
|
|
27838
|
+
error: scrubSecrets(probe.error?.replaceAll(member, "[REDACTED]")) || null
|
|
27839
|
+
};
|
|
27840
|
+
} catch {
|
|
27841
|
+
return {
|
|
27842
|
+
suffix: member.slice(-5),
|
|
27843
|
+
result: "not_tested",
|
|
27844
|
+
httpStatus: null,
|
|
27845
|
+
error: "The provider check did not complete."
|
|
27846
|
+
};
|
|
27847
|
+
}
|
|
27848
|
+
}));
|
|
27849
|
+
const rejected = checks.find((check) => check.result === "rejected");
|
|
27850
|
+
if (rejected) {
|
|
27851
|
+
addPoolKeys.respond(res, 422, {
|
|
27852
|
+
error: scrubSecrets(`The key ending ${rejected.suffix} was rejected (HTTP 401). Nothing was saved.`),
|
|
27853
|
+
checks
|
|
27854
|
+
});
|
|
27855
|
+
return true;
|
|
27856
|
+
}
|
|
27857
|
+
const result = await getDbClient2().transaction(async () => {
|
|
27858
|
+
const current = await readPool(key);
|
|
27859
|
+
if (current.source === "env")
|
|
27860
|
+
return { error: ENV_POOL_ERROR, status: 409 };
|
|
27861
|
+
const duplicate = duplicateError(current.members, additions);
|
|
27862
|
+
if (duplicate)
|
|
27863
|
+
return { error: duplicate, status: 409 };
|
|
27864
|
+
const members = [...current.members, ...additions];
|
|
27865
|
+
const error = await savePool(key, members, current.row);
|
|
27866
|
+
if (error)
|
|
27867
|
+
return { error, status: 400 };
|
|
27868
|
+
await recordKeyValidation2(key, checks.flatMap((check, index) => check.result === "verified" ? [{ keyIndex: current.members.length + index, keySuffix: check.suffix, ok: true }] : []), "global", null, { retireAbsent: false });
|
|
27869
|
+
return { value: members.join(",") };
|
|
27870
|
+
});
|
|
27871
|
+
if ("error" in result) {
|
|
27872
|
+
jsonError(res, scrubSecrets(result.error), result.status);
|
|
27873
|
+
return true;
|
|
27874
|
+
}
|
|
27875
|
+
await runConfigWriteSideEffects("global", key, result.value);
|
|
27876
|
+
addPoolKeys.respond(res, 200, { ...await poolResponse(key), checks });
|
|
27877
|
+
return true;
|
|
27878
|
+
}
|
|
27879
|
+
if (deletePoolKey.match(req.method, pathSegments)) {
|
|
27880
|
+
const parsed = await deletePoolKey.parse(req, res, pathSegments, queryParams);
|
|
27881
|
+
if (!parsed)
|
|
27882
|
+
return true;
|
|
27883
|
+
if (!await ensureConfigAdmin(req, res, "config.delete.any"))
|
|
27884
|
+
return true;
|
|
27885
|
+
if (!await ensureSecretRead2(req, res))
|
|
27886
|
+
return true;
|
|
27887
|
+
const { key, index, suffix } = parsed.query;
|
|
27888
|
+
const result = await getDbClient2().transaction(async () => {
|
|
27889
|
+
const current = await readPool(key);
|
|
27890
|
+
if (current.source === "env")
|
|
27891
|
+
return { error: ENV_POOL_ERROR, status: 409 };
|
|
27892
|
+
if (!current.members[index] || current.members[index].slice(-5) !== suffix) {
|
|
27893
|
+
return { error: "The key list changed. Reload it and try again.", status: 409 };
|
|
27894
|
+
}
|
|
27895
|
+
const members = current.members.filter((_, position) => position !== index);
|
|
27896
|
+
if (members.length) {
|
|
27897
|
+
const error = await savePool(key, members, current.row);
|
|
27898
|
+
if (error)
|
|
27899
|
+
return { error, status: 400 };
|
|
27900
|
+
} else {
|
|
27901
|
+
await deleteSwarmConfigByKey2("global", null, key);
|
|
27902
|
+
}
|
|
27903
|
+
await retirePoolKeyStatus(key, suffix, members.map((member, keyIndex) => ({ keySuffix: member.slice(-5), keyIndex })));
|
|
27904
|
+
return { value: members.join(",") };
|
|
27905
|
+
});
|
|
27906
|
+
if ("error" in result) {
|
|
27907
|
+
jsonError(res, scrubSecrets(result.error), result.status);
|
|
27908
|
+
return true;
|
|
27909
|
+
}
|
|
27910
|
+
await runConfigWriteSideEffects("global", key, result.value);
|
|
27911
|
+
deletePoolKey.respond(res, 200, await poolResponse(key));
|
|
27912
|
+
return true;
|
|
27913
|
+
}
|
|
27914
|
+
return false;
|
|
27915
|
+
}
|
|
27916
|
+
|
|
27252
27917
|
// src/http/pricing.ts
|
|
27253
27918
|
init_zod();
|
|
27254
27919
|
init_db3();
|
|
@@ -33619,6 +34284,7 @@ async function handleSessionData(req, res, pathSegments, queryParams, myAgentId)
|
|
|
33619
34284
|
// src/http/sessions.ts
|
|
33620
34285
|
init_zod();
|
|
33621
34286
|
init_key();
|
|
34287
|
+
init_source_key();
|
|
33622
34288
|
init_db3();
|
|
33623
34289
|
init_session_moves();
|
|
33624
34290
|
init_session_tree();
|
|
@@ -33627,6 +34293,74 @@ init_steering();
|
|
|
33627
34293
|
init_users();
|
|
33628
34294
|
init_rbac();
|
|
33629
34295
|
init_bus();
|
|
34296
|
+
|
|
34297
|
+
// src/slack/channel-labels.ts
|
|
34298
|
+
var LABEL_TTL_MS = 24 * 60 * 60 * 1000;
|
|
34299
|
+
var FAILURE_TTL_MS = 10 * 60 * 1000;
|
|
34300
|
+
var FAILURE_CACHE_MAX = 500;
|
|
34301
|
+
var LOOKUP_QUEUE_MAX = 50;
|
|
34302
|
+
var inFlight2 = new Set;
|
|
34303
|
+
var failedUntil = new Map;
|
|
34304
|
+
var pending = Promise.resolve();
|
|
34305
|
+
async function channelLabel(client, id) {
|
|
34306
|
+
const result = await callSlackWithRetry2(client, "conversations.info", {
|
|
34307
|
+
channel: id.toUpperCase()
|
|
34308
|
+
});
|
|
34309
|
+
const channel = result.channel;
|
|
34310
|
+
if (result.ok === false || !channel)
|
|
34311
|
+
throw new Error("Channel lookup failed");
|
|
34312
|
+
if (channel.is_mpim)
|
|
34313
|
+
return "Group DM";
|
|
34314
|
+
if (channel.is_im && channel.user) {
|
|
34315
|
+
const result = await callSlackWithRetry2(client, "users.info", { user: channel.user });
|
|
34316
|
+
const user = result.user;
|
|
34317
|
+
const name = user?.profile?.display_name || user?.real_name || user?.profile?.real_name;
|
|
34318
|
+
if (result.ok !== false && name)
|
|
34319
|
+
return `DM · ${name}`;
|
|
34320
|
+
} else if (channel.name) {
|
|
34321
|
+
return `#${channel.name}`;
|
|
34322
|
+
}
|
|
34323
|
+
throw new Error("Channel label unavailable");
|
|
34324
|
+
}
|
|
34325
|
+
var CHANNEL_GROUP_KEY = /^shared\/slack\/([^/]+)\/$/;
|
|
34326
|
+
function warmSlackChannelLabels(groupKeys) {
|
|
34327
|
+
const client = getSlackApp2()?.client;
|
|
34328
|
+
if (!client)
|
|
34329
|
+
return;
|
|
34330
|
+
for (const groupKey of groupKeys) {
|
|
34331
|
+
const id = CHANNEL_GROUP_KEY.exec(groupKey)?.[1];
|
|
34332
|
+
if (!id)
|
|
34333
|
+
continue;
|
|
34334
|
+
if (inFlight2.has(id) || (failedUntil.get(id) ?? 0) > Date.now())
|
|
34335
|
+
continue;
|
|
34336
|
+
failedUntil.delete(id);
|
|
34337
|
+
if (inFlight2.size >= LOOKUP_QUEUE_MAX)
|
|
34338
|
+
continue;
|
|
34339
|
+
if (failedUntil.size + inFlight2.size >= FAILURE_CACHE_MAX) {
|
|
34340
|
+
const now = Date.now();
|
|
34341
|
+
for (const [failedId, until] of failedUntil) {
|
|
34342
|
+
if (until <= now)
|
|
34343
|
+
failedUntil.delete(failedId);
|
|
34344
|
+
}
|
|
34345
|
+
if (failedUntil.size + inFlight2.size >= FAILURE_CACHE_MAX)
|
|
34346
|
+
continue;
|
|
34347
|
+
}
|
|
34348
|
+
inFlight2.add(id);
|
|
34349
|
+
pending = pending.then(async () => {
|
|
34350
|
+
try {
|
|
34351
|
+
const label = await channelLabel(client, id);
|
|
34352
|
+
await rememberSessionLabel(groupKey, label, LABEL_TTL_MS);
|
|
34353
|
+
} catch (error) {
|
|
34354
|
+
failedUntil.set(id, Date.now() + FAILURE_TTL_MS);
|
|
34355
|
+
console.warn(`[Slack] Could not cache a session channel label: ${slackErrorCode2(error) ?? "unknown error"}`);
|
|
34356
|
+
} finally {
|
|
34357
|
+
inFlight2.delete(id);
|
|
34358
|
+
}
|
|
34359
|
+
});
|
|
34360
|
+
}
|
|
34361
|
+
}
|
|
34362
|
+
|
|
34363
|
+
// src/http/sessions.ts
|
|
33630
34364
|
init_types();
|
|
33631
34365
|
init_request_auth_context();
|
|
33632
34366
|
init_runtime_pools_flag();
|
|
@@ -33689,6 +34423,7 @@ var SessionTreeGroupSchema = SessionSectionCountsSchema.extend({
|
|
|
33689
34423
|
lastActivityAt: string2()
|
|
33690
34424
|
});
|
|
33691
34425
|
var SessionTreeResponseSchema = object2({
|
|
34426
|
+
labels: record2(string2(), string2()).optional(),
|
|
33692
34427
|
groups: array2(SessionTreeGroupSchema),
|
|
33693
34428
|
inbox: SessionSectionCountsSchema,
|
|
33694
34429
|
later: SessionSectionCountsSchema,
|
|
@@ -34126,6 +34861,9 @@ async function checkSessionMove(rootTaskId, actor, req, myAgentId, options = {})
|
|
|
34126
34861
|
}
|
|
34127
34862
|
if (root.parentTaskId)
|
|
34128
34863
|
return { reason: "Task is not a session root" };
|
|
34864
|
+
const sourceError = sourceMoveError(options.destination ?? null, root);
|
|
34865
|
+
if (sourceError)
|
|
34866
|
+
return { reason: sourceError };
|
|
34129
34867
|
const tasks = await getRootTaskChain2(root.id);
|
|
34130
34868
|
for (const task of tasks) {
|
|
34131
34869
|
if (!await canMutateTaskNamespace(task, myAgentId, req)) {
|
|
@@ -34150,6 +34888,7 @@ var getSession = route({
|
|
|
34150
34888
|
chain: array2(TaskWithSteeringSchema),
|
|
34151
34889
|
access: SessionAccessSchema,
|
|
34152
34890
|
owner: SessionOwnerSchema.nullable(),
|
|
34891
|
+
groupKey: string2(),
|
|
34153
34892
|
approvals: array2(SessionApprovalSchema).optional(),
|
|
34154
34893
|
readState: _enum2(["unread", "read", "later", "done"]).optional(),
|
|
34155
34894
|
lastActivityAt: string2().optional()
|
|
@@ -34336,11 +35075,15 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34336
35075
|
if (!parsed)
|
|
34337
35076
|
return true;
|
|
34338
35077
|
const actor = await resolveSessionActor2(req, myAgentId);
|
|
34339
|
-
|
|
35078
|
+
const tree = await getSessionTree(actor, undefined, {
|
|
34340
35079
|
mine: parsed.query.show !== "all",
|
|
34341
35080
|
hideSource: parsed.query.hideSource,
|
|
34342
35081
|
showSource: parsed.query.showSource
|
|
34343
|
-
})
|
|
35082
|
+
});
|
|
35083
|
+
const { sourceGroups, slackChannels, threadLabels, ...counts } = tree;
|
|
35084
|
+
const labels = { ...threadLabels, ...await getSessionLabels(sourceGroups) };
|
|
35085
|
+
warmSlackChannelLabels(slackChannels.map((id) => `shared/slack/${id}/`).filter((key) => labels[key] === undefined));
|
|
35086
|
+
sessionTree.respond(res, 200, { ...counts, labels });
|
|
34344
35087
|
return true;
|
|
34345
35088
|
}
|
|
34346
35089
|
if (triageSessionListRoute.match(req.method, pathSegments)) {
|
|
@@ -34365,7 +35108,9 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34365
35108
|
const skipped = [];
|
|
34366
35109
|
const moves = [];
|
|
34367
35110
|
for (const rootId of new Set(parsed.body.rootTaskIds)) {
|
|
34368
|
-
const checked = await checkSessionMove(rootId, actor, req, myAgentId
|
|
35111
|
+
const checked = await checkSessionMove(rootId, actor, req, myAgentId, {
|
|
35112
|
+
destination: key
|
|
35113
|
+
});
|
|
34369
35114
|
if ("reason" in checked) {
|
|
34370
35115
|
skipped.push({ rootTaskId: rootId, reason: checked.reason });
|
|
34371
35116
|
} else {
|
|
@@ -34386,6 +35131,10 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34386
35131
|
if (!parsed)
|
|
34387
35132
|
return true;
|
|
34388
35133
|
const from = normalizeAssetKey(parsed.body.from);
|
|
35134
|
+
if (sourceOfKey(from) || parsed.body.to && sourceOfKey(normalizeAssetKey(parsed.body.to))) {
|
|
35135
|
+
jsonError(res, SOURCE_GROUPS_READ_ONLY, 400);
|
|
35136
|
+
return true;
|
|
35137
|
+
}
|
|
34389
35138
|
if (parseAssetKey(from).relativeSegments.length === 0) {
|
|
34390
35139
|
jsonError(res, "Cannot move a namespace root", 400);
|
|
34391
35140
|
return true;
|
|
@@ -34425,7 +35174,8 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34425
35174
|
continue;
|
|
34426
35175
|
}
|
|
34427
35176
|
const checked = await checkSessionMove(root.id, actor, req, myAgentId, {
|
|
34428
|
-
ownerOnly: true
|
|
35177
|
+
ownerOnly: true,
|
|
35178
|
+
destination: nextKey
|
|
34429
35179
|
});
|
|
34430
35180
|
if ("reason" in checked) {
|
|
34431
35181
|
skipped.push({ rootTaskId: root.id, reason: checked.reason });
|
|
@@ -34469,11 +35219,12 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34469
35219
|
} : null;
|
|
34470
35220
|
const chain = await getRootTaskChain2(parsed.params.rootTaskId);
|
|
34471
35221
|
const tasks = [root, ...chain];
|
|
34472
|
-
const [steering, citations, approvals, read] = await Promise.all([
|
|
35222
|
+
const [steering, citations, approvals, read, groupKey] = await Promise.all([
|
|
34473
35223
|
getTaskSteeringFieldsForTasks(tasks),
|
|
34474
35224
|
getTaskCitationsForTasks(tasks.map((task) => task.id)),
|
|
34475
35225
|
getPendingApprovalsForTasks2(tasks.map((task) => task.id)),
|
|
34476
|
-
actor.kind === "user" && actor.userId ? getSessionReadState(sessionRoot.id, actor.userId) : Promise.resolve(null)
|
|
35226
|
+
actor.kind === "user" && actor.userId ? getSessionReadState(sessionRoot.id, actor.userId) : Promise.resolve(null),
|
|
35227
|
+
getSessionGroupKey(root)
|
|
34477
35228
|
]);
|
|
34478
35229
|
const decorate = (task) => ({
|
|
34479
35230
|
...task,
|
|
@@ -34485,6 +35236,7 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
34485
35236
|
chain: chain.map(decorate),
|
|
34486
35237
|
access,
|
|
34487
35238
|
owner,
|
|
35239
|
+
groupKey,
|
|
34488
35240
|
...approvals.length ? { approvals } : {},
|
|
34489
35241
|
...read ?? {}
|
|
34490
35242
|
});
|
|
@@ -35873,7 +36625,8 @@ var SwarmMetricsSchema = object2({
|
|
|
35873
36625
|
sessionLogs: RetentionTableStatsSchema.optional(),
|
|
35874
36626
|
agentLog: RetentionTableStatsSchema.optional(),
|
|
35875
36627
|
events: RetentionTableStatsSchema.optional(),
|
|
35876
|
-
contextVersions: RetentionTableStatsSchema.optional()
|
|
36628
|
+
contextVersions: RetentionTableStatsSchema.optional(),
|
|
36629
|
+
scriptRuns: RetentionTableStatsSchema.optional()
|
|
35877
36630
|
})
|
|
35878
36631
|
});
|
|
35879
36632
|
var ConcurrentContextSchema = object2({
|
|
@@ -39250,8 +40003,66 @@ async function handleWorkflowEvents(req, res, pathSegments, queryParams) {
|
|
|
39250
40003
|
// src/http/workflows.ts
|
|
39251
40004
|
init_zod();
|
|
39252
40005
|
init_db3();
|
|
40006
|
+
init_workflow_idempotency();
|
|
39253
40007
|
init_workflow_runs();
|
|
39254
40008
|
init_types();
|
|
40009
|
+
|
|
40010
|
+
// src/http/idempotency-key.ts
|
|
40011
|
+
init_zod();
|
|
40012
|
+
init_workflow_idempotency();
|
|
40013
|
+
init_request_auth_context();
|
|
40014
|
+
var IDEMPOTENCY_KEY_PATTERN = /^[\x21-\x7E]{1,255}$/;
|
|
40015
|
+
var IDEMPOTENT_REPLAYED_HEADER = "Idempotent-Replayed";
|
|
40016
|
+
var idempotencyKeyHeader = (accepted) => object2({
|
|
40017
|
+
"Idempotency-Key": string2().regex(IDEMPOTENCY_KEY_PATTERN).optional().describe("Optional client-generated key, 1-255 visible ASCII characters (a UUID works). " + `The first request the server accepts under a key ${accepted}; a retry with the same key ` + "and an equivalent body gets that request's status and body back (with " + `\`${IDEMPOTENT_REPLAYED_HEADER}: true\`) and changes nothing. The key is scoped to the ` + "caller's identity and this operation; it is not a credential. The same key with a " + "different body is a 409. A request rejected before it is accepted (validation, auth, " + "not found, disabled) does not use up the key. Accepted keys do not expire.")
|
|
40018
|
+
});
|
|
40019
|
+
function idempotencyPrincipal(req, myAgentId) {
|
|
40020
|
+
const auth = getRequestAuth(req);
|
|
40021
|
+
switch (auth?.kind) {
|
|
40022
|
+
case "user":
|
|
40023
|
+
return `user:${auth.userId}`;
|
|
40024
|
+
case "agent":
|
|
40025
|
+
return `agent:${auth.agentId}`;
|
|
40026
|
+
case "controller":
|
|
40027
|
+
return `controller:${auth.controllerId}`;
|
|
40028
|
+
case "guest":
|
|
40029
|
+
return null;
|
|
40030
|
+
default:
|
|
40031
|
+
return myAgentId ? `agent:${myAgentId}` : "operator";
|
|
40032
|
+
}
|
|
40033
|
+
}
|
|
40034
|
+
function readIdempotencyKey(req, res, myAgentId) {
|
|
40035
|
+
const raw = req.headers["idempotency-key"];
|
|
40036
|
+
if (raw === undefined)
|
|
40037
|
+
return;
|
|
40038
|
+
const key = Array.isArray(raw) ? raw.join(", ") : raw;
|
|
40039
|
+
if (!IDEMPOTENCY_KEY_PATTERN.test(key)) {
|
|
40040
|
+
jsonError(res, "Idempotency-Key must be 1-255 visible ASCII characters", 400);
|
|
40041
|
+
return null;
|
|
40042
|
+
}
|
|
40043
|
+
const principal = idempotencyPrincipal(req, myAgentId);
|
|
40044
|
+
if (!principal) {
|
|
40045
|
+
jsonError(res, "Idempotency-Key needs an identified caller", 400);
|
|
40046
|
+
return null;
|
|
40047
|
+
}
|
|
40048
|
+
return { principal, key };
|
|
40049
|
+
}
|
|
40050
|
+
async function replayAcceptedOperation(res, claim, send) {
|
|
40051
|
+
const accepted = await findAcceptedWorkflowOperation(claim);
|
|
40052
|
+
if (!accepted)
|
|
40053
|
+
return false;
|
|
40054
|
+
if (accepted.fingerprint !== claim.fingerprint) {
|
|
40055
|
+
jsonError(res, "Idempotency-Key was already used for a different request", 409);
|
|
40056
|
+
} else if (accepted.resourceDeletedAt !== null) {
|
|
40057
|
+
jsonError(res, "The workflow this Idempotency-Key created or triggered was deleted; send a new key to start over", 410);
|
|
40058
|
+
} else {
|
|
40059
|
+
res.setHeader(IDEMPOTENT_REPLAYED_HEADER, "true");
|
|
40060
|
+
send(accepted.body);
|
|
40061
|
+
}
|
|
40062
|
+
return true;
|
|
40063
|
+
}
|
|
40064
|
+
|
|
40065
|
+
// src/http/workflows.ts
|
|
39255
40066
|
var WorkflowWithFavoriteSchema = WorkflowSchema.extend({ favorite: boolean() });
|
|
39256
40067
|
var WorkflowSaveResponseSchema = WorkflowSchema.extend({
|
|
39257
40068
|
warnings: array2(string2()).optional()
|
|
@@ -39280,6 +40091,11 @@ var WorkflowRunPageSchema = object2({
|
|
|
39280
40091
|
nextOffset: number2().int().optional()
|
|
39281
40092
|
})
|
|
39282
40093
|
});
|
|
40094
|
+
var WorkflowRunTreeSchema = object2({
|
|
40095
|
+
rootRunId: string2(),
|
|
40096
|
+
runs: array2(WorkflowRunSummarySchema),
|
|
40097
|
+
hasOpenWork: boolean()
|
|
40098
|
+
});
|
|
39283
40099
|
var SuccessResponseSchema = object2({ success: literal2(true) });
|
|
39284
40100
|
async function withSaveWarnings(workflow) {
|
|
39285
40101
|
const warnings = await workflowSaveWarnings(workflow.definition, getExecutorRegistry2());
|
|
@@ -39313,6 +40129,7 @@ var createWorkflowRoute = route({
|
|
|
39313
40129
|
pattern: ["api", "workflows"],
|
|
39314
40130
|
summary: "Create a new workflow",
|
|
39315
40131
|
tags: ["Workflows"],
|
|
40132
|
+
headers: idempotencyKeyHeader("creates one workflow"),
|
|
39316
40133
|
body: object2({
|
|
39317
40134
|
name: string2().min(1),
|
|
39318
40135
|
key: AssetKeySchema.optional(),
|
|
@@ -39330,7 +40147,9 @@ var createWorkflowRoute = route({
|
|
|
39330
40147
|
}),
|
|
39331
40148
|
responses: {
|
|
39332
40149
|
201: { description: "Workflow created", schema: WorkflowSaveResponseSchema },
|
|
39333
|
-
400: { description: "Invalid definition" }
|
|
40150
|
+
400: { description: "Invalid definition, or a malformed Idempotency-Key" },
|
|
40151
|
+
409: { description: "Idempotency-Key was already used for a different request" },
|
|
40152
|
+
410: { description: "The workflow created under this Idempotency-Key was deleted" }
|
|
39334
40153
|
}
|
|
39335
40154
|
});
|
|
39336
40155
|
var getWorkflowRoute = route({
|
|
@@ -39434,16 +40253,20 @@ var triggerWorkflowRoute = route({
|
|
|
39434
40253
|
path: "/api/workflows/{id}/trigger",
|
|
39435
40254
|
pattern: ["api", "workflows", null, "trigger"],
|
|
39436
40255
|
summary: "Trigger a workflow execution",
|
|
40256
|
+
description: "With an `Idempotency-Key`, a retry returns the accepted run's `runId` and `skipped` without starting, resuming or waiting for anything, even after the workflow was disabled or edited and whatever state the run is in now.",
|
|
39437
40257
|
tags: ["Workflows"],
|
|
39438
40258
|
params: object2({ id: string2() }),
|
|
40259
|
+
headers: idempotencyKeyHeader("starts one run"),
|
|
39439
40260
|
responses: {
|
|
39440
40261
|
201: {
|
|
39441
40262
|
description: "Workflow run started (or skipped if cooldown active)",
|
|
39442
40263
|
schema: object2({ runId: string2(), skipped: boolean() })
|
|
39443
40264
|
},
|
|
39444
|
-
400: { description: "Workflow is disabled" },
|
|
40265
|
+
400: { description: "Workflow is disabled, or a malformed Idempotency-Key" },
|
|
39445
40266
|
401: { description: "Unauthorized" },
|
|
39446
|
-
404: { description: "Workflow not found" }
|
|
40267
|
+
404: { description: "Workflow not found" },
|
|
40268
|
+
409: { description: "Idempotency-Key was already used for a different request" },
|
|
40269
|
+
410: { description: "The workflow triggered under this Idempotency-Key was deleted" }
|
|
39447
40270
|
}
|
|
39448
40271
|
});
|
|
39449
40272
|
var validateTriggerRoute = route({
|
|
@@ -39487,20 +40310,45 @@ var getWorkflowRunRoute = route({
|
|
|
39487
40310
|
path: "/api/workflow-runs/{id}",
|
|
39488
40311
|
pattern: ["api", "workflow-runs", null],
|
|
39489
40312
|
summary: "Get a workflow run with steps (includes retry columns)",
|
|
40313
|
+
description: "Returns the run with its `context` and every step with its `input` by default. A step's `input` is a snapshot of the context when the step started, so in runs with loops (polling, `wait`, iterations) the response grows with steps × context size. Pass `fields=slim` to drop `run.context` and `steps[].input`; outputs, errors, diagnostics, retry fields and `parent` stay.",
|
|
39490
40314
|
tags: ["Workflows"],
|
|
39491
40315
|
params: object2({ id: string2() }),
|
|
40316
|
+
query: object2({
|
|
40317
|
+
fields: _enum2(["full", "slim"]).optional()
|
|
40318
|
+
}),
|
|
39492
40319
|
responses: {
|
|
39493
40320
|
200: {
|
|
39494
40321
|
description: "Workflow run details with steps including retry info",
|
|
39495
|
-
schema:
|
|
39496
|
-
|
|
39497
|
-
|
|
39498
|
-
|
|
39499
|
-
|
|
40322
|
+
schema: union2([
|
|
40323
|
+
object2({
|
|
40324
|
+
run: WorkflowRunSchema,
|
|
40325
|
+
steps: array2(WorkflowRunStepSchema),
|
|
40326
|
+
parent: WorkflowRunParentSchema.optional()
|
|
40327
|
+
}),
|
|
40328
|
+
object2({
|
|
40329
|
+
run: WorkflowRunSummarySchema,
|
|
40330
|
+
steps: array2(WorkflowRunStepSlimSchema),
|
|
40331
|
+
parent: WorkflowRunParentSchema.optional()
|
|
40332
|
+
})
|
|
40333
|
+
])
|
|
39500
40334
|
},
|
|
39501
40335
|
404: { description: "Run not found" }
|
|
39502
40336
|
}
|
|
39503
40337
|
});
|
|
40338
|
+
var getWorkflowRunTreeRoute = route({
|
|
40339
|
+
method: "get",
|
|
40340
|
+
path: "/api/workflow-runs/{id}/tree",
|
|
40341
|
+
pattern: ["api", "workflow-runs", null, "tree"],
|
|
40342
|
+
summary: "Get a workflow run and every sub-workflow run below it",
|
|
40343
|
+
description: `Follows stored parent links (\`parentStepId\` → step → run) through every attempt of every step, terminal runs included. \`runs\` holds list rows without \`context\`, root first. \`hasOpenWork\` is true while any run in the tree is live, has a pending, running or waiting step, a queued retry, an open task or a pending approval; after a cancel it turns false once the tree has settled. Both come from one read snapshot. The tree is not paginated. Links that form a cycle or nest deeper than ${WORKFLOW_RUN_TREE_MAX_DEPTH} levels return 409.`,
|
|
40344
|
+
tags: ["Workflows"],
|
|
40345
|
+
params: object2({ id: string2() }),
|
|
40346
|
+
responses: {
|
|
40347
|
+
200: { description: "The run tree", schema: WorkflowRunTreeSchema },
|
|
40348
|
+
404: { description: "Run not found" },
|
|
40349
|
+
409: { description: "Stored parent links form a cycle or nest past the depth bound" }
|
|
40350
|
+
}
|
|
40351
|
+
});
|
|
39504
40352
|
var retryWorkflowRunRoute = route({
|
|
39505
40353
|
method: "post",
|
|
39506
40354
|
path: "/api/workflow-runs/{id}/retry",
|
|
@@ -39688,9 +40536,21 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
39688
40536
|
return true;
|
|
39689
40537
|
}
|
|
39690
40538
|
if (createWorkflowRoute.match(req.method, pathSegments)) {
|
|
40539
|
+
const idempotency = readIdempotencyKey(req, res, myAgentId);
|
|
40540
|
+
if (idempotency === null)
|
|
40541
|
+
return true;
|
|
39691
40542
|
const parsed = await createWorkflowRoute.parse(req, res, pathSegments, queryParams);
|
|
39692
40543
|
if (!parsed)
|
|
39693
40544
|
return true;
|
|
40545
|
+
const claim = idempotency && {
|
|
40546
|
+
...idempotency,
|
|
40547
|
+
operation: "workflow.create",
|
|
40548
|
+
targetId: "",
|
|
40549
|
+
fingerprint: workflowRequestFingerprint("workflow.create", parsed.body)
|
|
40550
|
+
};
|
|
40551
|
+
const replayCreate = (body) => createWorkflowRoute.respond(res, 201, body);
|
|
40552
|
+
if (claim && await replayAcceptedOperation(res, claim, replayCreate))
|
|
40553
|
+
return true;
|
|
39694
40554
|
const validation = validateDefinition(parsed.body.definition, getExecutorRegistry2());
|
|
39695
40555
|
if (!validation.valid) {
|
|
39696
40556
|
jsonError(res, `Invalid definition: ${validation.errors.join("; ")}`, 400);
|
|
@@ -39712,7 +40572,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
39712
40572
|
}
|
|
39713
40573
|
throw error;
|
|
39714
40574
|
}
|
|
39715
|
-
const
|
|
40575
|
+
const data = {
|
|
39716
40576
|
key,
|
|
39717
40577
|
name: parsed.body.name,
|
|
39718
40578
|
description: parsed.body.description,
|
|
@@ -39728,8 +40588,34 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
39728
40588
|
vcsRepo: parsed.body.vcsRepo,
|
|
39729
40589
|
createdByAgentId: myAgentId ?? undefined,
|
|
39730
40590
|
createdBy: await resolveHttpAuditUserId(req, myAgentId) ?? undefined
|
|
39731
|
-
}
|
|
39732
|
-
|
|
40591
|
+
};
|
|
40592
|
+
if (!claim) {
|
|
40593
|
+
const workflow = await createWorkflow2(data, "api");
|
|
40594
|
+
createWorkflowRoute.respond(res, 201, await withSaveWarnings(workflow));
|
|
40595
|
+
return true;
|
|
40596
|
+
}
|
|
40597
|
+
const warnings = await workflowSaveWarnings(parsed.body.definition, getExecutorRegistry2());
|
|
40598
|
+
let saved;
|
|
40599
|
+
try {
|
|
40600
|
+
saved = await getDbClient2().transaction(async () => {
|
|
40601
|
+
await assertWorkflowIdempotencyKeyUnused(claim);
|
|
40602
|
+
const workflow = await createWorkflow2(data, "api");
|
|
40603
|
+
const body = warnings.length > 0 ? { ...workflow, warnings } : workflow;
|
|
40604
|
+
await recordAcceptedWorkflowOperation(claim, {
|
|
40605
|
+
workflowId: workflow.id,
|
|
40606
|
+
status: 201,
|
|
40607
|
+
body
|
|
40608
|
+
});
|
|
40609
|
+
return body;
|
|
40610
|
+
});
|
|
40611
|
+
} catch (err) {
|
|
40612
|
+
if (err instanceof IdempotencyKeyTakenError) {
|
|
40613
|
+
if (await replayAcceptedOperation(res, claim, replayCreate))
|
|
40614
|
+
return true;
|
|
40615
|
+
}
|
|
40616
|
+
throw err;
|
|
40617
|
+
}
|
|
40618
|
+
createWorkflowRoute.respond(res, 201, saved);
|
|
39733
40619
|
return true;
|
|
39734
40620
|
}
|
|
39735
40621
|
if (getWorkflowRoute.match(req.method, pathSegments)) {
|
|
@@ -39931,9 +40817,26 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
39931
40817
|
return true;
|
|
39932
40818
|
}
|
|
39933
40819
|
if (triggerWorkflowRoute.match(req.method, pathSegments)) {
|
|
40820
|
+
const idempotency = readIdempotencyKey(req, res, myAgentId);
|
|
40821
|
+
if (idempotency === null)
|
|
40822
|
+
return true;
|
|
39934
40823
|
const parsed = await triggerWorkflowRoute.parse(req, res, pathSegments, queryParams);
|
|
39935
40824
|
if (!parsed)
|
|
39936
40825
|
return true;
|
|
40826
|
+
let claim;
|
|
40827
|
+
let keyedBody;
|
|
40828
|
+
const replayTrigger = (body) => triggerWorkflowRoute.respond(res, 201, body);
|
|
40829
|
+
if (idempotency) {
|
|
40830
|
+
keyedBody = await parseBody(req);
|
|
40831
|
+
claim = {
|
|
40832
|
+
...idempotency,
|
|
40833
|
+
operation: "workflow.trigger",
|
|
40834
|
+
targetId: parsed.params.id,
|
|
40835
|
+
fingerprint: workflowRequestFingerprint("workflow.trigger", keyedBody)
|
|
40836
|
+
};
|
|
40837
|
+
if (await replayAcceptedOperation(res, claim, replayTrigger))
|
|
40838
|
+
return true;
|
|
40839
|
+
}
|
|
39937
40840
|
const workflow = await getWorkflow2(parsed.params.id);
|
|
39938
40841
|
if (!workflow) {
|
|
39939
40842
|
res.writeHead(404);
|
|
@@ -39944,20 +40847,39 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
39944
40847
|
jsonError(res, "Workflow is disabled", 400);
|
|
39945
40848
|
return true;
|
|
39946
40849
|
}
|
|
39947
|
-
const body = await parseBody(req);
|
|
40850
|
+
const body = idempotency ? keyedBody : await parseBody(req);
|
|
39948
40851
|
let runId;
|
|
40852
|
+
let accepted;
|
|
39949
40853
|
try {
|
|
39950
40854
|
runId = await startWorkflowExecution2(workflow, body, getExecutorRegistry2(), {
|
|
39951
40855
|
triggerType: "api",
|
|
39952
|
-
requestedByUserId: await resolveHttpAuditUserId(req, myAgentId) ?? undefined
|
|
40856
|
+
requestedByUserId: await resolveHttpAuditUserId(req, myAgentId) ?? undefined,
|
|
40857
|
+
accept: claim ? async (run) => {
|
|
40858
|
+
const response = { runId: run.runId, skipped: run.skipped };
|
|
40859
|
+
await recordAcceptedWorkflowOperation(claim, {
|
|
40860
|
+
workflowId: workflow.id,
|
|
40861
|
+
runId: run.runId,
|
|
40862
|
+
status: 201,
|
|
40863
|
+
body: response
|
|
40864
|
+
});
|
|
40865
|
+
accepted = response;
|
|
40866
|
+
} : undefined
|
|
39953
40867
|
});
|
|
39954
40868
|
} catch (err) {
|
|
39955
40869
|
if (err instanceof TriggerSchemaError) {
|
|
39956
40870
|
triggerSchemaErrorResponse(res, err.message, err.validationErrors);
|
|
39957
40871
|
return true;
|
|
39958
40872
|
}
|
|
40873
|
+
if (claim && err instanceof IdempotencyKeyTakenError) {
|
|
40874
|
+
if (await replayAcceptedOperation(res, claim, replayTrigger))
|
|
40875
|
+
return true;
|
|
40876
|
+
}
|
|
39959
40877
|
throw err;
|
|
39960
40878
|
}
|
|
40879
|
+
if (accepted) {
|
|
40880
|
+
triggerWorkflowRoute.respond(res, 201, accepted);
|
|
40881
|
+
return true;
|
|
40882
|
+
}
|
|
39961
40883
|
const run = await getWorkflowRun2(runId);
|
|
39962
40884
|
const skipped = run?.status === "skipped";
|
|
39963
40885
|
triggerWorkflowRoute.respond(res, 201, { runId, skipped });
|
|
@@ -39979,17 +40901,39 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
39979
40901
|
const parsed = await getWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
|
|
39980
40902
|
if (!parsed)
|
|
39981
40903
|
return true;
|
|
39982
|
-
const
|
|
40904
|
+
const slim = parsed.query.fields === "slim";
|
|
40905
|
+
const run = slim ? await getWorkflowRunSummary(parsed.params.id) : await getWorkflowRun2(parsed.params.id, "display");
|
|
39983
40906
|
if (!run) {
|
|
39984
40907
|
res.writeHead(404);
|
|
39985
40908
|
res.end();
|
|
39986
40909
|
return true;
|
|
39987
40910
|
}
|
|
39988
|
-
const steps = await getWorkflowRunStepsByRunId2(parsed.params.id, "display");
|
|
40911
|
+
const steps = slim ? await getWorkflowRunStepsSlimByRunId(parsed.params.id) : await getWorkflowRunStepsByRunId2(parsed.params.id, "display");
|
|
39989
40912
|
const parent = run.parentStepId ? await getWorkflowRunParent(run.parentStepId) : null;
|
|
39990
40913
|
getWorkflowRunRoute.respond(res, 200, { run, steps, ...parent ? { parent } : {} });
|
|
39991
40914
|
return true;
|
|
39992
40915
|
}
|
|
40916
|
+
if (getWorkflowRunTreeRoute.match(req.method, pathSegments)) {
|
|
40917
|
+
const parsed = await getWorkflowRunTreeRoute.parse(req, res, pathSegments, queryParams);
|
|
40918
|
+
if (!parsed)
|
|
40919
|
+
return true;
|
|
40920
|
+
let tree;
|
|
40921
|
+
try {
|
|
40922
|
+
tree = await getWorkflowRunTree(parsed.params.id);
|
|
40923
|
+
} catch (err) {
|
|
40924
|
+
if (!(err instanceof WorkflowRunTreeError))
|
|
40925
|
+
throw err;
|
|
40926
|
+
jsonError(res, err.message, 409);
|
|
40927
|
+
return true;
|
|
40928
|
+
}
|
|
40929
|
+
if (!tree) {
|
|
40930
|
+
res.writeHead(404);
|
|
40931
|
+
res.end();
|
|
40932
|
+
return true;
|
|
40933
|
+
}
|
|
40934
|
+
getWorkflowRunTreeRoute.respond(res, 200, tree);
|
|
40935
|
+
return true;
|
|
40936
|
+
}
|
|
39993
40937
|
if (retryWorkflowRunRoute.match(req.method, pathSegments)) {
|
|
39994
40938
|
const parsed = await retryWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
|
|
39995
40939
|
if (!parsed)
|
|
@@ -40344,6 +41288,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
40344
41288
|
() => handleStatus(req, res, pathSegments, queryParams),
|
|
40345
41289
|
() => handleOnboarding(req, res, pathSegments, queryParams),
|
|
40346
41290
|
() => handleCodexOAuthDevice(req, res, pathSegments, queryParams),
|
|
41291
|
+
() => handleCodexOAuthAccounts(req, res, pathSegments, queryParams),
|
|
40347
41292
|
() => handleActiveSessions(req, res, pathSegments, queryParams, myAgentId),
|
|
40348
41293
|
() => handlePricing(req, res, pathSegments, queryParams, myAgentId),
|
|
40349
41294
|
() => handleSchedules(req, res, pathSegments, queryParams, myAgentId),
|
|
@@ -40351,6 +41296,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
40351
41296
|
() => handleWorkflowEvents(req, res, pathSegments, queryParams),
|
|
40352
41297
|
() => handleApprovalRequests(req, res, pathSegments, queryParams),
|
|
40353
41298
|
() => handleApps(req, res, pathSegments, queryParams, myAgentId),
|
|
41299
|
+
() => handlePoolKeys(req, res, pathSegments, queryParams),
|
|
40354
41300
|
() => handleConfig(req, res, pathSegments, queryParams),
|
|
40355
41301
|
() => handleFs(req, res, pathSegments, queryParams, myAgentId),
|
|
40356
41302
|
() => handleComb(req, res, pathSegments, queryParams, myAgentId),
|
|
@@ -40427,7 +41373,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
40427
41373
|
});
|
|
40428
41374
|
});
|
|
40429
41375
|
var detachRealtime = attachRealtimeTransport(httpServer);
|
|
40430
|
-
var { attachControllerTransport } = await import("./controllers-connect-
|
|
41376
|
+
var { attachControllerTransport } = await import("./controllers-connect-r2za39ef.js");
|
|
40431
41377
|
var detachControllers = attachControllerTransport(httpServer);
|
|
40432
41378
|
var stopWorkerNudges = startWorkerNudgeListener();
|
|
40433
41379
|
var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
|
|
@@ -40456,7 +41402,7 @@ async function shutdown() {
|
|
|
40456
41402
|
sessionsProcessed: getServerSessionsProcessed()
|
|
40457
41403
|
});
|
|
40458
41404
|
if (hasCapability("scheduling")) {
|
|
40459
|
-
const { stopScheduler } = await import("./index-
|
|
41405
|
+
const { stopScheduler } = await import("./index-38t35h0n.js");
|
|
40460
41406
|
stopScheduler();
|
|
40461
41407
|
}
|
|
40462
41408
|
stopHeartbeat2();
|
|
@@ -40468,7 +41414,7 @@ async function shutdown() {
|
|
|
40468
41414
|
await stopSlackApp2();
|
|
40469
41415
|
await stopChatSdk();
|
|
40470
41416
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
40471
|
-
const { stopOAuthKeepalive } = await import("./keepalive-
|
|
41417
|
+
const { stopOAuthKeepalive } = await import("./keepalive-em0117bp.js");
|
|
40472
41418
|
await stopOAuthKeepalive();
|
|
40473
41419
|
}
|
|
40474
41420
|
stopOAuthPendingGc();
|
|
@@ -40548,21 +41494,21 @@ try {
|
|
|
40548
41494
|
console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
|
|
40549
41495
|
}
|
|
40550
41496
|
try {
|
|
40551
|
-
const { ensurePricingSeeded } = await import("./boot-seeds-
|
|
41497
|
+
const { ensurePricingSeeded } = await import("./boot-seeds-9bmkspyw.js");
|
|
40552
41498
|
ensurePricingSeeded();
|
|
40553
|
-
const { startPricingRefreshLoop } = await import("./pricing-refresh-
|
|
41499
|
+
const { startPricingRefreshLoop } = await import("./pricing-refresh-yb75wv33.js");
|
|
40554
41500
|
startPricingRefreshLoop();
|
|
40555
41501
|
} catch (err) {
|
|
40556
41502
|
console.error("[startup] Failed to seed pricing rows:", err);
|
|
40557
41503
|
}
|
|
40558
41504
|
try {
|
|
40559
|
-
const { ensureModelProfilesSeeded } = await import("./boot-seeds-
|
|
41505
|
+
const { ensureModelProfilesSeeded } = await import("./boot-seeds-9bmkspyw.js");
|
|
40560
41506
|
await ensureModelProfilesSeeded();
|
|
40561
41507
|
} catch (err) {
|
|
40562
41508
|
console.error("[startup] Failed to seed model profiles:", err);
|
|
40563
41509
|
}
|
|
40564
41510
|
try {
|
|
40565
|
-
const { ensureRbacSeeded } = await import("./boot-seeds-
|
|
41511
|
+
const { ensureRbacSeeded } = await import("./boot-seeds-9bmkspyw.js");
|
|
40566
41512
|
ensureRbacSeeded();
|
|
40567
41513
|
} catch (err) {
|
|
40568
41514
|
console.error("[startup] Failed to sync RBAC seed rows:", err);
|
|
@@ -40570,7 +41516,7 @@ try {
|
|
|
40570
41516
|
throw err;
|
|
40571
41517
|
}
|
|
40572
41518
|
try {
|
|
40573
|
-
const { runAllSeeders } = await import("./index-
|
|
41519
|
+
const { runAllSeeders } = await import("./index-qhjf2htm.js");
|
|
40574
41520
|
await runAllSeeders({ scriptEmbeddingMode: "skip" });
|
|
40575
41521
|
} catch (err) {
|
|
40576
41522
|
console.error("[startup] Failed to seed built-in entities:", err);
|
|
@@ -40633,41 +41579,44 @@ httpServer.listen(port, async () => {
|
|
|
40633
41579
|
await initWorkflows2();
|
|
40634
41580
|
await startScriptRunSupervisor(getMcpBaseUrl());
|
|
40635
41581
|
if (hasCapability("scheduling")) {
|
|
40636
|
-
const { startScheduler } = await import("./index-
|
|
40637
|
-
const { getExecutorRegistry } = await import("./index-
|
|
41582
|
+
const { startScheduler } = await import("./index-38t35h0n.js");
|
|
41583
|
+
const { getExecutorRegistry } = await import("./index-k0yt1tvq.js");
|
|
40638
41584
|
const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
|
|
40639
41585
|
startScheduler(getExecutorRegistry(), intervalMs, {
|
|
40640
41586
|
runId: globalState.__runId
|
|
40641
41587
|
});
|
|
40642
41588
|
}
|
|
40643
41589
|
if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
|
|
40644
|
-
const { startHeartbeat } = await import("./index-
|
|
41590
|
+
const { startHeartbeat } = await import("./index-yqgbfgaj.js");
|
|
40645
41591
|
const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
|
|
40646
41592
|
startHeartbeat(heartbeatMs);
|
|
40647
41593
|
}
|
|
40648
41594
|
startPoolRouting();
|
|
40649
41595
|
startRuntimeSupervisor();
|
|
40650
41596
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
40651
|
-
const { startOAuthKeepalive } = await import("./keepalive-
|
|
41597
|
+
const { startOAuthKeepalive } = await import("./keepalive-em0117bp.js");
|
|
40652
41598
|
startOAuthKeepalive();
|
|
40653
41599
|
}
|
|
40654
41600
|
if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
|
|
40655
|
-
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-
|
|
41601
|
+
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-xysj4yse.js");
|
|
40656
41602
|
startOAuthRefreshSweep();
|
|
40657
41603
|
}
|
|
40658
41604
|
startOAuthPendingGc();
|
|
40659
41605
|
await startMemoryGc();
|
|
40660
41606
|
await startDbRetention();
|
|
40661
41607
|
startHumanFreeDrain();
|
|
40662
|
-
import("./boot-reembed-
|
|
41608
|
+
import("./boot-reembed-f4nn561n.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
|
|
40663
41609
|
console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
|
|
40664
41610
|
});
|
|
40665
|
-
import("./boot-reembed-
|
|
41611
|
+
import("./boot-reembed-6c1sjfnr.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
|
|
40666
41612
|
console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
|
|
40667
41613
|
});
|
|
40668
|
-
import("./boot-scrub-sweep-
|
|
41614
|
+
import("./boot-scrub-sweep-d4w9gajf.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
|
|
40669
41615
|
console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
|
|
40670
41616
|
});
|
|
41617
|
+
import("./session-source-backfill-qgtc86z1.js").then(({ runSessionSourceBackfill }) => runSessionSourceBackfill()).catch((err) => {
|
|
41618
|
+
console.error("[session-source-backfill] startup run failed (non-fatal):", err);
|
|
41619
|
+
});
|
|
40671
41620
|
}).on("error", (err) => {
|
|
40672
41621
|
console.error("HTTP Server Error:", err);
|
|
40673
41622
|
});
|