@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
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
MAX_RATE_LIMIT_RESET_MS,
|
|
5
5
|
parseRateLimitWindowTelemetry,
|
|
6
6
|
parseStderrForErrors,
|
|
7
|
+
redactRateLimitEvent,
|
|
8
|
+
redactRateLimitEventLine,
|
|
7
9
|
SessionErrorTracker,
|
|
8
10
|
trackErrorFromJson,
|
|
9
11
|
} from "../utils/error-tracker";
|
|
@@ -449,6 +451,69 @@ describe("SessionErrorTracker — model-scoped rejection (Fable weekly window)",
|
|
|
449
451
|
});
|
|
450
452
|
});
|
|
451
453
|
|
|
454
|
+
// Verbatim fixture from task 91175100-349d-4284-a0c1-c41d17ddf8fa, session_logs line 4,
|
|
455
|
+
// 2026-09-30. Fable on a Claude Team standard seat: rejected, no rateLimitType,
|
|
456
|
+
// errorCode "credits_required".
|
|
457
|
+
const FIXTURE_CREDITS_REQUIRED = {
|
|
458
|
+
type: "rate_limit_event",
|
|
459
|
+
rate_limit_info: {
|
|
460
|
+
status: "rejected",
|
|
461
|
+
resetsAt: 1790812800,
|
|
462
|
+
overageDisabledReason: "member_zero_credit_limit",
|
|
463
|
+
isUsingOverage: false,
|
|
464
|
+
errorCode: "credits_required",
|
|
465
|
+
canUserPurchaseCredits: false,
|
|
466
|
+
hasChargeableSavedPaymentMethod: true,
|
|
467
|
+
},
|
|
468
|
+
uuid: "bff51e54-9777-458a-aceb-b50aaa4255b5",
|
|
469
|
+
session_id: "9d326326-0c59-4b00-b819-b9b7dd3bf99f",
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
describe("SessionErrorTracker — credits_required rejection", () => {
|
|
473
|
+
test("credits_required is a seat mismatch, never a key-wide or model-scoped limit", () => {
|
|
474
|
+
const tracker = new SessionErrorTracker();
|
|
475
|
+
tracker.processRateLimitEvent(FIXTURE_CREDITS_REQUIRED);
|
|
476
|
+
expect(tracker.getRateLimitResetAt()).toBeUndefined();
|
|
477
|
+
expect(tracker.getModelRateLimit()).toBeUndefined();
|
|
478
|
+
expect(tracker.getCreditsRequired()?.overageDisabledReason).toBe("member_zero_credit_limit");
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("a rejected event with no rateLimitType and no errorCode stays key-wide", () => {
|
|
482
|
+
const tracker = new SessionErrorTracker();
|
|
483
|
+
const { errorCode: _errorCode, ...info } = FIXTURE_CREDITS_REQUIRED.rate_limit_info;
|
|
484
|
+
tracker.processRateLimitEvent({ ...FIXTURE_CREDITS_REQUIRED, rate_limit_info: info });
|
|
485
|
+
expect(tracker.getRateLimitResetAt()).toBeDefined();
|
|
486
|
+
expect(tracker.getCreditsRequired()).toBeUndefined();
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
describe("redactRateLimitEvent — seat payload egress", () => {
|
|
491
|
+
test("drops the seat billing fields and keeps the rest", () => {
|
|
492
|
+
const redacted = redactRateLimitEvent(FIXTURE_CREDITS_REQUIRED);
|
|
493
|
+
expect(redacted.rate_limit_info).toEqual({
|
|
494
|
+
status: "rejected",
|
|
495
|
+
resetsAt: FIXTURE_CREDITS_REQUIRED.rate_limit_info.resetsAt,
|
|
496
|
+
isUsingOverage: false,
|
|
497
|
+
errorCode: "credits_required",
|
|
498
|
+
});
|
|
499
|
+
expect(redacted.uuid).toBe(FIXTURE_CREDITS_REQUIRED.uuid);
|
|
500
|
+
// The original message is not mutated.
|
|
501
|
+
expect(FIXTURE_CREDITS_REQUIRED.rate_limit_info.overageDisabledReason).toBe(
|
|
502
|
+
"member_zero_credit_limit",
|
|
503
|
+
);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test("the line form redacts JSON and returns other lines byte for byte", () => {
|
|
507
|
+
const line = redactRateLimitEventLine(JSON.stringify(FIXTURE_CREDITS_REQUIRED));
|
|
508
|
+
expect(line).not.toContain("overageDisabledReason");
|
|
509
|
+
expect(line).toContain('"errorCode":"credits_required"');
|
|
510
|
+
const other = '{"type":"assistant", "message":{}}';
|
|
511
|
+
expect(redactRateLimitEventLine(other)).toBe(other);
|
|
512
|
+
const plainEvent = '{"type":"rate_limit_event","rate_limit_info":{"status":"allowed"}}';
|
|
513
|
+
expect(redactRateLimitEventLine(plainEvent)).toBe(plainEvent);
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
|
|
452
517
|
describe("trackErrorFromJson — rate_limit_event routing", () => {
|
|
453
518
|
test("routes rate_limit_event to processRateLimitEvent, stashes reset time", () => {
|
|
454
519
|
const tracker = new SessionErrorTracker();
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
buildFinalRateLimitWindows,
|
|
6
6
|
classifyRateLimitOutcome,
|
|
7
7
|
} from "../commands/rate-limit-outcome";
|
|
8
|
+
import { SessionErrorTracker } from "../utils/error-tracker";
|
|
8
9
|
|
|
9
10
|
describe("classifyRateLimitOutcome", () => {
|
|
10
11
|
test("event source: modelRateLimit set gives kind 'model' with source 'event'", () => {
|
|
@@ -323,3 +324,92 @@ describe("buildFinalRateLimitWindows — cross-worker recovery", () => {
|
|
|
323
324
|
).toEqual([0]);
|
|
324
325
|
});
|
|
325
326
|
});
|
|
327
|
+
|
|
328
|
+
describe("classifyRateLimitOutcome — seat mismatch", () => {
|
|
329
|
+
const nowMs = Date.parse("2026-09-30T12:00:00.000Z");
|
|
330
|
+
const creditsRequired = {
|
|
331
|
+
observedAt: "2026-09-30T11:59:00.000Z",
|
|
332
|
+
overageDisabledReason: "member_zero_credit_limit",
|
|
333
|
+
};
|
|
334
|
+
const observedText = "Fable 5.1 requires usage credits. Switch to another model to continue.";
|
|
335
|
+
|
|
336
|
+
test("the observed failure text is a seat outcome from text", () => {
|
|
337
|
+
expect(classifyRateLimitOutcome({}, observedText, nowMs)).toEqual({
|
|
338
|
+
kind: "seat",
|
|
339
|
+
model: "fable",
|
|
340
|
+
source: "text",
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("a credits_required event with the task model family is a seat outcome from event", () => {
|
|
345
|
+
expect(
|
|
346
|
+
classifyRateLimitOutcome({ creditsRequired }, undefined, nowMs, undefined, "fable"),
|
|
347
|
+
).toEqual({ kind: "seat", model: "fable", source: "event" });
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test("a credits_required event with no task model family and no text is not a seat outcome", () => {
|
|
351
|
+
expect(classifyRateLimitOutcome({ creditsRequired }, undefined, nowMs).kind).not.toBe("seat");
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("a seat outcome keeps an earlier key-wide rejection from the real tracker", () => {
|
|
355
|
+
// The tracker reads the real clock and clamps past resets, so use a real "now" here.
|
|
356
|
+
const nowMs = Date.now();
|
|
357
|
+
const tracker = new SessionErrorTracker();
|
|
358
|
+
const fiveHourResetsAtSec = Math.floor(nowMs / 1000) + 2 * 60 * 60;
|
|
359
|
+
tracker.processRateLimitEvent({
|
|
360
|
+
type: "rate_limit_event",
|
|
361
|
+
rate_limit_info: {
|
|
362
|
+
status: "rejected",
|
|
363
|
+
resetsAt: fiveHourResetsAtSec,
|
|
364
|
+
rateLimitType: "five_hour",
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
tracker.processRateLimitEvent({
|
|
368
|
+
type: "rate_limit_event",
|
|
369
|
+
rate_limit_info: {
|
|
370
|
+
status: "rejected",
|
|
371
|
+
resetsAt: 1790812800,
|
|
372
|
+
overageDisabledReason: "member_zero_credit_limit",
|
|
373
|
+
isUsingOverage: false,
|
|
374
|
+
errorCode: "credits_required",
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
const rateLimitResetAt = tracker.getRateLimitResetAt();
|
|
378
|
+
const creditsRequired = tracker.getCreditsRequired();
|
|
379
|
+
expect(rateLimitResetAt).toBeDefined();
|
|
380
|
+
expect(creditsRequired).toBeDefined();
|
|
381
|
+
|
|
382
|
+
const outcome = classifyRateLimitOutcome(
|
|
383
|
+
{ rateLimitResetAt, creditsRequired },
|
|
384
|
+
undefined,
|
|
385
|
+
nowMs,
|
|
386
|
+
undefined,
|
|
387
|
+
"fable",
|
|
388
|
+
);
|
|
389
|
+
expect(outcome).toEqual({
|
|
390
|
+
kind: "seat",
|
|
391
|
+
model: "fable",
|
|
392
|
+
source: "event",
|
|
393
|
+
keyRateLimitedUntil: new Date(fiveHourResetsAtSec * 1000).toISOString(),
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test("a seat outcome with no key-wide rejection carries no key reset", () => {
|
|
398
|
+
const outcome = classifyRateLimitOutcome({ creditsRequired }, observedText, nowMs);
|
|
399
|
+
expect(outcome).not.toHaveProperty("keyRateLimitedUntil");
|
|
400
|
+
expect(outcome).not.toHaveProperty("rateLimitedUntil");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("buildFinalRateLimitWindows returns the session windows unchanged for a seat outcome", () => {
|
|
404
|
+
const windows = {
|
|
405
|
+
five_hour: { status: "allowed", utilization: 0.24, lastSeenAt: "2026-09-30T11:00:00.000Z" },
|
|
406
|
+
};
|
|
407
|
+
expect(
|
|
408
|
+
buildFinalRateLimitWindows(
|
|
409
|
+
windows,
|
|
410
|
+
{ kind: "seat", model: "fable", source: "event" },
|
|
411
|
+
"2026-09-30T12:00:00.000Z",
|
|
412
|
+
),
|
|
413
|
+
).toBe(windows);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
@@ -82,7 +82,11 @@ const LEAD_ONLY_VERBS: PermissionVerb[] = [
|
|
|
82
82
|
];
|
|
83
83
|
|
|
84
84
|
const OPERATOR_ONLY_VERBS: PermissionVerb[] = [];
|
|
85
|
-
const
|
|
85
|
+
const LEAD_OR_OPERATOR_OR_USER_VERBS: PermissionVerb[] = ["extension.write", "extension.activate"];
|
|
86
|
+
|
|
87
|
+
const LEAD_OR_OPERATOR_VERBS: PermissionVerb[] = ["models.catalog.write"];
|
|
88
|
+
|
|
89
|
+
const AGENT_OR_OPERATOR_VERBS: PermissionVerb[] = ["models.harness-support.write"];
|
|
86
90
|
|
|
87
91
|
const LEAD_OR_RESOURCE_OWNER_VERBS: PermissionVerb[] = [
|
|
88
92
|
"memory.edit.any",
|
|
@@ -116,7 +120,11 @@ const REQUESTER_OWNS_TASK_VERBS: PermissionVerb[] = [
|
|
|
116
120
|
"task.action.own",
|
|
117
121
|
];
|
|
118
122
|
|
|
119
|
-
const COMPOSITE_VERBS: PermissionVerb[] = [
|
|
123
|
+
const COMPOSITE_VERBS: PermissionVerb[] = [
|
|
124
|
+
"memory.delete.any",
|
|
125
|
+
"task.fs.mutate",
|
|
126
|
+
"task.progress.write",
|
|
127
|
+
];
|
|
120
128
|
|
|
121
129
|
// ── Resource fixtures ────────────────────────────────────────────────────────
|
|
122
130
|
|
|
@@ -178,7 +186,9 @@ describe("verb-group partition", () => {
|
|
|
178
186
|
...REQUESTER_OWNS_TASK_VERBS,
|
|
179
187
|
...COMPOSITE_VERBS,
|
|
180
188
|
...OPERATOR_ONLY_VERBS,
|
|
189
|
+
...LEAD_OR_OPERATOR_OR_USER_VERBS,
|
|
181
190
|
...LEAD_OR_OPERATOR_VERBS,
|
|
191
|
+
...AGENT_OR_OPERATOR_VERBS,
|
|
182
192
|
];
|
|
183
193
|
expect(new Set(grouped).size).toBe(grouped.length);
|
|
184
194
|
expect(grouped.sort()).toEqual([...PERMISSION_VERBS].sort());
|
|
@@ -251,13 +261,47 @@ describe("lead-or-operator-or-user verbs", () => {
|
|
|
251
261
|
foreignUser: true,
|
|
252
262
|
operator: true,
|
|
253
263
|
};
|
|
254
|
-
for (const verb of
|
|
264
|
+
for (const verb of LEAD_OR_OPERATOR_OR_USER_VERBS) {
|
|
255
265
|
test(`${verb}: lead, operator, or user allowed`, () => {
|
|
256
266
|
expectDecisions(verb, { kind: "none" }, expected);
|
|
257
267
|
});
|
|
258
268
|
}
|
|
259
269
|
});
|
|
260
270
|
|
|
271
|
+
describe("agent-or-operator verbs", () => {
|
|
272
|
+
const expected: Expected = {
|
|
273
|
+
lead: true,
|
|
274
|
+
worker: true,
|
|
275
|
+
ownerWorker: true,
|
|
276
|
+
creatorWorker: true,
|
|
277
|
+
userRequester: false,
|
|
278
|
+
foreignUser: false,
|
|
279
|
+
operator: true,
|
|
280
|
+
};
|
|
281
|
+
for (const verb of AGENT_OR_OPERATOR_VERBS) {
|
|
282
|
+
test(`${verb}: any registered agent or the operator allowed, dashboard users denied`, () => {
|
|
283
|
+
expectDecisions(verb, { kind: "none" }, expected);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe("lead-or-operator verbs", () => {
|
|
289
|
+
const expected: Expected = {
|
|
290
|
+
lead: true,
|
|
291
|
+
worker: false,
|
|
292
|
+
ownerWorker: false,
|
|
293
|
+
creatorWorker: false,
|
|
294
|
+
userRequester: false,
|
|
295
|
+
foreignUser: false,
|
|
296
|
+
operator: true,
|
|
297
|
+
};
|
|
298
|
+
for (const verb of LEAD_OR_OPERATOR_VERBS) {
|
|
299
|
+
test(`${verb}: only the lead or the operator allowed`, () => {
|
|
300
|
+
expectDecisions(verb, { kind: "none" }, expected);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
261
305
|
describe("extension ownership", () => {
|
|
262
306
|
test("workers create extensions and write only their own existing resource", () => {
|
|
263
307
|
const worker = { kind: "agent", agentId: "extension-owner", isLead: false } as const;
|
|
@@ -505,6 +549,36 @@ describe("task.fs.mutate composite (operator OR user OR lead OR assignee OR crea
|
|
|
505
549
|
});
|
|
506
550
|
});
|
|
507
551
|
|
|
552
|
+
describe("task.progress.write composite (operator OR user OR lead OR assignee OR unassigned)", () => {
|
|
553
|
+
test("the creator and an unrelated worker are denied on an assigned task", () => {
|
|
554
|
+
expectDecisions("task.progress.write", TASK_RESOURCE, {
|
|
555
|
+
lead: true,
|
|
556
|
+
worker: false,
|
|
557
|
+
ownerWorker: true, // assignee (task.agentId)
|
|
558
|
+
creatorWorker: false,
|
|
559
|
+
userRequester: true,
|
|
560
|
+
foreignUser: true,
|
|
561
|
+
operator: true,
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test("any agent may write an unassigned task", () => {
|
|
566
|
+
expectDecisions(
|
|
567
|
+
"task.progress.write",
|
|
568
|
+
{ kind: "task", taskId: "task-2", agentId: null },
|
|
569
|
+
{
|
|
570
|
+
lead: true,
|
|
571
|
+
worker: true,
|
|
572
|
+
ownerWorker: true,
|
|
573
|
+
creatorWorker: true,
|
|
574
|
+
userRequester: true,
|
|
575
|
+
foreignUser: true,
|
|
576
|
+
operator: true,
|
|
577
|
+
},
|
|
578
|
+
);
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
|
|
508
582
|
// ── Audit sink seam ──────────────────────────────────────────────────────────
|
|
509
583
|
|
|
510
584
|
describe("audit sink", () => {
|
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { describe, expect, test } from "bun:test";
|
|
12
|
+
import { reasoningLevelsForModel } from "@desplega/model-catalog";
|
|
12
13
|
import {
|
|
13
14
|
applyReasoningEffort,
|
|
14
15
|
REASONING_EFFORT_LEVELS,
|
|
16
|
+
type ReasoningHarness,
|
|
15
17
|
reasoningCapability,
|
|
16
18
|
} from "../providers/reasoning-effort";
|
|
19
|
+
import { runtimeCatalogSection } from "../utils/runtime-model-catalog";
|
|
17
20
|
|
|
18
21
|
describe("REASONING_EFFORT_LEVELS", () => {
|
|
19
22
|
test("is the closed normalized enum", () => {
|
|
@@ -243,3 +246,109 @@ describe("applyReasoningEffort — opencode-options shape", () => {
|
|
|
243
246
|
});
|
|
244
247
|
});
|
|
245
248
|
});
|
|
249
|
+
|
|
250
|
+
// The offered levels, the API's validation and the harness application all read the same
|
|
251
|
+
// answer. This matrix pins it per (harness, model) so the swarm app's pickers, the runtime
|
|
252
|
+
// PATCH and the run-time adapters cannot drift apart.
|
|
253
|
+
describe("harness × model → effort matrix", () => {
|
|
254
|
+
const matrix: {
|
|
255
|
+
harness: "claude" | "codex" | "pi" | "opencode";
|
|
256
|
+
model: string;
|
|
257
|
+
levels: string[];
|
|
258
|
+
}[] = [
|
|
259
|
+
{ harness: "claude", model: "claude-opus-5-5", levels: ["low", "medium", "high", "xhigh"] },
|
|
260
|
+
{ harness: "claude", model: "claude-sonnet-5-5", levels: ["low", "medium", "high", "xhigh"] },
|
|
261
|
+
{ harness: "claude", model: "claude-haiku-4-5", levels: ["off", "low", "medium", "high"] },
|
|
262
|
+
{
|
|
263
|
+
harness: "codex",
|
|
264
|
+
model: "gpt-5.6-sol",
|
|
265
|
+
levels: ["off", "low", "medium", "high", "xhigh", "max"],
|
|
266
|
+
},
|
|
267
|
+
{ harness: "codex", model: "gpt-6-astra", levels: ["low", "medium", "high", "xhigh", "max"] },
|
|
268
|
+
{ harness: "codex", model: "gpt-5.1-codex", levels: ["low", "medium", "high"] },
|
|
269
|
+
{ harness: "pi", model: "openrouter/deepseek/deepseek-v4.1-flash", levels: ["low", "high"] },
|
|
270
|
+
{
|
|
271
|
+
harness: "pi",
|
|
272
|
+
model: "openrouter/anthropic/claude-opus-5.5",
|
|
273
|
+
levels: ["low", "medium", "high", "xhigh"],
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
harness: "opencode",
|
|
277
|
+
model: "openrouter/deepseek/deepseek-v4.1-flash",
|
|
278
|
+
levels: ["low", "high"],
|
|
279
|
+
},
|
|
280
|
+
{ harness: "pi", model: "openrouter/qwen/qwen3-coder-flash", levels: [] },
|
|
281
|
+
{ harness: "claude", model: "totally-custom-model-xyz", levels: [] },
|
|
282
|
+
];
|
|
283
|
+
|
|
284
|
+
for (const { harness, model, levels } of matrix) {
|
|
285
|
+
test(`${harness} ${model}: ${levels.length > 0 ? levels.join(", ") : "no effort"}`, () => {
|
|
286
|
+
expect(reasoningCapability(harness, model).levels).toEqual(levels);
|
|
287
|
+
// Every offered level is applied, every other level is dropped: what a picker offers is what
|
|
288
|
+
// reaches the harness.
|
|
289
|
+
for (const level of REASONING_EFFORT_LEVELS) {
|
|
290
|
+
const applied = applyReasoningEffort(harness, model, level);
|
|
291
|
+
const takes = levels.includes(level);
|
|
292
|
+
// opencode has no explicit off, so its `off` is a noop even when offered.
|
|
293
|
+
const expectNoop = !takes || (harness === "opencode" && level === "off");
|
|
294
|
+
expect(applied.kind === "noop").toBe(expectNoop);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
describe("Claude CLI shortnames (the tier defaults) take effort like the model they stand for", () => {
|
|
301
|
+
test("opus, sonnet, haiku and fable resolve to their newest catalog model", () => {
|
|
302
|
+
expect(reasoningCapability("claude", "opus")).toEqual(
|
|
303
|
+
reasoningCapability("claude", "claude-opus-5-5"),
|
|
304
|
+
);
|
|
305
|
+
expect(reasoningCapability("claude", "sonnet")).toEqual(
|
|
306
|
+
reasoningCapability("claude", "claude-sonnet-5-5"),
|
|
307
|
+
);
|
|
308
|
+
expect(reasoningCapability("claude", "haiku").levels).toContain("off");
|
|
309
|
+
expect(reasoningCapability("claude", "fable").supported).toBe(true);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test("shortnames mean nothing to the other harnesses", () => {
|
|
313
|
+
expect(reasoningCapability("codex", "opus").supported).toBe(false);
|
|
314
|
+
expect(reasoningCapability("pi", "opus").supported).toBe(false);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// The evals app validates and lists efforts with `reasoningLevelsForModel` (packages/model-catalog);
|
|
319
|
+
// the worker applies them with `reasoningCapability`. They are two entry points to one rule, and
|
|
320
|
+
// this pins them together over the real snapshot so an eval can never accept a level the worker
|
|
321
|
+
// would drop (or hide one it would take).
|
|
322
|
+
describe("reasoningLevelsForModel agrees with reasoningCapability", () => {
|
|
323
|
+
const catalog = {
|
|
324
|
+
anthropic: { models: runtimeCatalogSection("anthropic") },
|
|
325
|
+
openai: { models: runtimeCatalogSection("openai") },
|
|
326
|
+
openrouter: { models: runtimeCatalogSection("openrouter") },
|
|
327
|
+
};
|
|
328
|
+
const pairs: [ReasoningHarness, string][] = [
|
|
329
|
+
...Object.keys(catalog.anthropic.models).map((id): [ReasoningHarness, string] => [
|
|
330
|
+
"claude",
|
|
331
|
+
id,
|
|
332
|
+
]),
|
|
333
|
+
...["opus", "sonnet", "haiku", "fable"].map((id): [ReasoningHarness, string] => ["claude", id]),
|
|
334
|
+
...Object.keys(catalog.openai.models).map((id): [ReasoningHarness, string] => ["codex", id]),
|
|
335
|
+
...Object.keys(catalog.openrouter.models).flatMap((id): [ReasoningHarness, string][] => [
|
|
336
|
+
["pi", `openrouter/${id}`],
|
|
337
|
+
["opencode", `openrouter/${id}`],
|
|
338
|
+
]),
|
|
339
|
+
["pi", "anthropic/claude-opus-5-5"],
|
|
340
|
+
["opencode", "openai/gpt-5.6-sol"],
|
|
341
|
+
["claude", "not-a-model"],
|
|
342
|
+
["pi", "no-provider-prefix"],
|
|
343
|
+
];
|
|
344
|
+
|
|
345
|
+
test("gives the same levels for every catalog model on every harness", () => {
|
|
346
|
+
expect(pairs.length).toBeGreaterThan(100);
|
|
347
|
+
const mismatches = pairs.filter(
|
|
348
|
+
([harness, model]) =>
|
|
349
|
+
JSON.stringify(reasoningLevelsForModel(harness, model, catalog)) !==
|
|
350
|
+
JSON.stringify(reasoningCapability(harness, model).levels),
|
|
351
|
+
);
|
|
352
|
+
expect(mismatches).toEqual([]);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { describe, expect, test } from "bun:test";
|
|
7
7
|
import { carryForwardDelistedModels } from "../../scripts/refresh-modelsdev-pricing";
|
|
8
|
-
import {
|
|
8
|
+
import { getCodexModelPricing } from "../providers/codex-models";
|
|
9
9
|
|
|
10
10
|
describe("carryForwardDelistedModels", () => {
|
|
11
11
|
test("models missing from the fresh fetch are carried forward; fresh data wins otherwise", () => {
|
|
@@ -42,12 +42,12 @@ describe("carryForwardDelistedModels", () => {
|
|
|
42
42
|
|
|
43
43
|
describe("FALLBACK_CODEX_MODEL_PRICING (advisory table)", () => {
|
|
44
44
|
test("gpt-6 Astra and gpt-5.6 Sol carry the published rates", () => {
|
|
45
|
-
expect(
|
|
45
|
+
expect(getCodexModelPricing("gpt-6-astra")).toEqual({
|
|
46
46
|
inputPerMillion: 10,
|
|
47
47
|
cachedInputPerMillion: 1,
|
|
48
48
|
outputPerMillion: 50,
|
|
49
49
|
});
|
|
50
|
-
expect(
|
|
50
|
+
expect(getCodexModelPricing("gpt-5.6-sol")).toEqual({
|
|
51
51
|
inputPerMillion: 4,
|
|
52
52
|
cachedInputPerMillion: 0.4,
|
|
53
53
|
outputPerMillion: 20,
|
|
@@ -57,12 +57,12 @@ describe("FALLBACK_CODEX_MODEL_PRICING (advisory table)", () => {
|
|
|
57
57
|
test("gpt-5.6 terra/luna carry the published rates", () => {
|
|
58
58
|
// Direct assertions: through computeCodexCostUsd the models.dev snapshot
|
|
59
59
|
// shadows this table, so drift here would otherwise go unnoticed.
|
|
60
|
-
expect(
|
|
60
|
+
expect(getCodexModelPricing("gpt-5.6-terra")).toEqual({
|
|
61
61
|
inputPerMillion: 2.0,
|
|
62
62
|
cachedInputPerMillion: 0.2,
|
|
63
63
|
outputPerMillion: 12.0,
|
|
64
64
|
});
|
|
65
|
-
expect(
|
|
65
|
+
expect(getCodexModelPricing("gpt-5.6-luna")).toEqual({
|
|
66
66
|
inputPerMillion: 0.2,
|
|
67
67
|
cachedInputPerMillion: 0.02,
|
|
68
68
|
outputPerMillion: 1.2,
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { reportKeyCompletionOutcome } from "../commands/runner";
|
|
3
|
+
|
|
4
|
+
// A fake API that records the order in which it FINISHES handling credential
|
|
5
|
+
// reports. The success reset is slow, so a fire-and-forget caller would let
|
|
6
|
+
// the later auth-failure reports land first and have their bench erased.
|
|
7
|
+
const handled: string[] = [];
|
|
8
|
+
let clearDelayMs = 0;
|
|
9
|
+
let server: ReturnType<typeof Bun.serve>;
|
|
10
|
+
let apiUrl: string;
|
|
11
|
+
|
|
12
|
+
const credential = { keyType: "CODEX_OAUTH", keySuffix: "d3Ove", keyIndex: 2 };
|
|
13
|
+
const authFailure =
|
|
14
|
+
"[auth-error] Codex authentication failed — check OPENAI_API_KEY or ChatGPT login. Original error: workspace routing discovery unauthorized (401)";
|
|
15
|
+
|
|
16
|
+
beforeAll(() => {
|
|
17
|
+
server = Bun.serve({
|
|
18
|
+
port: 0,
|
|
19
|
+
async fetch(req) {
|
|
20
|
+
const path = new URL(req.url).pathname;
|
|
21
|
+
const body = (await req.json()) as { clearAuthBench?: boolean };
|
|
22
|
+
if (path === "/api/keys/clear-rate-limit") {
|
|
23
|
+
await Bun.sleep(clearDelayMs);
|
|
24
|
+
handled.push(`clear:${body.clearAuthBench === true}`);
|
|
25
|
+
return Response.json({ success: true, cleared: true });
|
|
26
|
+
}
|
|
27
|
+
if (path === "/api/keys/report-auth-failure") {
|
|
28
|
+
handled.push("auth-failure");
|
|
29
|
+
return Response.json({
|
|
30
|
+
success: true,
|
|
31
|
+
consecutiveAuthFailures: handled.filter((h) => h === "auth-failure").length,
|
|
32
|
+
benched: false,
|
|
33
|
+
rateLimitedUntil: null,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return new Response("not found", { status: 404 });
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
apiUrl = `http://localhost:${server.port}`;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterAll(() => {
|
|
43
|
+
server.stop(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
handled.length = 0;
|
|
48
|
+
clearDelayMs = 0;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("reportKeyCompletionOutcome", () => {
|
|
52
|
+
test("a delayed success reset lands before later auth failures of the same login", async () => {
|
|
53
|
+
clearDelayMs = 200;
|
|
54
|
+
const completions = [
|
|
55
|
+
{ exitCode: 0, failureReason: undefined },
|
|
56
|
+
{ exitCode: 1, failureReason: authFailure },
|
|
57
|
+
{ exitCode: 1, failureReason: authFailure },
|
|
58
|
+
];
|
|
59
|
+
// Same shape as checkCompletedProcesses: one awaited report per completion.
|
|
60
|
+
for (const [i, c] of completions.entries()) {
|
|
61
|
+
await reportKeyCompletionOutcome({
|
|
62
|
+
apiUrl,
|
|
63
|
+
apiKey: "test-key",
|
|
64
|
+
credential,
|
|
65
|
+
taskId: `00000000-0000-4000-8000-00000000000${i}`,
|
|
66
|
+
...c,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
expect(handled).toEqual(["clear:true", "auth-failure", "auth-failure"]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("returns only after the success reset is handled", async () => {
|
|
73
|
+
clearDelayMs = 100;
|
|
74
|
+
await reportKeyCompletionOutcome({
|
|
75
|
+
apiUrl,
|
|
76
|
+
apiKey: "test-key",
|
|
77
|
+
credential,
|
|
78
|
+
taskId: "00000000-0000-4000-8000-000000000009",
|
|
79
|
+
exitCode: 0,
|
|
80
|
+
failureReason: undefined,
|
|
81
|
+
});
|
|
82
|
+
expect(handled).toEqual(["clear:true"]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("a non-auth failure sends no report", async () => {
|
|
86
|
+
await reportKeyCompletionOutcome({
|
|
87
|
+
apiUrl,
|
|
88
|
+
apiKey: "test-key",
|
|
89
|
+
credential,
|
|
90
|
+
taskId: "00000000-0000-4000-8000-00000000000b",
|
|
91
|
+
exitCode: 1,
|
|
92
|
+
failureReason: "[rate-limit] Codex API rate limit hit. Original error: 429",
|
|
93
|
+
});
|
|
94
|
+
expect(handled).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Last: its handler finishes after the test, so nothing may assert on `handled` later.
|
|
98
|
+
test("a hung success reset is bounded by the timeout and never throws", async () => {
|
|
99
|
+
clearDelayMs = 2_000;
|
|
100
|
+
const started = Date.now();
|
|
101
|
+
await reportKeyCompletionOutcome({
|
|
102
|
+
apiUrl,
|
|
103
|
+
apiKey: "test-key",
|
|
104
|
+
credential,
|
|
105
|
+
taskId: "00000000-0000-4000-8000-00000000000a",
|
|
106
|
+
exitCode: 0,
|
|
107
|
+
failureReason: undefined,
|
|
108
|
+
timeoutMs: 100,
|
|
109
|
+
});
|
|
110
|
+
expect(Date.now() - started).toBeLessThan(1_500);
|
|
111
|
+
});
|
|
112
|
+
});
|