@desplega.ai/agent-swarm 1.158.0 → 1.160.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
- package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
- package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
- package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
- package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
- package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
- package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
- package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
- package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
- package/dist/boot-seeds-gsetbs5y.js +28 -0
- package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
- package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
- package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
- package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
- package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
- package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
- package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
- package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
- package/dist/cli-0x01kwrd.js +491 -0
- package/dist/cli-0xqde53b.js +176 -0
- package/dist/cli-10nhj6xq.js +8355 -0
- package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
- package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
- package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
- package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
- package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
- package/dist/cli-3qhyh31j.js +166 -0
- package/dist/cli-447dt1h3.js +3828 -0
- package/dist/cli-4derpgyk.js +115 -0
- package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
- package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
- package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
- package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
- package/dist/cli-741yb0xx.js +1027 -0
- package/dist/cli-74h9hscv.js +69 -0
- package/dist/cli-7cxw8b60.js +14910 -0
- package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
- package/dist/cli-7kyk9jr3.js +22 -0
- package/dist/cli-89s4ngw3.js +183 -0
- package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
- package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
- package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
- package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
- package/dist/cli-br0qdrnp.js +2150 -0
- package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
- package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
- package/dist/cli-cpvsaqsw.js +333 -0
- package/dist/cli-d5czme6m.js +17805 -0
- package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
- package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
- package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
- package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
- package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
- package/dist/cli-gt4hxb8p.js +99 -0
- package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
- package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
- package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
- package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
- package/dist/cli-kmcpfwn2.js +333856 -0
- package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
- package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
- package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
- package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
- package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
- package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
- package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
- package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
- package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
- package/dist/cli-rb9m6rpe.js +4980 -0
- package/dist/cli-rykfmgwg.js +102 -0
- package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
- package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
- package/dist/cli-tfky2838.js +756 -0
- package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
- package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
- package/dist/cli-trc24wk2.js +143 -0
- package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
- package/dist/cli-v7fn5gms.js +1425 -0
- package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
- package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
- package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
- package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
- package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
- package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
- package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
- package/dist/cli-zpep9q5e.js +491 -0
- package/dist/cli.js +41 -32
- package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
- package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
- package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
- package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
- package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
- package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
- package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
- package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
- package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
- package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
- package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
- package/dist/execute-6e7qeyk4.js +1017 -0
- package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
- package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
- package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
- package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
- package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
- package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
- package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
- package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
- package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
- package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
- package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
- package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
- package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
- package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
- package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
- package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
- package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
- package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
- package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
- package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
- package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
- package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
- package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
- package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
- package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
- package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
- package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
- package/dist/pricing-refresh-wx0tp7cb.js +39 -0
- package/dist/quickjs-r1pq2107.wasm +0 -0
- package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
- package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
- package/dist/runtime-zyssgse0.js +24 -0
- package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
- package/dist/typesafe-system-one-2ef30pec.js +27 -0
- package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
- package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
- package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
- package/openapi.json +1314 -91
- package/package.json +12 -11
- package/src/be/db/agents.ts +20 -0
- package/src/be/db/api-keys.ts +70 -0
- package/src/be/db/tasks/human-free.ts +442 -0
- package/src/be/db/tasks/read.ts +56 -1
- package/src/be/db/tasks/write.ts +107 -11
- package/src/be/db.ts +274 -188
- package/src/be/harness-model-support.ts +182 -0
- package/src/be/human-free-drain.ts +67 -0
- package/src/be/memory/providers/sqlite-store.ts +51 -15
- package/src/be/migrations/182_task_human_free_flag.sql +63 -0
- package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
- package/src/be/migrations/184_model_catalog.sql +120 -0
- package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
- package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
- package/src/be/model-catalog-store.ts +644 -0
- package/src/be/model-tier-keys.ts +46 -0
- package/src/be/model-tier-resolution.ts +534 -0
- package/src/be/model-validation.ts +188 -0
- package/src/be/models-catalog.ts +61 -7
- package/src/be/modelsdev-cache.json +82 -0
- package/src/be/modelsdev-cache.ts +2 -0
- package/src/be/pricing-refresh.ts +154 -12
- package/src/be/scripts/typecheck.ts +15 -0
- package/src/be/seed/runner.ts +18 -12
- package/src/be/seed/types.ts +1 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
- package/src/be/swarm-config-guard.ts +8 -0
- package/src/cli.tsx +10 -0
- package/src/commands/claude-managed-setup.ts +3 -1
- package/src/commands/codex-login.ts +67 -0
- package/src/commands/credential-outcome-report.ts +191 -0
- package/src/commands/rate-limit-outcome.ts +34 -4
- package/src/commands/runner.ts +357 -186
- package/src/commands/seat-mismatch-report.ts +46 -0
- package/src/extensions/apply-task-create.ts +27 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/heartbeat/heartbeat.ts +79 -17
- package/src/heartbeat/templates.ts +2 -2
- package/src/http/agents.ts +62 -1
- package/src/http/api-keys.ts +140 -2
- package/src/http/codex-oauth-keep-warm.ts +3 -5
- package/src/http/index.ts +8 -0
- package/src/http/memory.ts +12 -5
- package/src/http/models-catalog.ts +357 -8
- package/src/http/poll.ts +54 -3
- package/src/http/schedules.ts +51 -6
- package/src/http/script-runs.ts +12 -0
- package/src/http/session-data.ts +2 -5
- package/src/http/stats.ts +6 -8
- package/src/http/status.ts +15 -1
- package/src/http/tasks.ts +90 -7
- package/src/http/usage-cache.ts +56 -15
- package/src/http/workflows.ts +46 -8
- package/src/mcp-client/http-client.ts +5 -0
- package/src/memory/recall-query.ts +74 -0
- package/src/prompts/base-prompt.ts +15 -4
- package/src/prompts/session-templates.ts +23 -1
- package/src/providers/acp-adapter.ts +1 -0
- package/src/providers/claude-adapter.ts +14 -5
- package/src/providers/claude-managed-adapter.ts +1 -0
- package/src/providers/claude-managed-models.ts +47 -161
- package/src/providers/claude-sdk-session.ts +3 -1
- package/src/providers/codex-adapter.ts +14 -14
- package/src/providers/codex-models.ts +65 -198
- package/src/providers/devin-adapter.ts +1 -0
- package/src/providers/dsh-adapter.ts +2 -1
- package/src/providers/harness-version.ts +83 -7
- package/src/providers/opencode-adapter.ts +53 -1
- package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
- package/src/providers/pi-codemode-runtime.ts +17 -0
- package/src/providers/pi-mono-adapter.ts +361 -83
- package/src/providers/pi-mono-extension.ts +16 -1
- package/src/providers/reasoning-effort.ts +44 -140
- package/src/providers/types.ts +8 -0
- package/src/rbac/legacy-policy.ts +43 -0
- package/src/rbac/permissions.ts +15 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/types/stdlib.d.ts +15 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
- package/src/server.ts +6 -0
- package/src/slack/assistant.ts +13 -0
- package/src/slack/message-text.ts +56 -2
- package/src/slack/render-v2.ts +87 -37
- package/src/slack/session-status.ts +541 -0
- package/src/slack/thread-buffer.ts +10 -2
- package/src/tasks/sibling-awareness.ts +3 -2
- package/src/telemetry.ts +5 -4
- package/src/templates.d.ts +6 -0
- package/src/tests/agents-list-model-display.test.ts +4 -6
- package/src/tests/api-key-auth-failure-route.test.ts +142 -0
- package/src/tests/api-key-tracking.test.ts +368 -1
- package/src/tests/base-prompt.test.ts +43 -2
- package/src/tests/claude-adapter.test.ts +68 -0
- package/src/tests/claude-managed-adapter.test.ts +12 -18
- package/src/tests/codex-adapter.test.ts +2 -1
- package/src/tests/codex-auth-failure.test.ts +52 -0
- package/src/tests/codex-gpt6-release.test.ts +66 -5
- package/src/tests/codex-login.test.ts +116 -0
- package/src/tests/context-window.test.ts +7 -5
- package/src/tests/credential-exhaustion-policy.test.ts +118 -3
- package/src/tests/credential-outcome-report.test.ts +171 -0
- package/src/tests/credential-status-api.test.ts +103 -2
- package/src/tests/db-extraction-contract.test.ts +1 -0
- package/src/tests/db-task-read-contract.test.ts +10 -1
- package/src/tests/db-task-write-contract.test.ts +535 -2
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dokploy-deploy.test.ts +315 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/explicit-model-validation.test.ts +583 -0
- package/src/tests/extensions-pre-task.test.ts +73 -0
- package/src/tests/fetch-resolved-env.test.ts +46 -0
- package/src/tests/hang-watchdog-worker.ts +47 -0
- package/src/tests/hang-watchdog.test.ts +45 -0
- package/src/tests/hang-watchdog.ts +30 -0
- package/src/tests/harness-model-guard.test.ts +123 -0
- package/src/tests/harness-model-support.test.ts +374 -0
- package/src/tests/harness-version.test.ts +70 -3
- package/src/tests/heartbeat-checklist-config.test.ts +71 -0
- package/src/tests/heartbeat-checklist.test.ts +4 -2
- package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
- package/src/tests/http-task-write-ownership.test.ts +172 -0
- package/src/tests/human-free-flag.test.ts +279 -0
- package/src/tests/human-free-oracle.ts +57 -0
- package/src/tests/human-free-reclassify.test.ts +669 -0
- package/src/tests/memory-fts-populate.test.ts +139 -0
- package/src/tests/memory-http-recall-gating.test.ts +125 -1
- package/src/tests/migration-046-budgets.test.ts +3 -3
- package/src/tests/model-catalog-migration.test.ts +134 -0
- package/src/tests/model-catalog-table.test.ts +249 -0
- package/src/tests/model-catalog-write-access.test.ts +387 -0
- package/src/tests/model-rate-limit-windows.test.ts +19 -0
- package/src/tests/model-tier-resolution.test.ts +611 -0
- package/src/tests/models-catalog.test.ts +1 -1
- package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
- package/src/tests/opencode-adapter.test.ts +157 -2
- package/src/tests/package-publish.test.ts +137 -36
- package/src/tests/pi-codemode.test.ts +246 -0
- package/src/tests/pi-mono-adapter.test.ts +3 -0
- package/src/tests/pi-native-mcp.test.ts +193 -0
- package/src/tests/pi-tool-exposure.test.ts +374 -0
- package/src/tests/preload.ts +3 -0
- package/src/tests/pricing-routes.test.ts +2 -2
- package/src/tests/prompt-template-session.test.ts +5 -3
- package/src/tests/rate-limit-event.test.ts +65 -0
- package/src/tests/rate-limit-outcome.test.ts +90 -0
- package/src/tests/rbac-engine.test.ts +77 -3
- package/src/tests/reasoning-effort.test.ts +109 -0
- package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
- package/src/tests/runner-key-completion-outcome.test.ts +112 -0
- package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
- package/src/tests/runner-registration-retry.test.ts +149 -0
- package/src/tests/runtime-model-catalog.test.ts +86 -0
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/seat-mismatch-report.test.ts +85 -0
- package/src/tests/seed-scripts.test.ts +138 -0
- package/src/tests/seed.test.ts +25 -0
- package/src/tests/session-costs.test.ts +14 -11
- package/src/tests/slack-message-text.test.ts +101 -0
- package/src/tests/slack-render-v2.test.ts +96 -0
- package/src/tests/slack-session-status.test.ts +626 -0
- package/src/tests/slack-thread-buffer-context.test.ts +93 -0
- package/src/tests/status.test.ts +29 -0
- package/src/tests/steering-promotion.test.ts +51 -0
- package/src/tests/store-progress-ownership.test.ts +136 -0
- package/src/tests/subscription-plans.test.ts +28 -0
- package/src/tests/task-cascade-fail.test.ts +148 -2
- package/src/tests/task-citations.test.ts +3 -2
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/usage-cache.test.ts +166 -0
- package/src/tests/workflow-agent-task.test.ts +30 -0
- package/src/tests/workflow-executors.test.ts +5 -2
- package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
- package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
- package/src/tests/workflow-system-one-decision.test.ts +2063 -0
- package/src/tests/workflow-triggers-v2.test.ts +320 -0
- package/src/tools/model-catalog/index.ts +137 -0
- package/src/tools/schedules/create-schedule.ts +17 -2
- package/src/tools/schedules/patch-schedule.ts +31 -1
- package/src/tools/schedules/update-schedule.ts +31 -1
- package/src/tools/send-task.ts +18 -1
- package/src/tools/store-progress.ts +49 -4
- package/src/tools/task-action.ts +14 -1
- package/src/tools/tool-config.ts +3 -1
- package/src/tools/workflows/create-workflow.ts +17 -4
- package/src/tools/workflows/patch-workflow-node.ts +17 -7
- package/src/tools/workflows/patch-workflow.ts +9 -2
- package/src/tools/workflows/update-workflow.ts +17 -4
- package/src/types.ts +41 -1
- package/src/utils/codex-auth-failure.ts +34 -0
- package/src/utils/context-window.ts +47 -53
- package/src/utils/credentials.ts +72 -30
- package/src/utils/error-tracker.ts +80 -0
- package/src/utils/harness-cli-version.ts +115 -0
- package/src/utils/harness-model-error.ts +33 -0
- package/src/utils/model-rate-limit-windows.ts +12 -0
- package/src/utils/runtime-model-catalog.ts +152 -0
- package/src/utils/spawn-model-guard.ts +43 -0
- package/src/utils/subscription-plans.ts +22 -0
- package/src/workflows/approval-resolution.ts +39 -0
- package/src/workflows/definition.ts +7 -0
- package/src/workflows/engine.ts +69 -1
- package/src/workflows/executors/agent-task.ts +16 -6
- package/src/workflows/executors/base.ts +53 -0
- package/src/workflows/executors/human-in-the-loop.ts +8 -8
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/system-one-decision.ts +1232 -0
- package/src/workflows/executors/system-one-providers.ts +301 -0
- package/src/workflows/executors/workflow-llm.ts +13 -1
- package/src/workflows/model-validation.ts +45 -0
- package/src/workflows/patch-definition.ts +5 -0
- package/src/workflows/readiness.ts +86 -0
- package/src/workflows/recovery.ts +12 -12
- package/src/workflows/resume.ts +23 -9
- package/src/workflows/triggers.ts +85 -0
- package/templates/schedules/daily-blocker-digest/content.md +4 -5
- package/templates/skills/agent-browser/SKILL.md +6 -5
- package/templates/skills/agent-browser/content.md +6 -5
- package/templates/skills/heartbeat-runbook/config.json +1 -1
- package/templates/skills/heartbeat-runbook/content.md +2 -2
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
- package/templates/skills/swarm-scripts/content.md +1 -1
- package/templates/skills/workflow-iterate/content.md +82 -1
- package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
- package/templates/workflows/pr-review-status-sweep/content.md +2 -0
- package/dist/boot-seeds-s3q01xj3.js +0 -26
- package/dist/claude-sdk-session-t442qz6f.js +0 -39108
- package/dist/cli-0xjkj1j7.js +0 -61
- package/dist/cli-20cj37vt.js +0 -335561
- package/dist/cli-2djtr51b.js +0 -48
- package/dist/cli-65hjmev5.js +0 -1141
- package/dist/cli-aw1jwp1r.js +0 -14075
- package/dist/cli-h967nb6r.js +0 -6603
- package/dist/cli-vapyk8sw.js +0 -20
- package/dist/cli-ws6rqycm.js +0 -247
- package/dist/pricing-refresh-v1cbr9te.js +0 -27
- package/src/providers/modelsdev-reasoning.json +0 -6453
- package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
normalizeRepoUrl,
|
|
10
10
|
} from "../providers/claude-managed-adapter";
|
|
11
11
|
import {
|
|
12
|
-
CLAUDE_MANAGED_MODEL_PRICING,
|
|
13
12
|
computeClaudeManagedCostUsd,
|
|
13
|
+
getClaudeManagedModelPricing,
|
|
14
14
|
} from "../providers/claude-managed-models";
|
|
15
15
|
import type { ProviderEvent, ProviderSessionConfig } from "../providers/types";
|
|
16
16
|
|
|
@@ -885,58 +885,52 @@ describe("ClaudeManagedAdapter (Phase 4) — repo provisioning + cost data", ()
|
|
|
885
885
|
expect(cost2).toBe(0);
|
|
886
886
|
});
|
|
887
887
|
|
|
888
|
-
test("
|
|
889
|
-
expect(
|
|
888
|
+
test("catalog prices managed models: covers sonnet, opus, haiku at minimum", () => {
|
|
889
|
+
expect(getClaudeManagedModelPricing("claude-fable-5-1")).toEqual({
|
|
890
890
|
inputPerMillion: 10.0,
|
|
891
891
|
outputPerMillion: 50.0,
|
|
892
892
|
cacheReadPerMillion: 0.25,
|
|
893
893
|
cacheWritePerMillion: 12.5,
|
|
894
894
|
});
|
|
895
|
-
expect(
|
|
896
|
-
inputPerMillion: 10.0,
|
|
897
|
-
outputPerMillion: 50.0,
|
|
898
|
-
cacheReadPerMillion: 0.25,
|
|
899
|
-
cacheWritePerMillion: 12.5,
|
|
900
|
-
});
|
|
901
|
-
expect(CLAUDE_MANAGED_MODEL_PRICING["claude-opus-5-5"]).toEqual({
|
|
895
|
+
expect(getClaudeManagedModelPricing("claude-opus-5-5")).toEqual({
|
|
902
896
|
inputPerMillion: 4.0,
|
|
903
897
|
outputPerMillion: 20.0,
|
|
904
898
|
cacheReadPerMillion: 0.2,
|
|
905
899
|
cacheWritePerMillion: 5.0,
|
|
906
900
|
});
|
|
907
|
-
expect(
|
|
901
|
+
expect(getClaudeManagedModelPricing("claude-opus-5")).toEqual({
|
|
908
902
|
inputPerMillion: 5.0,
|
|
909
903
|
outputPerMillion: 25.0,
|
|
910
904
|
cacheReadPerMillion: 0.5,
|
|
911
905
|
cacheWritePerMillion: 6.25,
|
|
912
906
|
});
|
|
913
|
-
expect(
|
|
907
|
+
expect(getClaudeManagedModelPricing("claude-fable-5")).toEqual({
|
|
914
908
|
inputPerMillion: 10.0,
|
|
915
909
|
outputPerMillion: 50.0,
|
|
916
910
|
cacheReadPerMillion: 1.0,
|
|
917
911
|
cacheWritePerMillion: 12.5,
|
|
918
912
|
});
|
|
919
|
-
expect(
|
|
913
|
+
expect(getClaudeManagedModelPricing("claude-mythos-5")).toEqual({
|
|
920
914
|
inputPerMillion: 10.0,
|
|
921
915
|
outputPerMillion: 50.0,
|
|
922
916
|
cacheReadPerMillion: 1.0,
|
|
923
917
|
cacheWritePerMillion: 12.5,
|
|
924
918
|
});
|
|
925
|
-
expect(
|
|
919
|
+
expect(getClaudeManagedModelPricing("claude-sonnet-5-5")).toEqual({
|
|
926
920
|
inputPerMillion: 2.0,
|
|
927
921
|
outputPerMillion: 10.0,
|
|
928
922
|
cacheReadPerMillion: 0.2,
|
|
929
923
|
cacheWritePerMillion: 2.5,
|
|
930
924
|
});
|
|
931
|
-
expect(
|
|
925
|
+
expect(getClaudeManagedModelPricing("claude-sonnet-5")).toEqual({
|
|
932
926
|
inputPerMillion: 2.0,
|
|
933
927
|
outputPerMillion: 10.0,
|
|
934
928
|
cacheReadPerMillion: 0.2,
|
|
935
929
|
cacheWritePerMillion: 2.5,
|
|
936
930
|
});
|
|
937
|
-
expect(
|
|
938
|
-
expect(
|
|
939
|
-
expect(
|
|
931
|
+
expect(getClaudeManagedModelPricing("claude-sonnet-4-6")).toBeDefined();
|
|
932
|
+
expect(getClaudeManagedModelPricing("claude-opus-4-7")).toBeDefined();
|
|
933
|
+
expect(getClaudeManagedModelPricing("claude-haiku-4-5")).toBeDefined();
|
|
940
934
|
});
|
|
941
935
|
|
|
942
936
|
test("session totalCostUsd = token cost + (durationMs/3.6e6) × $0.08 runtime fee", async () => {
|
|
@@ -1914,12 +1914,13 @@ describe("buildCodexConfig — context-mode + features", () => {
|
|
|
1914
1914
|
expect(mcp["context-mode"]).toBeUndefined();
|
|
1915
1915
|
});
|
|
1916
1916
|
|
|
1917
|
-
test("
|
|
1917
|
+
test("disables apps and enables hooks", async () => {
|
|
1918
1918
|
delete process.env.CONTEXT_MODE_DISABLED;
|
|
1919
1919
|
globalThis.fetch = stubFetch({ servers: [], total: 0 });
|
|
1920
1920
|
const merged = await buildCodexConfig(cfg(), "gpt-5.4", () => {});
|
|
1921
1921
|
|
|
1922
1922
|
const features = merged.features as Record<string, unknown>;
|
|
1923
|
+
expect(features.apps).toBe(false);
|
|
1923
1924
|
expect(features.hooks).toBe(true);
|
|
1924
1925
|
expect(features.plugin_hooks).toBe(true);
|
|
1925
1926
|
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { buildPoolRevalidationFailureReason } from "../providers/codex-adapter";
|
|
3
|
+
import { CodexOAuthRefreshError } from "../providers/codex-oauth/storage";
|
|
4
|
+
import { isCodexAuthFailureReason } from "../utils/codex-auth-failure";
|
|
5
|
+
|
|
6
|
+
describe("isCodexAuthFailureReason", () => {
|
|
7
|
+
test.each([
|
|
8
|
+
"[auth-error] Codex authentication failed — check OPENAI_API_KEY or ChatGPT login. Original error: workspace routing discovery unauthorized (401)",
|
|
9
|
+
"[auth-error] Codex authentication failed — check OPENAI_API_KEY or ChatGPT login. Original error: Failed to refresh token: 400 Bad Request: Invalid 'refresh_token': empty string",
|
|
10
|
+
'[auth-error] Codex pool slot 2 [...d3Ove] revalidation failed: refresh rejected (401 {"error":"refresh_token_invalidated"}) — credential likely revoked; re-run codex-login for this slot.',
|
|
11
|
+
])("counts %s", (reason) => {
|
|
12
|
+
expect(isCodexAuthFailureReason(reason)).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test.each([
|
|
16
|
+
undefined,
|
|
17
|
+
null,
|
|
18
|
+
"",
|
|
19
|
+
"[rate-limit] Codex API rate limit hit. Original error: 429",
|
|
20
|
+
"[auth-error] Codex pool slot 2 [...d3Ove] revalidation failed: timed out waiting for the refresh lock — transient, will retry on next task.",
|
|
21
|
+
"[auth-error] Codex pool slot 2 [...d3Ove] revalidation failed: refresh rejected (429 Too Many Requests) — credential likely revoked; re-run codex-login for this slot.",
|
|
22
|
+
"[auth-error] Codex pool slot 2 [...d3Ove] revalidation failed: refresh rejected (503 Service Unavailable) — credential likely revoked; re-run codex-login for this slot.",
|
|
23
|
+
"[auth-error] Codex pool slot 2 [...d3Ove] revalidation failed: refresh rejected (unknown status ) — credential likely revoked; re-run codex-login for this slot.",
|
|
24
|
+
"[auth-error] Codex pool slot 2 [...d3Ove] revalidation failed: no credentials found in config store — the slot may have just been quarantined; the next task will pick another slot.",
|
|
25
|
+
])("does not count %p", (reason) => {
|
|
26
|
+
expect(isCodexAuthFailureReason(reason)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test.each([
|
|
30
|
+
["network error", new TypeError("fetch failed")],
|
|
31
|
+
["refresh-lock HTTP error", new Error("refresh lock acquire failed: HTTP 502")],
|
|
32
|
+
["persistence error", new Error("Failed to store Codex OAuth credentials: 500")],
|
|
33
|
+
["lock timeout", new CodexOAuthRefreshError(2, "lock_timeout", "d3Ove")],
|
|
34
|
+
["throttled refresh", new CodexOAuthRefreshError(2, "refresh_rejected", "d3Ove", 429)],
|
|
35
|
+
["upstream refresh error", new CodexOAuthRefreshError(2, "refresh_rejected", "d3Ove", 503)],
|
|
36
|
+
])("a thrown %s during revalidation does not count", (_label, err) => {
|
|
37
|
+
const reason = buildPoolRevalidationFailureReason(err, 2);
|
|
38
|
+
expect(reason).toContain("[auth-error]");
|
|
39
|
+
expect(isCodexAuthFailureReason(reason)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("a confirmed refresh rejection during revalidation counts", () => {
|
|
43
|
+
const err = new CodexOAuthRefreshError(
|
|
44
|
+
2,
|
|
45
|
+
"refresh_rejected",
|
|
46
|
+
"d3Ove",
|
|
47
|
+
401,
|
|
48
|
+
'{"error":"refresh_token_invalidated"}',
|
|
49
|
+
);
|
|
50
|
+
expect(isCodexAuthFailureReason(buildPoolRevalidationFailureReason(err, 2))).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -5,10 +5,10 @@ import cache from "../be/modelsdev-cache.json";
|
|
|
5
5
|
import { buildModelsDevSeedRows } from "../be/seed-pricing";
|
|
6
6
|
import {
|
|
7
7
|
CODEX_DEFAULT_MODEL,
|
|
8
|
-
CODEX_MODELS,
|
|
9
8
|
computeCodexCostUsd,
|
|
10
|
-
FALLBACK_CODEX_MODEL_PRICING,
|
|
11
9
|
getCodexContextWindow,
|
|
10
|
+
getCodexModelPricing,
|
|
11
|
+
listCodexModels,
|
|
12
12
|
resolveCodexModel,
|
|
13
13
|
} from "../providers/codex-models";
|
|
14
14
|
import { applyReasoningEffort, reasoningCapability } from "../providers/reasoning-effort";
|
|
@@ -21,11 +21,11 @@ const releases = [
|
|
|
21
21
|
for (const release of releases) {
|
|
22
22
|
describe(release.id, () => {
|
|
23
23
|
test("uses the exact bare CLI ID with verified context and base costs", () => {
|
|
24
|
-
expect(
|
|
24
|
+
expect(listCodexModels()).toContain(release.id);
|
|
25
25
|
expect(resolveCodexModel(release.id.toUpperCase())).toBe(release.id);
|
|
26
26
|
expect(getCodexContextWindow(release.id)).toBe(1_050_000);
|
|
27
27
|
expect(cache.openai.models[release.id].limit.output).toBe(128_000);
|
|
28
|
-
expect(
|
|
28
|
+
expect(getCodexModelPricing(release.id)).toEqual({
|
|
29
29
|
inputPerMillion: release.input,
|
|
30
30
|
cachedInputPerMillion: release.read,
|
|
31
31
|
outputPerMillion: release.output,
|
|
@@ -79,7 +79,7 @@ for (const release of releases) {
|
|
|
79
79
|
test("is available through the catalog and direct UI selector", () => {
|
|
80
80
|
const model = buildModelsCatalog(cache).openai?.models[release.id];
|
|
81
81
|
expect(model?.limit?.context).toBe(1_050_000);
|
|
82
|
-
expect(model?.cost).
|
|
82
|
+
expect(model?.cost).toMatchObject({ input: release.input, output: release.output });
|
|
83
83
|
const option = modelGroupsForHarness("codex", undefined, undefined)
|
|
84
84
|
.flatMap((group) => group.models)
|
|
85
85
|
.find((entry) => entry.id === release.id);
|
|
@@ -95,3 +95,64 @@ test("release additions preserve rollout-safe defaults and aliases", () => {
|
|
|
95
95
|
expect(resolveCodexModel("haiku")).toBe("gpt-5.6-luna");
|
|
96
96
|
expect(resolveCodexModel("opus")).toBe("gpt-5.6-sol");
|
|
97
97
|
});
|
|
98
|
+
|
|
99
|
+
describe("gpt-6.1-sol", () => {
|
|
100
|
+
const id = "gpt-6.1-sol";
|
|
101
|
+
|
|
102
|
+
test("uses the exact bare CLI ID with verified context and base costs", () => {
|
|
103
|
+
expect(listCodexModels()).toContain(id);
|
|
104
|
+
expect(resolveCodexModel("GPT-6.1-SOL")).toBe(id);
|
|
105
|
+
expect(getCodexContextWindow(id)).toBe(1_050_000);
|
|
106
|
+
expect(cache.openai.models[id].limit.output).toBe(128_000);
|
|
107
|
+
expect(getCodexModelPricing(id)).toEqual({
|
|
108
|
+
inputPerMillion: 2,
|
|
109
|
+
cachedInputPerMillion: 0.1,
|
|
110
|
+
outputPerMillion: 10,
|
|
111
|
+
});
|
|
112
|
+
expect(computeCodexCostUsd(id, 1_000_000, 250_000, 100_000)).toBeCloseTo(
|
|
113
|
+
2 * 0.75 + 0.1 * 0.25 + 10 * 0.1,
|
|
114
|
+
8,
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("exposes low through max without an off level", () => {
|
|
119
|
+
expect(reasoningCapability("codex", id)).toEqual({
|
|
120
|
+
supported: true,
|
|
121
|
+
levels: ["low", "medium", "high", "xhigh", "max"],
|
|
122
|
+
default: "medium",
|
|
123
|
+
});
|
|
124
|
+
expect(applyReasoningEffort("codex", id, "max")).toEqual({
|
|
125
|
+
kind: "codex-config",
|
|
126
|
+
config: { model_reasoning_effort: "max" },
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("seeds all four token classes with long-context tiers", () => {
|
|
131
|
+
const rows = buildModelsDevSeedRows(cache).filter(
|
|
132
|
+
(row) => row.provider === "codex" && row.model === id,
|
|
133
|
+
);
|
|
134
|
+
expect(Object.fromEntries(rows.map((row) => [row.tokenClass, row.pricePerMillionUsd]))).toEqual(
|
|
135
|
+
{ input: 2, output: 10, cached_input: 0.1, cache_write: 2.5 },
|
|
136
|
+
);
|
|
137
|
+
expect(cache.openai.models[id].cost.tiers).toEqual([
|
|
138
|
+
{
|
|
139
|
+
input: 4,
|
|
140
|
+
output: 15,
|
|
141
|
+
cache_read: 0.2,
|
|
142
|
+
cache_write: 5,
|
|
143
|
+
tier: { type: "context", size: 272000 },
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("is available through the catalog and direct UI selector", () => {
|
|
149
|
+
const model = buildModelsCatalog(cache).openai?.models[id];
|
|
150
|
+
expect(model?.limit?.context).toBe(1_050_000);
|
|
151
|
+
expect(model?.cost).toMatchObject({ input: 2, output: 10 });
|
|
152
|
+
const option = modelGroupsForHarness("codex", undefined, undefined)
|
|
153
|
+
.flatMap((group) => group.models)
|
|
154
|
+
.find((entry) => entry.id === id);
|
|
155
|
+
expect(option?.label).toBe("GPT-6.1 Sol");
|
|
156
|
+
expect(option?.reasoningLevels).toEqual(["low", "medium", "high", "xhigh", "max"]);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -197,6 +197,8 @@ describe("runCodexLogin", () => {
|
|
|
197
197
|
})),
|
|
198
198
|
store,
|
|
199
199
|
loadAllSlots: mock(async () => []),
|
|
200
|
+
clearAuthBench: mock(async () => false),
|
|
201
|
+
readAuthFence: mock(async () => 0),
|
|
200
202
|
log: () => {},
|
|
201
203
|
error: () => {},
|
|
202
204
|
exit: () => {},
|
|
@@ -229,6 +231,8 @@ describe("runCodexLogin", () => {
|
|
|
229
231
|
{ slot: 0, creds: { access: "", refresh: "", expires: 0, accountId: "" } },
|
|
230
232
|
{ slot: 1, creds: { access: "", refresh: "", expires: 0, accountId: "" } },
|
|
231
233
|
]),
|
|
234
|
+
clearAuthBench: mock(async () => false),
|
|
235
|
+
readAuthFence: mock(async () => 0),
|
|
232
236
|
log: () => {},
|
|
233
237
|
error: () => {},
|
|
234
238
|
exit: () => {},
|
|
@@ -285,6 +289,8 @@ describe("runCodexLogin", () => {
|
|
|
285
289
|
})),
|
|
286
290
|
store,
|
|
287
291
|
loadAllSlots: mock(async () => []),
|
|
292
|
+
clearAuthBench: mock(async () => false),
|
|
293
|
+
readAuthFence: mock(async () => 0),
|
|
288
294
|
log: () => {},
|
|
289
295
|
error: () => {},
|
|
290
296
|
exit: () => {},
|
|
@@ -322,4 +328,114 @@ describe("runCodexLogin", () => {
|
|
|
322
328
|
expect(error).toHaveBeenCalledWith(expect.stringContaining("All credential slots"));
|
|
323
329
|
expect(exit).toHaveBeenCalledWith(1);
|
|
324
330
|
});
|
|
331
|
+
|
|
332
|
+
it("lifts the auth-failure bench on the re-logged key after storing", async () => {
|
|
333
|
+
const calls: string[] = [];
|
|
334
|
+
const store = mock(async () => {
|
|
335
|
+
calls.push("store");
|
|
336
|
+
});
|
|
337
|
+
const clearAuthBench = mock(
|
|
338
|
+
async (_apiUrl: string, _apiKey: string, keySuffix: string, slot: number, fence: number) => {
|
|
339
|
+
calls.push(`clear:${keySuffix}@${slot} fence ${fence}`);
|
|
340
|
+
return true;
|
|
341
|
+
},
|
|
342
|
+
);
|
|
343
|
+
const readAuthFence = mock(async () => {
|
|
344
|
+
calls.push("read-fence");
|
|
345
|
+
return 7;
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
await runCodexLogin([], {
|
|
349
|
+
resolveConfig: async () => ({
|
|
350
|
+
apiUrl: "http://localhost:3013",
|
|
351
|
+
apiKey: "example-test-key",
|
|
352
|
+
slot: 2,
|
|
353
|
+
}),
|
|
354
|
+
login: mock(async () => ({
|
|
355
|
+
access: "at_test",
|
|
356
|
+
refresh: "rt_test",
|
|
357
|
+
expires: Date.now() + 3600000,
|
|
358
|
+
accountId: "acc-test-d3Ove",
|
|
359
|
+
})),
|
|
360
|
+
store,
|
|
361
|
+
loadAllSlots: mock(async () => []),
|
|
362
|
+
clearAuthBench,
|
|
363
|
+
readAuthFence,
|
|
364
|
+
log: () => {},
|
|
365
|
+
error: () => {},
|
|
366
|
+
exit: () => {},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// at_test has no chatgpt_user_id claim, so the suffix falls back to accountId.
|
|
370
|
+
// The fence is read BEFORE the credential write, so failures on the fresh login survive.
|
|
371
|
+
expect(calls).toEqual(["read-fence", "store", "clear:d3Ove@2 fence 7"]);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("skips the unfenced clear when the fence cannot be read", async () => {
|
|
375
|
+
const error = mock(() => {});
|
|
376
|
+
const exit = mock(() => {});
|
|
377
|
+
const store = mock(async () => {});
|
|
378
|
+
const clearAuthBench = mock(async () => true);
|
|
379
|
+
|
|
380
|
+
await runCodexLogin([], {
|
|
381
|
+
resolveConfig: async () => ({
|
|
382
|
+
apiUrl: "http://localhost:3013",
|
|
383
|
+
apiKey: "example-test-key",
|
|
384
|
+
slot: 2,
|
|
385
|
+
}),
|
|
386
|
+
login: mock(async () => ({
|
|
387
|
+
access: "at_test",
|
|
388
|
+
refresh: "rt_test",
|
|
389
|
+
expires: Date.now() + 3600000,
|
|
390
|
+
accountId: "acc-test-d3Ove",
|
|
391
|
+
})),
|
|
392
|
+
store,
|
|
393
|
+
loadAllSlots: mock(async () => []),
|
|
394
|
+
clearAuthBench,
|
|
395
|
+
readAuthFence: mock(async () => {
|
|
396
|
+
throw new Error("keys/available returned 503");
|
|
397
|
+
}),
|
|
398
|
+
log: () => {},
|
|
399
|
+
error,
|
|
400
|
+
exit,
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
expect(store).toHaveBeenCalled();
|
|
404
|
+
expect(clearAuthBench).not.toHaveBeenCalled();
|
|
405
|
+
expect(error).toHaveBeenCalledWith(expect.stringContaining("keys/available returned 503"));
|
|
406
|
+
expect(exit).not.toHaveBeenCalled();
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("keeps a successful login when lifting the bench fails", async () => {
|
|
410
|
+
const error = mock(() => {});
|
|
411
|
+
const exit = mock(() => {});
|
|
412
|
+
|
|
413
|
+
await runCodexLogin([], {
|
|
414
|
+
resolveConfig: async () => ({
|
|
415
|
+
apiUrl: "http://localhost:3013",
|
|
416
|
+
apiKey: "example-test-key",
|
|
417
|
+
slot: 2,
|
|
418
|
+
}),
|
|
419
|
+
login: mock(async () => ({
|
|
420
|
+
access: "at_test",
|
|
421
|
+
refresh: "rt_test",
|
|
422
|
+
expires: Date.now() + 3600000,
|
|
423
|
+
accountId: "acc-test-d3Ove",
|
|
424
|
+
})),
|
|
425
|
+
store: mock(async () => {}),
|
|
426
|
+
loadAllSlots: mock(async () => []),
|
|
427
|
+
clearAuthBench: mock(async () => {
|
|
428
|
+
throw new Error("clear-rate-limit returned 500");
|
|
429
|
+
}),
|
|
430
|
+
readAuthFence: mock(async () => 0),
|
|
431
|
+
log: () => {},
|
|
432
|
+
error,
|
|
433
|
+
exit,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
expect(error).toHaveBeenCalledWith(
|
|
437
|
+
expect.stringContaining("could not lift the auth-failure bench"),
|
|
438
|
+
);
|
|
439
|
+
expect(exit).not.toHaveBeenCalled();
|
|
440
|
+
});
|
|
325
441
|
});
|
|
@@ -8,13 +8,12 @@ import {
|
|
|
8
8
|
} from "../utils/context-window";
|
|
9
9
|
|
|
10
10
|
describe("getContextWindowSize", () => {
|
|
11
|
-
|
|
11
|
+
// Windows come from the model catalog: a model the catalog lacks (mythos is
|
|
12
|
+
// not on models.dev) gets the 200K default until an overlay row adds it.
|
|
13
|
+
test("returns 1M for fable models", () => {
|
|
12
14
|
expect(getContextWindowSize("claude-fable-5-1")).toBe(1_000_000);
|
|
13
|
-
expect(getContextWindowSize("claude-mythos-5-1")).toBe(1_000_000);
|
|
14
15
|
expect(getContextWindowSize("claude-fable-5")).toBe(1_000_000);
|
|
15
|
-
expect(getContextWindowSize("claude-mythos-5")).toBe(1_000_000);
|
|
16
16
|
expect(getContextWindowSize("fable")).toBe(1_000_000);
|
|
17
|
-
expect(getContextWindowSize("mythos")).toBe(1_000_000);
|
|
18
17
|
});
|
|
19
18
|
|
|
20
19
|
test("returns 1M for opus models", () => {
|
|
@@ -38,8 +37,11 @@ describe("getContextWindowSize", () => {
|
|
|
38
37
|
expect(getContextWindowSize("haiku")).toBe(200_000);
|
|
39
38
|
});
|
|
40
39
|
|
|
40
|
+
test("reads OpenAI windows from the catalog", () => {
|
|
41
|
+
expect(getContextWindowSize("gpt-5")).toBe(400_000);
|
|
42
|
+
});
|
|
43
|
+
|
|
41
44
|
test("returns 200K default for unknown models", () => {
|
|
42
|
-
expect(getContextWindowSize("gpt-5")).toBe(200_000);
|
|
43
45
|
expect(getContextWindowSize("unknown-model")).toBe(200_000);
|
|
44
46
|
expect(getContextWindowSize("")).toBe(200_000);
|
|
45
47
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
2
2
|
import { fetchResolvedEnv } from "../commands/runner";
|
|
3
3
|
import {
|
|
4
4
|
type ModelFamily,
|
|
@@ -18,6 +18,9 @@ describe("resolveCredentialPools — model window exhaustion policy", () => {
|
|
|
18
18
|
let apiUrl: string;
|
|
19
19
|
const earliestResetAt = "2026-09-27T00:00:00.000Z";
|
|
20
20
|
let configResponse: { configs: Array<{ key: string; value: string }> } = { configs: [] };
|
|
21
|
+
/** Blocked indices returned for `model=fable`. The seat tests below override it. */
|
|
22
|
+
const windowOnlyFableBlocks = { modelBlockedIndices: [0, 1], seatBlockedIndices: [] as number[] };
|
|
23
|
+
let fableBlocks = windowOnlyFableBlocks;
|
|
21
24
|
|
|
22
25
|
beforeAll(() => {
|
|
23
26
|
server = Bun.serve({
|
|
@@ -34,8 +37,9 @@ describe("resolveCredentialPools — model window exhaustion policy", () => {
|
|
|
34
37
|
success: true,
|
|
35
38
|
availableIndices: [],
|
|
36
39
|
totalKeys: 2,
|
|
37
|
-
modelBlockedIndices:
|
|
38
|
-
|
|
40
|
+
modelBlockedIndices: fableBlocks.modelBlockedIndices,
|
|
41
|
+
seatBlockedIndices: fableBlocks.seatBlockedIndices,
|
|
42
|
+
earliestModelResetAt: fableBlocks.modelBlockedIndices.length ? earliestResetAt : null,
|
|
39
43
|
});
|
|
40
44
|
}
|
|
41
45
|
// sonnet (or any other model / no model): pool is fully available.
|
|
@@ -175,4 +179,115 @@ describe("resolveCredentialPools — model window exhaustion policy", () => {
|
|
|
175
179
|
expect(selections.length).toBe(1);
|
|
176
180
|
expect(selections[0]!.isRateLimitFallback).toBe(false);
|
|
177
181
|
});
|
|
182
|
+
|
|
183
|
+
describe("seat blocks", () => {
|
|
184
|
+
const fableTask = {
|
|
185
|
+
apiUrl: "",
|
|
186
|
+
apiKey: "key",
|
|
187
|
+
provider: "claude",
|
|
188
|
+
model: "claude-fable-5-1",
|
|
189
|
+
enforceModelCapacity: true,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
afterEach(() => {
|
|
193
|
+
fableBlocks = windowOnlyFableBlocks;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("default policy: throws and names seat blocks and window blocks", async () => {
|
|
197
|
+
fableBlocks = { modelBlockedIndices: [0], seatBlockedIndices: [1] };
|
|
198
|
+
const env: Record<string, string | undefined> = { CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b" };
|
|
199
|
+
const err = await resolveCredentialPools(env, { ...fableTask, apiUrl }).catch((e) => e);
|
|
200
|
+
expect(err).toBeInstanceOf(ModelWindowExhaustedError);
|
|
201
|
+
const typed = err as ModelWindowExhaustedError;
|
|
202
|
+
expect(typed.seatBlockedCount).toBe(1);
|
|
203
|
+
expect(typed.modelBlockedCount).toBe(1);
|
|
204
|
+
expect(typed.message).toBe(
|
|
205
|
+
"No CLAUDE_CODE_OAUTH_TOKEN key can run Fable: 1 keys are on a seat without Fable, 1 keys have the Fable window exhausted until 2026-09-27T00:00:00.000Z. Re-dispatch with another model or modelTier.",
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("MODEL_WINDOW_EXHAUSTED_POLICY=fallback: seat blocks still throw", async () => {
|
|
210
|
+
fableBlocks = { modelBlockedIndices: [], seatBlockedIndices: [0, 1] };
|
|
211
|
+
const env: Record<string, string | undefined> = {
|
|
212
|
+
CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b",
|
|
213
|
+
MODEL_WINDOW_EXHAUSTED_POLICY: "fallback",
|
|
214
|
+
};
|
|
215
|
+
const err = await resolveCredentialPools(env, { ...fableTask, apiUrl }).catch((e) => e);
|
|
216
|
+
expect(err).toBeInstanceOf(ModelWindowExhaustedError);
|
|
217
|
+
const typed = err as ModelWindowExhaustedError;
|
|
218
|
+
expect(typed.earliestResetAt).toBeNull();
|
|
219
|
+
expect(typed.message).toBe(
|
|
220
|
+
"No CLAUDE_CODE_OAUTH_TOKEN key can run Fable: 2 keys are on a seat without Fable, 0 keys have the Fable window exhausted. Re-dispatch with another model or modelTier.",
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("MODEL_WINDOW_EXHAUSTED_POLICY=fallback: window blocks alone still pick a key", async () => {
|
|
225
|
+
const env: Record<string, string | undefined> = {
|
|
226
|
+
CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b",
|
|
227
|
+
MODEL_WINDOW_EXHAUSTED_POLICY: "fallback",
|
|
228
|
+
};
|
|
229
|
+
const selections = await resolveCredentialPools(env, { ...fableTask, apiUrl });
|
|
230
|
+
expect(selections).toHaveLength(1);
|
|
231
|
+
expect(selections[0]!.isRateLimitFallback).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("MODEL_WINDOW_EXHAUSTED_POLICY=fallback: a mixed pool picks the Fable-capable key", async () => {
|
|
235
|
+
fableBlocks = { modelBlockedIndices: [1], seatBlockedIndices: [0] };
|
|
236
|
+
const env: Record<string, string | undefined> = {
|
|
237
|
+
CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b",
|
|
238
|
+
MODEL_WINDOW_EXHAUSTED_POLICY: "fallback",
|
|
239
|
+
};
|
|
240
|
+
const selections = await resolveCredentialPools(env, { ...fableTask, apiUrl });
|
|
241
|
+
expect(selections).toHaveLength(1);
|
|
242
|
+
expect(selections[0]!.index).toBe(1);
|
|
243
|
+
expect(selections[0]!.isRateLimitFallback).toBe(true);
|
|
244
|
+
expect(env.CLAUDE_CODE_OAUTH_TOKEN).toBe("tok-b");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("MODEL_WINDOW_EXHAUSTED_POLICY=fallback: every key without a seat block stays reachable", async () => {
|
|
248
|
+
fableBlocks = { modelBlockedIndices: [1, 2], seatBlockedIndices: [0] };
|
|
249
|
+
const picked = new Set<number>();
|
|
250
|
+
for (let run = 0; run < 50; run++) {
|
|
251
|
+
const env: Record<string, string | undefined> = {
|
|
252
|
+
CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b,tok-c",
|
|
253
|
+
MODEL_WINDOW_EXHAUSTED_POLICY: "fallback",
|
|
254
|
+
};
|
|
255
|
+
const selections = await resolveCredentialPools(env, { ...fableTask, apiUrl });
|
|
256
|
+
picked.add(selections[0]!.index);
|
|
257
|
+
}
|
|
258
|
+
expect([...picked].sort()).toEqual([1, 2]);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("default policy: a key-wide rate limit next to a seat block picks the other key", async () => {
|
|
262
|
+
fableBlocks = { modelBlockedIndices: [], seatBlockedIndices: [0] };
|
|
263
|
+
const env: Record<string, string | undefined> = { CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b" };
|
|
264
|
+
const selections = await resolveCredentialPools(env, { ...fableTask, apiUrl });
|
|
265
|
+
expect(selections[0]!.index).toBe(1);
|
|
266
|
+
expect(selections[0]!.isRateLimitFallback).toBe(true);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("a taskless configuration load never throws on seat blocks", async () => {
|
|
270
|
+
fableBlocks = { modelBlockedIndices: [], seatBlockedIndices: [0, 1] };
|
|
271
|
+
const env: Record<string, string | undefined> = { CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b" };
|
|
272
|
+
const selections = await resolveCredentialPools(env, {
|
|
273
|
+
...fableTask,
|
|
274
|
+
apiUrl,
|
|
275
|
+
enforceModelCapacity: undefined,
|
|
276
|
+
});
|
|
277
|
+
expect(selections).toHaveLength(1);
|
|
278
|
+
expect(selections[0]!.seatBlockedIndices).toEqual([0, 1]);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("a sonnet task on a seat-blocked Fable pool picks a key", async () => {
|
|
282
|
+
fableBlocks = { modelBlockedIndices: [], seatBlockedIndices: [0, 1] };
|
|
283
|
+
const env: Record<string, string | undefined> = { CLAUDE_CODE_OAUTH_TOKEN: "tok-a,tok-b" };
|
|
284
|
+
const selections = await resolveCredentialPools(env, {
|
|
285
|
+
...fableTask,
|
|
286
|
+
apiUrl,
|
|
287
|
+
model: "claude-sonnet-5",
|
|
288
|
+
});
|
|
289
|
+
expect(selections).toHaveLength(1);
|
|
290
|
+
expect(selections[0]!.isRateLimitFallback).toBe(false);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
178
293
|
});
|