@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
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
|
-
type OpenAICompatibleProvider,
|
|
23
22
|
openAICompatibleKeyVars,
|
|
24
23
|
openAICompatibleProviders,
|
|
25
24
|
providerBaseUrl,
|
|
@@ -45,13 +44,35 @@ import type {
|
|
|
45
44
|
ProviderName,
|
|
46
45
|
ReasoningEffort,
|
|
47
46
|
} from "../types";
|
|
48
|
-
import { CLAUDE_CREDENTIALS_HINT } from "../utils/credentials";
|
|
49
47
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
CLAUDE_CREDENTIALS_HINT,
|
|
49
|
+
CREDENTIAL_POOL_VARS,
|
|
50
|
+
splitCredentialPool,
|
|
51
|
+
} from "../utils/credentials";
|
|
52
|
+
import {
|
|
53
|
+
checkAnthropicApiKey,
|
|
54
|
+
checkDeepSeekApiKey,
|
|
55
|
+
checkOpenAICompatibleProvider,
|
|
56
|
+
checkOpenAiApiKey,
|
|
57
|
+
checkOpenRouter,
|
|
58
|
+
checkXaiApiKey,
|
|
59
|
+
type LiveKeyResult,
|
|
60
|
+
type LiveValidationResult,
|
|
61
|
+
timedFetch,
|
|
62
|
+
} from "../utils/provider-key-probes";
|
|
53
63
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
54
64
|
|
|
65
|
+
export {
|
|
66
|
+
checkAnthropicApiKey,
|
|
67
|
+
checkDeepSeekApiKey,
|
|
68
|
+
checkOpenAICompatibleProvider,
|
|
69
|
+
checkOpenAiApiKey,
|
|
70
|
+
checkOpenRouter,
|
|
71
|
+
checkXaiApiKey,
|
|
72
|
+
type LiveKeyResult,
|
|
73
|
+
type LiveValidationResult,
|
|
74
|
+
} from "../utils/provider-key-probes";
|
|
75
|
+
|
|
55
76
|
export type SupportedProvider =
|
|
56
77
|
| "claude"
|
|
57
78
|
| "claude-managed"
|
|
@@ -215,46 +236,8 @@ export async function checkProviderCredentials(
|
|
|
215
236
|
// Mirrors `checkProviderCredentials` but issues a real (cheapest possible)
|
|
216
237
|
// upstream call so the user can flip the `harness` milestone to `verified`.
|
|
217
238
|
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
// safe. All errors run through `scrubSecrets` so we never leak the user's
|
|
221
|
-
// own key shape back through the JSON response.
|
|
222
|
-
|
|
223
|
-
const LIVE_TEST_TIMEOUT_MS = 5_000;
|
|
224
|
-
|
|
225
|
-
export interface LiveValidationResult {
|
|
226
|
-
ok: boolean;
|
|
227
|
-
error?: string;
|
|
228
|
-
latency_ms: number;
|
|
229
|
-
/** No free live check exists for this credential (cloud routes): report presence only. */
|
|
230
|
-
skipped?: boolean;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async function timedFetch(
|
|
234
|
-
url: string,
|
|
235
|
-
init: RequestInit,
|
|
236
|
-
): Promise<{ ok: boolean; status: number; bodyText: string; latency_ms: number }> {
|
|
237
|
-
const controller = new AbortController();
|
|
238
|
-
const timer = setTimeout(() => controller.abort(), LIVE_TEST_TIMEOUT_MS);
|
|
239
|
-
const start = Date.now();
|
|
240
|
-
try {
|
|
241
|
-
const res = await fetch(url, { ...init, signal: controller.signal });
|
|
242
|
-
let bodyText = "";
|
|
243
|
-
try {
|
|
244
|
-
bodyText = await res.text();
|
|
245
|
-
} catch {
|
|
246
|
-
// ignore body read errors — status alone is enough for ok/not-ok
|
|
247
|
-
}
|
|
248
|
-
return {
|
|
249
|
-
ok: res.ok,
|
|
250
|
-
status: res.status,
|
|
251
|
-
bodyText,
|
|
252
|
-
latency_ms: Date.now() - start,
|
|
253
|
-
};
|
|
254
|
-
} finally {
|
|
255
|
-
clearTimeout(timer);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
239
|
+
// Worker-only dispatch uses the shared probes in `provider-key-probes.ts`.
|
|
240
|
+
// The API imports those probes directly to avoid loading worker harnesses.
|
|
258
241
|
|
|
259
242
|
function asLiveError(err: unknown, latency_ms: number): LiveValidationResult {
|
|
260
243
|
const raw = err instanceof Error ? err.message : String(err);
|
|
@@ -265,6 +248,69 @@ function asLiveError(err: unknown, latency_ms: number): LiveValidationResult {
|
|
|
265
248
|
};
|
|
266
249
|
}
|
|
267
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Run `check` on every member of a comma pool in parallel. The pool passes
|
|
253
|
+
* when one key works (the runner skips a rejected key); `warning` names the
|
|
254
|
+
* keys that failed, and the check fails only when every key fails.
|
|
255
|
+
*/
|
|
256
|
+
export async function checkEachKey(
|
|
257
|
+
keyType: string,
|
|
258
|
+
value: string,
|
|
259
|
+
check: (key: string) => Promise<LiveValidationResult>,
|
|
260
|
+
): Promise<LiveValidationResult> {
|
|
261
|
+
const members = splitCredentialPool(value);
|
|
262
|
+
if (members.length === 0) members.push(value.trim());
|
|
263
|
+
const results = await Promise.all(
|
|
264
|
+
members.map(async (member) => {
|
|
265
|
+
const startedAt = Date.now();
|
|
266
|
+
try {
|
|
267
|
+
return await check(member);
|
|
268
|
+
} catch (err) {
|
|
269
|
+
return asLiveError(err, Date.now() - startedAt);
|
|
270
|
+
}
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
const latency_ms = Math.max(...results.map((result) => result.latency_ms));
|
|
274
|
+
if (results.every((result) => result.skipped)) return { ok: true, skipped: true, latency_ms };
|
|
275
|
+
const keys = results.map(
|
|
276
|
+
(result, index): LiveKeyResult => ({
|
|
277
|
+
keyType,
|
|
278
|
+
index,
|
|
279
|
+
suffix: members[index]!.slice(-5),
|
|
280
|
+
ok: result.ok,
|
|
281
|
+
...(result.error !== undefined ? { error: result.error } : {}),
|
|
282
|
+
...(result.httpStatus !== undefined ? { httpStatus: result.httpStatus } : {}),
|
|
283
|
+
latency_ms: result.latency_ms,
|
|
284
|
+
}),
|
|
285
|
+
);
|
|
286
|
+
const failed = keys.filter((key) => !key.ok);
|
|
287
|
+
if (failed.length === 0) return { ok: true, latency_ms, keys };
|
|
288
|
+
const failures = failed
|
|
289
|
+
.map(
|
|
290
|
+
(key) =>
|
|
291
|
+
`key ending ${key.suffix} (${key.httpStatus !== undefined ? `HTTP ${key.httpStatus}` : (key.error ?? "Unknown error")})`,
|
|
292
|
+
)
|
|
293
|
+
.join(", ");
|
|
294
|
+
if (failed.length < keys.length) {
|
|
295
|
+
return {
|
|
296
|
+
ok: true,
|
|
297
|
+
latency_ms,
|
|
298
|
+
keys,
|
|
299
|
+
warning: `${failed.length} of ${keys.length} keys failed: ${failures}.`,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (keys.length === 1) {
|
|
303
|
+
return {
|
|
304
|
+
ok: false,
|
|
305
|
+
error: failed[0]!.error,
|
|
306
|
+
httpStatus: failed[0]!.httpStatus,
|
|
307
|
+
latency_ms,
|
|
308
|
+
keys,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
return { ok: false, error: `All ${keys.length} keys failed: ${failures}.`, latency_ms, keys };
|
|
312
|
+
}
|
|
313
|
+
|
|
268
314
|
// ─── Per-endpoint live-call helpers ──────────────────────────────────────────
|
|
269
315
|
// Each helper accepts the auth material it needs and returns a normalized
|
|
270
316
|
// `LiveValidationResult`. The harness-level dispatcher below picks which
|
|
@@ -272,22 +318,10 @@ function asLiveError(err: unknown, latency_ms: number): LiveValidationResult {
|
|
|
272
318
|
// users no longer see "ANTHROPIC_API_KEY is not set" when their adapter is
|
|
273
319
|
// happily running off `CLAUDE_CODE_OAUTH_TOKEN`.
|
|
274
320
|
|
|
275
|
-
async function checkAnthropicApiKey(apiKey: string): Promise<LiveValidationResult> {
|
|
276
|
-
const r = await timedFetch("https://api.anthropic.com/v1/models", {
|
|
277
|
-
method: "GET",
|
|
278
|
-
headers: { "x-api-key": apiKey, "anthropic-version": "2023-06-01" },
|
|
279
|
-
});
|
|
280
|
-
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
281
|
-
return {
|
|
282
|
-
ok: false,
|
|
283
|
-
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
284
|
-
latency_ms: r.latency_ms,
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
321
|
/**
|
|
289
|
-
* OAuth credentials (
|
|
290
|
-
*
|
|
322
|
+
* Codex OAuth credentials (ChatGPT login) are treated as a presence check — we
|
|
323
|
+
* don't issue a live upstream call. (Claude subscription tokens get a real
|
|
324
|
+
* check through the route: see `claudeSubscriptionProvider`.)
|
|
291
325
|
*
|
|
292
326
|
* Why: OAuth flows include their own refresh logic (handled at adapter boot,
|
|
293
327
|
* not here), the OAuth-bearer-with-/v1/models contract isn't a stable public
|
|
@@ -299,70 +333,6 @@ function presenceCheckOk(): LiveValidationResult {
|
|
|
299
333
|
return { ok: true, latency_ms: 0 };
|
|
300
334
|
}
|
|
301
335
|
|
|
302
|
-
async function checkOpenAiApiKey(apiKey: string): Promise<LiveValidationResult> {
|
|
303
|
-
const r = await timedFetch("https://api.openai.com/v1/models", {
|
|
304
|
-
method: "GET",
|
|
305
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
306
|
-
});
|
|
307
|
-
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
308
|
-
return {
|
|
309
|
-
ok: false,
|
|
310
|
-
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
311
|
-
latency_ms: r.latency_ms,
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/** `GET /v1/models` is the call the Grok CLI makes first; it runs no inference. */
|
|
316
|
-
async function checkXaiApiKey(apiKey: string): Promise<LiveValidationResult> {
|
|
317
|
-
const r = await timedFetch("https://api.x.ai/v1/models", {
|
|
318
|
-
method: "GET",
|
|
319
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
320
|
-
});
|
|
321
|
-
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
322
|
-
return {
|
|
323
|
-
ok: false,
|
|
324
|
-
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
325
|
-
latency_ms: r.latency_ms,
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
async function checkOpenRouter(apiKey: string): Promise<LiveValidationResult> {
|
|
330
|
-
const url = `${getOpenRouterBaseUrl()}/models`;
|
|
331
|
-
const r = await timedFetch(url, {
|
|
332
|
-
method: "GET",
|
|
333
|
-
headers: { ...getOpenRouterAttributionHeaders(url), Authorization: `Bearer ${apiKey}` },
|
|
334
|
-
});
|
|
335
|
-
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
336
|
-
return {
|
|
337
|
-
ok: false,
|
|
338
|
-
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
339
|
-
latency_ms: r.latency_ms,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* `GET <baseUrl>/models` with a Bearer key against an OpenAI-compatible
|
|
345
|
-
* registry provider (NaN, Helmcode). Lists models, runs no inference.
|
|
346
|
-
* `baseUrl` defaults to the registry entry; the probe passes the
|
|
347
|
-
* `<ID>_BASE_URL` override, and tests inject a fake server.
|
|
348
|
-
*/
|
|
349
|
-
export async function checkOpenAICompatibleProvider(
|
|
350
|
-
provider: OpenAICompatibleProvider,
|
|
351
|
-
apiKey: string,
|
|
352
|
-
baseUrl: string = provider.baseUrl,
|
|
353
|
-
): Promise<LiveValidationResult> {
|
|
354
|
-
const r = await timedFetch(`${baseUrl.replace(/\/+$/, "")}/models`, {
|
|
355
|
-
method: "GET",
|
|
356
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
357
|
-
});
|
|
358
|
-
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
359
|
-
return {
|
|
360
|
-
ok: false,
|
|
361
|
-
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
362
|
-
latency_ms: r.latency_ms,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
336
|
/**
|
|
367
337
|
* Mirror of the disk check in `checkCodexCredentials` — true when the worker
|
|
368
338
|
* has a materialised `~/.codex/auth.json`, which is the canonical "logged in"
|
|
@@ -402,14 +372,15 @@ function parseCodexOAuthAccess(blob: string | undefined): string | null {
|
|
|
402
372
|
*
|
|
403
373
|
* | Harness | Accepted credentials (in resolution order) | Endpoint |
|
|
404
374
|
* |------------------|-------------------------------------------------------------------------|--------------------------------|
|
|
405
|
-
* | `claude` | default route: Foundry / Bedrock / Vertex → gateway (`ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY`) → `CLAUDE_CODE_OAUTH_TOKEN` → `ANTHROPIC_API_KEY` | the route's own `/v1/models`; OAuth
|
|
375
|
+
* | `claude` | default route: Foundry / Bedrock / Vertex → gateway (`ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY`) → `CLAUDE_CODE_OAUTH_TOKEN` → `ANTHROPIC_API_KEY` | the route's own `/v1/models`; OAuth: `/api/oauth/profile` (403 scope = ok); cloud routes skipped |
|
|
406
376
|
* | `claude-managed` | `ANTHROPIC_API_KEY` (managed agents always use API key + managed envs) | Anthropic `/v1/models` |
|
|
407
377
|
* | `codex` | `~/.codex/auth.json` (file) → `CODEX_OAUTH` (env OAuth) → `OPENAI_API_KEY` | OpenAI `/v1/models` (api-key path only) |
|
|
408
|
-
* | `opencode` | auth.json (file) → `OPENROUTER_API_KEY` → `ANTHROPIC_API_KEY` → `OPENAI_API_KEY` → each registry provider key (`NAN_API_KEY` or `HELMCODE_API_NAN`, `HELMCODE_API_KEY`) | file presence-only, otherwise provider's `/v1/models` |
|
|
378
|
+
* | `opencode` | auth.json (file) → `OPENROUTER_API_KEY` → `ANTHROPIC_API_KEY` → `OPENAI_API_KEY` → each registry provider key (`NAN_API_KEY` or `HELMCODE_API_NAN`, `HELMCODE_API_KEY`) | file presence-only, otherwise OpenRouter `/key` or the provider's `/v1/models` |
|
|
409
379
|
* | `pi` | auth.json (file) → provider API keys, including model-specific keys | file/model-specific key presence-only, otherwise provider's `/v1/models` |
|
|
410
380
|
* | `acp` | target-specific (the ACP target process owns its own auth) | presence-only (validated by the target process) |
|
|
411
381
|
* | `pi` (bedrock) | `MODEL_OVERRIDE=amazon-bedrock/*` → AWS SDK default credential chain | presence-only (real check is the worker-side Bedrock enumeration) |
|
|
412
382
|
* | `devin` | `DEVIN_API_KEY` (+ `DEVIN_API_BASE_URL` override) | `${baseUrl}/v3/self` |
|
|
383
|
+
* | `dsh` | `DEEPSEEK_API_KEY` → `OPENROUTER_API_KEY` | DeepSeek `/models`, or OpenRouter `/key` |
|
|
413
384
|
* | `amp` | `AMP_API_KEY` | `amp usage` (credit balance, no inference; 5s timeout) |
|
|
414
385
|
*
|
|
415
386
|
* Returns `{ok: true, latency_ms}` on 2xx, `{ok: false, error, latency_ms}`
|
|
@@ -429,8 +400,9 @@ export async function validateProviderCredentials(
|
|
|
429
400
|
case "claude": {
|
|
430
401
|
// The default route decides where the check goes: a gateway key is
|
|
431
402
|
// checked against the gateway only (scoped fetch), never against
|
|
432
|
-
// api.anthropic.com.
|
|
433
|
-
// free check and report
|
|
403
|
+
// api.anthropic.com. A subscription token is checked against
|
|
404
|
+
// `/api/oauth/profile`; cloud routes have no free check and report
|
|
405
|
+
// `configured` (no live test).
|
|
434
406
|
const route = deriveDefaultRoute("claude", env);
|
|
435
407
|
if (!route) {
|
|
436
408
|
return {
|
|
@@ -439,16 +411,40 @@ export async function validateProviderCredentials(
|
|
|
439
411
|
latency_ms: Date.now() - startedAt,
|
|
440
412
|
};
|
|
441
413
|
}
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
414
|
+
const checkRoute = async (
|
|
415
|
+
routeEnv: Record<string, string | undefined>,
|
|
416
|
+
): Promise<LiveValidationResult> => {
|
|
417
|
+
const start = Date.now();
|
|
418
|
+
const result = await validateRoute(route, routeEnv);
|
|
419
|
+
const latency_ms = Date.now() - start;
|
|
420
|
+
if (result.status === "verified") return { ok: true, latency_ms };
|
|
421
|
+
if (result.status === "configured") return { ok: true, skipped: true, latency_ms };
|
|
422
|
+
return {
|
|
423
|
+
ok: false,
|
|
424
|
+
error: scrubSecrets(result.reason),
|
|
425
|
+
httpStatus: result.httpStatus,
|
|
426
|
+
latency_ms,
|
|
427
|
+
};
|
|
428
|
+
};
|
|
429
|
+
const keyVar =
|
|
430
|
+
route.auth.kind === "subscription"
|
|
431
|
+
? "CLAUDE_CODE_OAUTH_TOKEN"
|
|
432
|
+
: "secretKey" in route.auth
|
|
433
|
+
? route.auth.secretKey
|
|
434
|
+
: undefined;
|
|
435
|
+
const value = keyVar ? env[keyVar] : undefined;
|
|
436
|
+
// Only pool vars are split: the runner never splits a gateway token.
|
|
437
|
+
if (keyVar && value && (CREDENTIAL_POOL_VARS as readonly string[]).includes(keyVar)) {
|
|
438
|
+
return checkEachKey(keyVar, value, (member) => checkRoute({ ...env, [keyVar]: member }));
|
|
439
|
+
}
|
|
440
|
+
return checkRoute(env);
|
|
447
441
|
}
|
|
448
442
|
case "claude-managed": {
|
|
449
443
|
// Managed agents always run with an API key — OAuth not supported on
|
|
450
444
|
// the managed-agents path today.
|
|
451
|
-
if (env.ANTHROPIC_API_KEY)
|
|
445
|
+
if (env.ANTHROPIC_API_KEY) {
|
|
446
|
+
return checkEachKey("ANTHROPIC_API_KEY", env.ANTHROPIC_API_KEY, checkAnthropicApiKey);
|
|
447
|
+
}
|
|
452
448
|
return {
|
|
453
449
|
ok: false,
|
|
454
450
|
error: "ANTHROPIC_API_KEY is not set.",
|
|
@@ -456,6 +452,22 @@ export async function validateProviderCredentials(
|
|
|
456
452
|
};
|
|
457
453
|
}
|
|
458
454
|
case "codex": {
|
|
455
|
+
// A gateway route is checked against the gateway only (scoped fetch
|
|
456
|
+
// to its own `/models`), never against api.openai.com, and wins over
|
|
457
|
+
// every OAuth / auth.json / OPENAI_API_KEY check below.
|
|
458
|
+
const gateway = deriveDefaultRoute("codex", env);
|
|
459
|
+
if (gateway) {
|
|
460
|
+
const result = await validateRoute(gateway, env);
|
|
461
|
+
const latency_ms = Date.now() - startedAt;
|
|
462
|
+
if (result.status === "verified") return { ok: true, latency_ms };
|
|
463
|
+
if (result.status === "configured") return { ok: true, skipped: true, latency_ms };
|
|
464
|
+
return {
|
|
465
|
+
ok: false,
|
|
466
|
+
error: scrubSecrets(result.reason),
|
|
467
|
+
httpStatus: result.httpStatus,
|
|
468
|
+
latency_ms,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
459
471
|
// Resolution order matches `checkCodexCredentials`:
|
|
460
472
|
// 1) `~/.codex/auth.json` on disk (canonical state once `codex login`
|
|
461
473
|
// has run, or when the entrypoint pre-materialised it from
|
|
@@ -474,7 +486,9 @@ export async function validateProviderCredentials(
|
|
|
474
486
|
if (codexAuthFileExists(env)) return presenceCheckOk();
|
|
475
487
|
if (parseCodexOAuthAccess(env.CODEX_OAUTH)) return presenceCheckOk();
|
|
476
488
|
if (hasCodexOAuthPoolSlots(env)) return presenceCheckOk();
|
|
477
|
-
if (env.OPENAI_API_KEY)
|
|
489
|
+
if (env.OPENAI_API_KEY) {
|
|
490
|
+
return checkEachKey("OPENAI_API_KEY", env.OPENAI_API_KEY, checkOpenAiApiKey);
|
|
491
|
+
}
|
|
478
492
|
return {
|
|
479
493
|
ok: false,
|
|
480
494
|
error:
|
|
@@ -503,13 +517,21 @@ export async function validateProviderCredentials(
|
|
|
503
517
|
// registry providers in declaration order (NaN, canonical key or
|
|
504
518
|
// alias → Helmcode) at their `<ID>_BASE_URL`, so existing env
|
|
505
519
|
// combinations keep their probe.
|
|
506
|
-
if (env.OPENROUTER_API_KEY)
|
|
507
|
-
|
|
508
|
-
|
|
520
|
+
if (env.OPENROUTER_API_KEY) {
|
|
521
|
+
return checkEachKey("OPENROUTER_API_KEY", env.OPENROUTER_API_KEY, checkOpenRouter);
|
|
522
|
+
}
|
|
523
|
+
if (env.ANTHROPIC_API_KEY) {
|
|
524
|
+
return checkEachKey("ANTHROPIC_API_KEY", env.ANTHROPIC_API_KEY, checkAnthropicApiKey);
|
|
525
|
+
}
|
|
526
|
+
if (env.OPENAI_API_KEY) {
|
|
527
|
+
return checkEachKey("OPENAI_API_KEY", env.OPENAI_API_KEY, checkOpenAiApiKey);
|
|
528
|
+
}
|
|
509
529
|
for (const direct of openAICompatibleProviders()) {
|
|
510
530
|
const key = providerKeyFromEnv(direct, env);
|
|
511
531
|
if (key) {
|
|
512
|
-
return
|
|
532
|
+
return checkEachKey(direct.envVar, key, (member) =>
|
|
533
|
+
checkOpenAICompatibleProvider(direct, member, providerBaseUrl(direct, env)),
|
|
534
|
+
);
|
|
513
535
|
}
|
|
514
536
|
}
|
|
515
537
|
// Model-specific keys (e.g. GEMINI_API_KEY) can satisfy readiness
|
|
@@ -534,28 +556,36 @@ export async function validateProviderCredentials(
|
|
|
534
556
|
};
|
|
535
557
|
}
|
|
536
558
|
const baseUrl = env.DEVIN_API_BASE_URL ?? "https://api.devin.ai";
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
559
|
+
return checkEachKey("DEVIN_API_KEY", apiKey, async (member) => {
|
|
560
|
+
const r = await timedFetch(`${baseUrl.replace(/\/+$/, "")}/v3/self`, {
|
|
561
|
+
method: "GET",
|
|
562
|
+
headers: {
|
|
563
|
+
Authorization: `Bearer ${member}`,
|
|
564
|
+
"Content-Type": "application/json",
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
568
|
+
return {
|
|
569
|
+
ok: false,
|
|
570
|
+
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
571
|
+
httpStatus: r.status,
|
|
572
|
+
latency_ms: r.latency_ms,
|
|
573
|
+
};
|
|
543
574
|
});
|
|
544
|
-
|
|
575
|
+
}
|
|
576
|
+
case "dsh": {
|
|
577
|
+
// Same precedence as `checkDshCredentials`: the DeepSeek key, then OpenRouter.
|
|
578
|
+
const deepseekKey = env.DEEPSEEK_API_KEY?.trim();
|
|
579
|
+
if (deepseekKey) return checkEachKey("DEEPSEEK_API_KEY", deepseekKey, checkDeepSeekApiKey);
|
|
580
|
+
const openRouterKey = env.OPENROUTER_API_KEY?.trim();
|
|
581
|
+
if (openRouterKey)
|
|
582
|
+
return checkEachKey("OPENROUTER_API_KEY", openRouterKey, checkOpenRouter);
|
|
545
583
|
return {
|
|
546
584
|
ok: false,
|
|
547
|
-
error:
|
|
548
|
-
latency_ms:
|
|
585
|
+
error: "Set DEEPSEEK_API_KEY or OPENROUTER_API_KEY for dsh.",
|
|
586
|
+
latency_ms: Date.now() - startedAt,
|
|
549
587
|
};
|
|
550
588
|
}
|
|
551
|
-
case "dsh":
|
|
552
|
-
return checkDshCredentials(env).ready
|
|
553
|
-
? presenceCheckOk()
|
|
554
|
-
: {
|
|
555
|
-
ok: false,
|
|
556
|
-
error: "Set DEEPSEEK_API_KEY or OPENROUTER_API_KEY for dsh.",
|
|
557
|
-
latency_ms: Date.now() - startedAt,
|
|
558
|
-
};
|
|
559
589
|
case "amp": {
|
|
560
590
|
if (!checkAmpCredentials(env).ready) {
|
|
561
591
|
return {
|
|
@@ -565,14 +595,17 @@ export async function validateProviderCredentials(
|
|
|
565
595
|
};
|
|
566
596
|
}
|
|
567
597
|
// `amp usage` reads the credit balance and runs no inference.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
598
|
+
return checkEachKey("AMP_API_KEY", env.AMP_API_KEY!, async (member) => {
|
|
599
|
+
const start = Date.now();
|
|
600
|
+
const live = await liveTestAmpCredentials({ ...env, AMP_API_KEY: member });
|
|
601
|
+
return live.ok
|
|
602
|
+
? { ok: true, latency_ms: Date.now() - start }
|
|
603
|
+
: {
|
|
604
|
+
ok: false,
|
|
605
|
+
error: live.error ?? "amp usage failed",
|
|
606
|
+
latency_ms: Date.now() - start,
|
|
607
|
+
};
|
|
608
|
+
});
|
|
576
609
|
}
|
|
577
610
|
case "cursor": {
|
|
578
611
|
const apiKey = env.CURSOR_API_KEY?.trim();
|
|
@@ -584,16 +617,21 @@ export async function validateProviderCredentials(
|
|
|
584
617
|
};
|
|
585
618
|
}
|
|
586
619
|
const { liveTestCursorKey } = await import("../providers/cursor-adapter");
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
620
|
+
return checkEachKey("CURSOR_API_KEY", apiKey, async (member) => {
|
|
621
|
+
const start = Date.now();
|
|
622
|
+
const result = await liveTestCursorKey(member);
|
|
623
|
+
return result.ok
|
|
624
|
+
? { ok: true, latency_ms: Date.now() - start }
|
|
625
|
+
: { ok: false, error: result.error, latency_ms: Date.now() - start };
|
|
626
|
+
});
|
|
591
627
|
}
|
|
592
628
|
case "grok": {
|
|
593
629
|
const apiKey = env.XAI_API_KEY?.trim();
|
|
594
|
-
if (apiKey) return
|
|
630
|
+
if (apiKey) return checkEachKey("XAI_API_KEY", apiKey, checkXaiApiKey);
|
|
595
631
|
const openRouterKey = env.OPENROUTER_API_KEY?.trim();
|
|
596
|
-
if (openRouterKey)
|
|
632
|
+
if (openRouterKey) {
|
|
633
|
+
return checkEachKey("OPENROUTER_API_KEY", openRouterKey, checkOpenRouter);
|
|
634
|
+
}
|
|
597
635
|
return {
|
|
598
636
|
ok: false,
|
|
599
637
|
error: "Set XAI_API_KEY or OPENROUTER_API_KEY for grok.",
|
|
@@ -653,6 +691,8 @@ export async function buildCredStatusReport(
|
|
|
653
691
|
error: live.error ?? null,
|
|
654
692
|
latency_ms: live.latency_ms,
|
|
655
693
|
testedAt: Date.now(),
|
|
694
|
+
...(live.warning !== undefined ? { warning: live.warning } : {}),
|
|
695
|
+
...(live.keys !== undefined ? { keys: live.keys } : {}),
|
|
656
696
|
};
|
|
657
697
|
}
|
|
658
698
|
// Include the Bedrock enumeration block when the pi probe ran in Bedrock SDK
|
package/src/commands/runner.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { deriveDefaultRoute } from "@desplega/model-routing";
|
|
3
4
|
import type { TemplateResponse } from "../../templates/schema.ts";
|
|
4
5
|
import {
|
|
5
6
|
type Attributes,
|
|
@@ -118,7 +119,13 @@ import {
|
|
|
118
119
|
prependContextPreamble,
|
|
119
120
|
} from "./context-preamble.ts";
|
|
120
121
|
import { reportCredentialOutcomeThenFinish } from "./credential-outcome-report.ts";
|
|
121
|
-
import {
|
|
122
|
+
import {
|
|
123
|
+
type CredentialRefreshState,
|
|
124
|
+
credentialFingerprint,
|
|
125
|
+
recheckableFailures,
|
|
126
|
+
refreshCredentialStatus,
|
|
127
|
+
reportKeyValidation,
|
|
128
|
+
} from "./credential-refresh.ts";
|
|
122
129
|
import {
|
|
123
130
|
awaitCredentials,
|
|
124
131
|
BootMaxWaitExceededError,
|
|
@@ -831,6 +838,8 @@ export async function exitAfterTasksIfFinished(
|
|
|
831
838
|
*/
|
|
832
839
|
export interface ResolvedEnvResult {
|
|
833
840
|
env: Record<string, string | undefined>;
|
|
841
|
+
/** Full credential pools for live validation. Keep this environment in process only. */
|
|
842
|
+
credentialEnv: Record<string, string | undefined>;
|
|
834
843
|
credentialSelections: CredentialSelection[];
|
|
835
844
|
/** Raw config-row value, kept separate from the merged environment so an
|
|
836
845
|
* actual worker environment variable retains precedence. */
|
|
@@ -1049,6 +1058,7 @@ export async function fetchResolvedEnv(
|
|
|
1049
1058
|
});
|
|
1050
1059
|
const effectiveModel = modelSelection.model || (env.MODEL_OVERRIDE as string | undefined) || "";
|
|
1051
1060
|
|
|
1061
|
+
const credentialEnv = { ...env };
|
|
1052
1062
|
const credentialSelections = await resolveCredentialPools(env, {
|
|
1053
1063
|
apiUrl,
|
|
1054
1064
|
apiKey,
|
|
@@ -1065,7 +1075,7 @@ export async function fetchResolvedEnv(
|
|
|
1065
1075
|
enforceModelCapacity: sessionContext?.enforceModelCapacity,
|
|
1066
1076
|
});
|
|
1067
1077
|
|
|
1068
|
-
return { env, credentialSelections, resolvedProvider, scriptsOnlyConfigValue };
|
|
1078
|
+
return { env, credentialEnv, credentialSelections, resolvedProvider, scriptsOnlyConfigValue };
|
|
1069
1079
|
}
|
|
1070
1080
|
|
|
1071
1081
|
/**
|
|
@@ -3352,6 +3362,8 @@ export interface PollOptions {
|
|
|
3352
3362
|
pollTimeout: number;
|
|
3353
3363
|
/** Push scheduling fetches once, then returns control to the runner. */
|
|
3354
3364
|
singlePoll?: boolean;
|
|
3365
|
+
/** Stop an open poll window before its next claim request. */
|
|
3366
|
+
shouldStop?: () => boolean;
|
|
3355
3367
|
/** Distinguishes a failed fetch from an empty successful response. */
|
|
3356
3368
|
onPollFailure?: () => void;
|
|
3357
3369
|
since?: string; // Optional: for filtering finished tasks
|
|
@@ -3669,6 +3681,7 @@ async function pollForTriggerOnce(opts: PollOptions): Promise<Trigger | null> {
|
|
|
3669
3681
|
}
|
|
3670
3682
|
|
|
3671
3683
|
while (Date.now() - startTime < opts.pollTimeout) {
|
|
3684
|
+
if (opts.shouldStop?.()) return null;
|
|
3672
3685
|
try {
|
|
3673
3686
|
// Build URL with optional since parameter
|
|
3674
3687
|
let url = `${opts.apiUrl}/api/poll`;
|
|
@@ -4316,7 +4329,9 @@ async function spawnProviderProcess(
|
|
|
4316
4329
|
// config-store slot — gates whether `codexSlot` is set below (see
|
|
4317
4330
|
// `CodexOAuthCredentialInfo`).
|
|
4318
4331
|
let oauthIsPoolBacked = false;
|
|
4319
|
-
|
|
4332
|
+
// A gateway route uses no OAuth: no pool slot is picked, so no auth.json is
|
|
4333
|
+
// materialised for a session whose traffic goes to the gateway.
|
|
4334
|
+
if (adapter.name === "codex" && !deriveDefaultRoute("codex", freshEnv)) {
|
|
4320
4335
|
const oauthInfo = await resolveCodexOAuthCredentialInfo(opts.apiUrl, opts.apiKey);
|
|
4321
4336
|
oauthSelection = oauthInfo?.selection;
|
|
4322
4337
|
oauthIsPoolBacked = oauthInfo?.isPoolBacked ?? false;
|
|
@@ -6016,7 +6031,10 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
6016
6031
|
ready: null,
|
|
6017
6032
|
lastRefreshAt: 0,
|
|
6018
6033
|
inFlight: false,
|
|
6034
|
+
fingerprint: null,
|
|
6035
|
+
rejectedKeys: 0,
|
|
6019
6036
|
};
|
|
6037
|
+
let latestCredentialEnv: Record<string, string | undefined> | undefined;
|
|
6020
6038
|
|
|
6021
6039
|
// Throttle for live HARNESS_PROVIDER reconciliation. Each reconciliation
|
|
6022
6040
|
// calls `fetchResolvedEnv` which also re-resolves credential pools — we
|
|
@@ -6410,6 +6428,10 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
6410
6428
|
credentialRefreshState.harnessProvider = state.harnessProvider;
|
|
6411
6429
|
credentialRefreshState.ready = bootCredSnapshot?.ready ?? true;
|
|
6412
6430
|
credentialRefreshState.lastRefreshAt = Date.now();
|
|
6431
|
+
credentialRefreshState.fingerprint = credentialFingerprint(process.env);
|
|
6432
|
+
credentialRefreshState.rejectedKeys = recheckableFailures(bootCredSnapshot?.liveTest);
|
|
6433
|
+
const keys = bootCredSnapshot?.liveTest?.keys;
|
|
6434
|
+
if (keys?.length) await reportKeyValidation(apiConfig, keys);
|
|
6413
6435
|
} catch (error) {
|
|
6414
6436
|
console.error(`[${role}] Failed to report credential readiness after recovery: ${error}`);
|
|
6415
6437
|
process.exit(1);
|
|
@@ -7012,9 +7034,11 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
7012
7034
|
try {
|
|
7013
7035
|
const {
|
|
7014
7036
|
env: freshEnv,
|
|
7037
|
+
credentialEnv,
|
|
7015
7038
|
resolvedProvider,
|
|
7016
7039
|
scriptsOnlyConfigValue,
|
|
7017
7040
|
} = await fetchResolvedEnv(apiUrl, apiKey, agentId);
|
|
7041
|
+
latestCredentialEnv = credentialEnv;
|
|
7018
7042
|
const nextScriptsOnly = resolveScriptsOnlyMode({
|
|
7019
7043
|
env: process.env.SCRIPTS_ONLY_MCP,
|
|
7020
7044
|
configValue: scriptsOnlyConfigValue,
|
|
@@ -7046,7 +7070,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
7046
7070
|
apiConfig,
|
|
7047
7071
|
credentialRefreshState,
|
|
7048
7072
|
state.harnessProvider,
|
|
7049
|
-
process.env,
|
|
7073
|
+
latestCredentialEnv ?? process.env,
|
|
7050
7074
|
).catch((err) =>
|
|
7051
7075
|
console.warn(`[${role}] cred_status post_task refresh failed (non-fatal): ${err}`),
|
|
7052
7076
|
);
|
|
@@ -7099,7 +7123,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
7099
7123
|
}
|
|
7100
7124
|
}
|
|
7101
7125
|
|
|
7102
|
-
// Only poll if we have capacity and the API is
|
|
7126
|
+
// Only poll if we have capacity and neither the API nor worker is draining
|
|
7103
7127
|
const schedule = pushDelivery.schedule({
|
|
7104
7128
|
mode: state.deliveryMode ?? "poll",
|
|
7105
7129
|
push: deliveryChecks.push,
|
|
@@ -7108,7 +7132,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
7108
7132
|
exitAfterTasks === null
|
|
7109
7133
|
? state.maxConcurrent
|
|
7110
7134
|
: Math.min(state.maxConcurrent, Math.max(0, exitAfterTasks - state.tasksProcessed)),
|
|
7111
|
-
draining: state.apiDraining,
|
|
7135
|
+
draining: state.apiDraining || shuttingDown,
|
|
7112
7136
|
lastPushPingAt,
|
|
7113
7137
|
pollInterval: PollIntervalMs,
|
|
7114
7138
|
});
|
|
@@ -7146,6 +7170,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
7146
7170
|
runtimeInstanceId,
|
|
7147
7171
|
pollTimeout: effectiveTimeout,
|
|
7148
7172
|
singlePoll: schedule.singlePoll,
|
|
7173
|
+
shouldStop: () => shuttingDown,
|
|
7149
7174
|
onPollFailure,
|
|
7150
7175
|
harnessProvider: state.harnessProvider,
|
|
7151
7176
|
onApiDrainSignal: (draining) => applyApiDrainSignal(state, role, draining),
|