@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
package/src/commands/runner.ts
CHANGED
|
@@ -36,7 +36,9 @@ import {
|
|
|
36
36
|
import type { SteerDeliveryResult } from "../providers/types.ts";
|
|
37
37
|
import { initTelemetry, telemetry } from "../telemetry.ts";
|
|
38
38
|
import {
|
|
39
|
+
type ModelTierOverrides,
|
|
39
40
|
type ProviderName,
|
|
41
|
+
parseWorkerModelTierOverrides,
|
|
40
42
|
type ReasoningEffort,
|
|
41
43
|
type RepoGuidelines,
|
|
42
44
|
resolveTaskModelSelection,
|
|
@@ -44,6 +46,7 @@ import {
|
|
|
44
46
|
} from "../types.ts";
|
|
45
47
|
import { getApiKey } from "../utils/api-key.ts";
|
|
46
48
|
import { computeBudgetBackoffMs } from "../utils/budget-backoff.ts";
|
|
49
|
+
import { isCodexAuthFailureReason } from "../utils/codex-auth-failure.ts";
|
|
47
50
|
import { getMcpBaseUrl } from "../utils/constants.ts";
|
|
48
51
|
import { getContextWindowSize } from "../utils/context-window.ts";
|
|
49
52
|
import {
|
|
@@ -51,16 +54,16 @@ import {
|
|
|
51
54
|
ModelWindowExhaustedError,
|
|
52
55
|
resolveCredentialPools,
|
|
53
56
|
} from "../utils/credentials.ts";
|
|
54
|
-
import {
|
|
55
|
-
|
|
56
|
-
resolveCodexCreditsExhaustedCooldownMs,
|
|
57
|
-
} from "../utils/error-tracker.ts";
|
|
57
|
+
import { resolveCodexCreditsExhaustedCooldownMs } from "../utils/error-tracker.ts";
|
|
58
|
+
import { probeHarnessCliVersion, reportHarnessModelOutcome } from "../utils/harness-cli-version.ts";
|
|
58
59
|
import { resolveHarnessProvider } from "../utils/harness-provider.ts";
|
|
59
60
|
import { prettyPrintLine, prettyPrintStderr } from "../utils/pretty-print.ts";
|
|
60
61
|
import { terminateRegisteredProcessGroups } from "../utils/process-group.ts";
|
|
62
|
+
import { refreshRuntimeModelCatalog } from "../utils/runtime-model-catalog.ts";
|
|
61
63
|
import { resolveScriptsOnlyMode } from "../utils/scripts-only-mode.ts";
|
|
62
64
|
import { scrubSecrets } from "../utils/secret-scrubber.ts";
|
|
63
65
|
import { refreshSkillsIfChanged } from "../utils/skills-refresh.ts";
|
|
66
|
+
import { guardSpawnModel } from "../utils/spawn-model-guard.ts";
|
|
64
67
|
import { isSteeringEnabled } from "../utils/steering-enabled.ts";
|
|
65
68
|
import { interpolate } from "../utils/template.ts";
|
|
66
69
|
import { detectVcsProvider } from "../vcs/index.ts";
|
|
@@ -71,6 +74,7 @@ import {
|
|
|
71
74
|
buildResumeContextPreamble,
|
|
72
75
|
prependContextPreamble,
|
|
73
76
|
} from "./context-preamble.ts";
|
|
77
|
+
import { reportCredentialOutcomeThenFinish } from "./credential-outcome-report.ts";
|
|
74
78
|
import { type CredentialRefreshState, refreshCredentialStatus } from "./credential-refresh.ts";
|
|
75
79
|
import {
|
|
76
80
|
awaitCredentials,
|
|
@@ -95,7 +99,6 @@ import {
|
|
|
95
99
|
reportLatestModel,
|
|
96
100
|
sendCredStatusReport,
|
|
97
101
|
} from "./provider-credentials.ts";
|
|
98
|
-
import { buildFinalRateLimitWindows, classifyRateLimitOutcome } from "./rate-limit-outcome.ts";
|
|
99
102
|
import {
|
|
100
103
|
type ResumeSessionCandidate,
|
|
101
104
|
type ResumeSessionResolution,
|
|
@@ -105,6 +108,7 @@ import {
|
|
|
105
108
|
import "./templates.ts";
|
|
106
109
|
|
|
107
110
|
export { buildAttachmentsSection } from "./attachments-section.ts";
|
|
111
|
+
export { reportKeyRateLimitWindows } from "./credential-outcome-report.ts";
|
|
108
112
|
|
|
109
113
|
/** Throttle interval for progress updates (3 seconds). */
|
|
110
114
|
const PROGRESS_THROTTLE_MS = 3000;
|
|
@@ -773,6 +777,16 @@ export interface ResolvedEnvResult {
|
|
|
773
777
|
// Preserve the deployment value before config reloads mutate process.env.
|
|
774
778
|
const deploymentMemoryRaters = process.env.MEMORY_RATERS;
|
|
775
779
|
|
|
780
|
+
/**
|
|
781
|
+
* Container value (undefined when unset) of each RELOADABLE_ENV_KEYS entry a
|
|
782
|
+
* swarm_config row has overwritten in process.env, recorded before the first
|
|
783
|
+
* overwrite. A reload starts from process.env, so without this a deleted row
|
|
784
|
+
* would leave its value in place until the container restarts. Keys no row
|
|
785
|
+
* ever overwrote are absent and keep the container value. MEMORY_RATERS keeps
|
|
786
|
+
* its own deployment snapshot above.
|
|
787
|
+
*/
|
|
788
|
+
const rowOverriddenBootEnv = new Map<string, string | undefined>();
|
|
789
|
+
|
|
776
790
|
export async function fetchResolvedEnv(
|
|
777
791
|
apiUrl: string,
|
|
778
792
|
apiKey: string,
|
|
@@ -823,6 +837,11 @@ export async function fetchResolvedEnv(
|
|
|
823
837
|
// Only reset after a successful fetch so outages retain the current value.
|
|
824
838
|
env.MEMORY_RATERS =
|
|
825
839
|
baseEnv === process.env ? deploymentMemoryRaters : baseEnv.MEMORY_RATERS;
|
|
840
|
+
// Same for every other key a row overwrote: start from the container
|
|
841
|
+
// value, so a row that is gone no longer applies.
|
|
842
|
+
if (baseEnv === process.env) {
|
|
843
|
+
for (const [key, bootValue] of rowOverriddenBootEnv) env[key] = bootValue;
|
|
844
|
+
}
|
|
826
845
|
|
|
827
846
|
if (data.configs?.length) {
|
|
828
847
|
scriptsOnlyConfigValue = data.configs.find(
|
|
@@ -1045,7 +1064,7 @@ export async function provisionAgentFsAfterRegistration(opts: {
|
|
|
1045
1064
|
*
|
|
1046
1065
|
* - STEERING_ENABLED — read per-poll by `isSteeringEnabled()` and by the
|
|
1047
1066
|
* system-prompt builder; flipping it mid-run just gates a feature.
|
|
1048
|
-
* - ANONYMIZED_TELEMETRY — read per-event by `
|
|
1067
|
+
* - ANONYMIZED_TELEMETRY — read per-event by `isTelemetryEnabled()`.
|
|
1049
1068
|
* - MEMORY_RATERS — read per hook/prompt invocation.
|
|
1050
1069
|
* - TEMPLATE_REGISTRY_URL — read per registry fetch.
|
|
1051
1070
|
* - SLACK_DISABLE — read by the prompt builder to gate the Slack tool section.
|
|
@@ -1069,6 +1088,9 @@ export const RELOADABLE_ENV_KEYS: ReadonlySet<string> = new Set([
|
|
|
1069
1088
|
"TEMPLATE_REGISTRY_URL",
|
|
1070
1089
|
"SLACK_DISABLE",
|
|
1071
1090
|
"SWARM_ORG_NAME",
|
|
1091
|
+
// pi reads these from process.env for its traits and its session.
|
|
1092
|
+
"PI_TOOL_DEFERRAL",
|
|
1093
|
+
"PI_CODEMODE",
|
|
1072
1094
|
]);
|
|
1073
1095
|
|
|
1074
1096
|
/**
|
|
@@ -1105,11 +1127,20 @@ export function applyResolvedEnvToProcessEnv(
|
|
|
1105
1127
|
const changed: string[] = [];
|
|
1106
1128
|
for (const key of RELOADABLE_ENV_KEYS) {
|
|
1107
1129
|
const next = freshEnv[key];
|
|
1108
|
-
if (
|
|
1130
|
+
if (
|
|
1131
|
+
next === undefined &&
|
|
1132
|
+
process.env[key] !== undefined &&
|
|
1133
|
+
(key === "MEMORY_RATERS" || rowOverriddenBootEnv.has(key))
|
|
1134
|
+
) {
|
|
1135
|
+
// A deleted row for a key the container never set. Keys no row
|
|
1136
|
+
// overwrote stay as the container set them.
|
|
1109
1137
|
delete process.env[key];
|
|
1110
1138
|
changed.push(key);
|
|
1111
1139
|
} else if (next !== undefined && next !== process.env[key]) {
|
|
1112
1140
|
const previous = process.env[key];
|
|
1141
|
+
if (key !== "MEMORY_RATERS" && !rowOverriddenBootEnv.has(key)) {
|
|
1142
|
+
rowOverriddenBootEnv.set(key, previous);
|
|
1143
|
+
}
|
|
1113
1144
|
process.env[key] = next;
|
|
1114
1145
|
changed.push(key);
|
|
1115
1146
|
// Make a reload that blanks a previously-set value loud — silently
|
|
@@ -1220,6 +1251,8 @@ const SWARM_TOOL_LABELS: Record<string, string | null> = {
|
|
|
1220
1251
|
"set-config": "⚙️ Setting config",
|
|
1221
1252
|
"list-config": "⚙️ Listing config",
|
|
1222
1253
|
"delete-config": "⚙️ Deleting config",
|
|
1254
|
+
"model-catalog-refresh": "🧠 Refreshing model catalog",
|
|
1255
|
+
"model-catalog-overlay-upsert": "🧠 Updating model catalog overlay",
|
|
1223
1256
|
// Schedules
|
|
1224
1257
|
"create-schedule": "📅 Creating schedule",
|
|
1225
1258
|
"list-schedules": "📅 Listing schedules",
|
|
@@ -1773,14 +1806,19 @@ export async function resolveCodexOAuthCredentialInfo(
|
|
|
1773
1806
|
const slots = await loadAllCodexOAuthSlots(apiUrl, apiKey);
|
|
1774
1807
|
if (slots.length > 0) {
|
|
1775
1808
|
let availableIndices: number[] | undefined;
|
|
1809
|
+
let authFailureFence: number | undefined;
|
|
1776
1810
|
try {
|
|
1777
1811
|
const resp = await fetch(
|
|
1778
1812
|
`${apiUrl}/api/keys/available?keyType=CODEX_OAUTH&totalKeys=${slots.length}`,
|
|
1779
1813
|
{ headers: { Authorization: `Bearer ${apiKey}` } },
|
|
1780
1814
|
);
|
|
1781
1815
|
if (resp.ok) {
|
|
1782
|
-
const data = (await resp.json()) as {
|
|
1816
|
+
const data = (await resp.json()) as {
|
|
1817
|
+
availableIndices: number[];
|
|
1818
|
+
authFailureFence?: number;
|
|
1819
|
+
};
|
|
1783
1820
|
availableIndices = data.availableIndices;
|
|
1821
|
+
authFailureFence = data.authFailureFence;
|
|
1784
1822
|
if (availableIndices.length < slots.length) {
|
|
1785
1823
|
console.log(
|
|
1786
1824
|
`[credentials] CODEX_OAUTH: ${availableIndices.length}/${slots.length} slots available (${slots.length - availableIndices.length} rate-limited)`,
|
|
@@ -1821,7 +1859,10 @@ export async function resolveCodexOAuthCredentialInfo(
|
|
|
1821
1859
|
},
|
|
1822
1860
|
last_refresh: new Date(slotEntry.creds.expires).toISOString(),
|
|
1823
1861
|
};
|
|
1824
|
-
const sel =
|
|
1862
|
+
const sel = {
|
|
1863
|
+
...authJsonToCredentialSelection(authJson, selectedSlot, slots.length),
|
|
1864
|
+
authFailureFence,
|
|
1865
|
+
};
|
|
1825
1866
|
console.log(
|
|
1826
1867
|
`[credentials] Selected CODEX_OAUTH slot ${selectedSlot + 1}/${slots.length} [...${sel.keySuffix}]`,
|
|
1827
1868
|
);
|
|
@@ -1864,92 +1905,54 @@ export async function resolveCodexOAuthCredentialInfo(
|
|
|
1864
1905
|
}
|
|
1865
1906
|
}
|
|
1866
1907
|
|
|
1867
|
-
/**
|
|
1868
|
-
|
|
1908
|
+
/** Upper bound on each awaited credential-outcome report, so a slow API never stalls completions. */
|
|
1909
|
+
const KEY_OUTCOME_REPORT_TIMEOUT_MS = 5000;
|
|
1910
|
+
|
|
1911
|
+
/** Report a Codex pool auth failure; the API benches after 2 in a row. Awaited, never throws. */
|
|
1912
|
+
async function reportKeyAuthFailure(
|
|
1869
1913
|
apiUrl: string,
|
|
1870
1914
|
apiKey: string,
|
|
1871
1915
|
keyType: string,
|
|
1872
1916
|
keySuffix: string,
|
|
1873
1917
|
keyIndex: number,
|
|
1874
|
-
|
|
1918
|
+
taskId: string,
|
|
1919
|
+
timeoutMs = KEY_OUTCOME_REPORT_TIMEOUT_MS,
|
|
1875
1920
|
): Promise<void> {
|
|
1876
1921
|
try {
|
|
1877
|
-
await fetch(`${apiUrl}/api/keys/report-
|
|
1922
|
+
const resp = await fetch(`${apiUrl}/api/keys/report-auth-failure`, {
|
|
1878
1923
|
method: "POST",
|
|
1879
1924
|
headers: {
|
|
1880
1925
|
"Content-Type": "application/json",
|
|
1881
1926
|
Authorization: `Bearer ${apiKey}`,
|
|
1882
1927
|
},
|
|
1883
|
-
body: JSON.stringify({
|
|
1884
|
-
|
|
1885
|
-
keySuffix,
|
|
1886
|
-
keyIndex,
|
|
1887
|
-
rateLimitedUntil,
|
|
1888
|
-
}),
|
|
1928
|
+
body: JSON.stringify({ keyType, keySuffix, keyIndex, taskId }),
|
|
1929
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1889
1930
|
});
|
|
1931
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
1932
|
+
const data = (await resp.json()) as {
|
|
1933
|
+
consecutiveAuthFailures: number;
|
|
1934
|
+
benched: boolean;
|
|
1935
|
+
rateLimitedUntil: string | null;
|
|
1936
|
+
};
|
|
1890
1937
|
console.log(
|
|
1891
|
-
`[credentials]
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
// Non-blocking
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
|
|
1898
|
-
/**
|
|
1899
|
-
* Reports rate-limit window telemetry for a key. Returns the underlying
|
|
1900
|
-
* fetch promise (does not swallow errors) so a caller that needs the post to
|
|
1901
|
-
* complete before the task finishes (a model-scoped block) can await it and
|
|
1902
|
-
* decide how to handle a failure; a caller that wants the legacy
|
|
1903
|
-
* fire-and-forget behavior appends `.catch(() => {})`.
|
|
1904
|
-
*
|
|
1905
|
-
* Throws on a non-2xx response so a failed persistence surfaces to the
|
|
1906
|
-
* caller instead of logging success while only the in-process guard took
|
|
1907
|
-
* effect — otherwise other workers redraw the same exhausted key at once.
|
|
1908
|
-
*
|
|
1909
|
-
* `logKeySuffix` defaults to true for the legacy full-telemetry call site;
|
|
1910
|
-
* the model-scoped call site passes false since it already logs the model
|
|
1911
|
-
* family and key index itself (see the `[credential] model window ...`
|
|
1912
|
-
* log above the call).
|
|
1913
|
-
*/
|
|
1914
|
-
export async function reportKeyRateLimitWindows(
|
|
1915
|
-
apiUrl: string,
|
|
1916
|
-
apiKey: string,
|
|
1917
|
-
keyType: string,
|
|
1918
|
-
keySuffix: string,
|
|
1919
|
-
keyIndex: number,
|
|
1920
|
-
windows: RateLimitWindowTelemetry,
|
|
1921
|
-
logKeySuffix = true,
|
|
1922
|
-
): Promise<void> {
|
|
1923
|
-
if (Object.keys(windows).length === 0) return;
|
|
1924
|
-
const response = await fetch(`${apiUrl}/api/keys/report-rate-limit-windows`, {
|
|
1925
|
-
method: "POST",
|
|
1926
|
-
headers: {
|
|
1927
|
-
"Content-Type": "application/json",
|
|
1928
|
-
Authorization: `Bearer ${apiKey}`,
|
|
1929
|
-
},
|
|
1930
|
-
body: JSON.stringify({
|
|
1931
|
-
keyType,
|
|
1932
|
-
keySuffix,
|
|
1933
|
-
keyIndex,
|
|
1934
|
-
windows,
|
|
1935
|
-
}),
|
|
1936
|
-
});
|
|
1937
|
-
if (!response.ok) {
|
|
1938
|
-
throw new Error(
|
|
1939
|
-
`Failed to report rate-limit windows for key #${keyIndex}: HTTP ${response.status}`,
|
|
1938
|
+
`[credentials] Auth failure on ...${keySuffix}: ${data.consecutiveAuthFailures} in a row${
|
|
1939
|
+
data.benched ? `; benched until ${data.rateLimitedUntil}` : ""
|
|
1940
|
+
}`,
|
|
1940
1941
|
);
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
console.
|
|
1942
|
+
} catch (err) {
|
|
1943
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1944
|
+
console.warn(scrubSecrets(`[credentials] Failed to report auth failure: ${message}`));
|
|
1944
1945
|
}
|
|
1945
1946
|
}
|
|
1946
1947
|
|
|
1947
|
-
/** Clear a stale rate-limit record after a successful task
|
|
1948
|
+
/** Clear a stale rate-limit record after a successful task. Bounded, never throws. */
|
|
1948
1949
|
async function reportKeyClearRateLimit(
|
|
1949
1950
|
apiUrl: string,
|
|
1950
1951
|
apiKey: string,
|
|
1951
1952
|
keyType: string,
|
|
1952
1953
|
keySuffix: string,
|
|
1954
|
+
authFence: number | undefined,
|
|
1955
|
+
timeoutMs = KEY_OUTCOME_REPORT_TIMEOUT_MS,
|
|
1953
1956
|
): Promise<void> {
|
|
1954
1957
|
try {
|
|
1955
1958
|
const resp = await fetch(`${apiUrl}/api/keys/clear-rate-limit`, {
|
|
@@ -1958,7 +1961,11 @@ async function reportKeyClearRateLimit(
|
|
|
1958
1961
|
"Content-Type": "application/json",
|
|
1959
1962
|
Authorization: `Bearer ${apiKey}`,
|
|
1960
1963
|
},
|
|
1961
|
-
|
|
1964
|
+
// A task that exited 0 proves the login works, so it may lift an auth bench.
|
|
1965
|
+
// `authFence` (read before the task started) stops a late (timed-out) report,
|
|
1966
|
+
// from this or any other worker, from clearing failures recorded after it.
|
|
1967
|
+
body: JSON.stringify({ keyType, keySuffix, clearAuthBench: true, authFence }),
|
|
1968
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1962
1969
|
});
|
|
1963
1970
|
if (resp.ok) {
|
|
1964
1971
|
const data = (await resp.json()) as { cleared?: boolean };
|
|
@@ -1973,6 +1980,49 @@ async function reportKeyClearRateLimit(
|
|
|
1973
1980
|
}
|
|
1974
1981
|
}
|
|
1975
1982
|
|
|
1983
|
+
/**
|
|
1984
|
+
* Report a finished task's credential outcome: a success resets the auth-failure
|
|
1985
|
+
* count (and lifts an auth bench); a counted Codex auth failure adds to it.
|
|
1986
|
+
* Awaited by the caller before it processes the next completion, so the API sees
|
|
1987
|
+
* success and failure reports in completion order. A success carries the
|
|
1988
|
+
* `authFence` the task read before it started: when its report times out and
|
|
1989
|
+
* lands late, the API keeps every auth failure recorded after that fence.
|
|
1990
|
+
* Without a fence, a success clears only an ordinary rate limit. Bounded, never throws.
|
|
1991
|
+
*/
|
|
1992
|
+
export async function reportKeyCompletionOutcome(opts: {
|
|
1993
|
+
apiUrl: string;
|
|
1994
|
+
apiKey: string;
|
|
1995
|
+
credential: { keyType: string; keySuffix: string; keyIndex: number; authFence?: number };
|
|
1996
|
+
taskId: string;
|
|
1997
|
+
exitCode: number;
|
|
1998
|
+
failureReason: string | undefined;
|
|
1999
|
+
timeoutMs?: number;
|
|
2000
|
+
}): Promise<void> {
|
|
2001
|
+
const { apiUrl, apiKey, credential, taskId, exitCode, failureReason, timeoutMs } = opts;
|
|
2002
|
+
if (exitCode === 0) {
|
|
2003
|
+
await reportKeyClearRateLimit(
|
|
2004
|
+
apiUrl,
|
|
2005
|
+
apiKey,
|
|
2006
|
+
credential.keyType,
|
|
2007
|
+
credential.keySuffix,
|
|
2008
|
+
credential.authFence,
|
|
2009
|
+
timeoutMs,
|
|
2010
|
+
);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
if (credential.keyType === "CODEX_OAUTH" && isCodexAuthFailureReason(failureReason)) {
|
|
2014
|
+
await reportKeyAuthFailure(
|
|
2015
|
+
apiUrl,
|
|
2016
|
+
apiKey,
|
|
2017
|
+
credential.keyType,
|
|
2018
|
+
credential.keySuffix,
|
|
2019
|
+
credential.keyIndex,
|
|
2020
|
+
taskId,
|
|
2021
|
+
timeoutMs,
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1976
2026
|
/**
|
|
1977
2027
|
* Supersede a task via the API (for graceful shutdown / context-limit /
|
|
1978
2028
|
* operator-triggered). Returns `{ ok: true, resumeTaskId }` on success.
|
|
@@ -2342,7 +2392,7 @@ export interface RunnerOptions {
|
|
|
2342
2392
|
}
|
|
2343
2393
|
|
|
2344
2394
|
/** Running task state for parallel execution */
|
|
2345
|
-
interface RunningTask {
|
|
2395
|
+
export interface RunningTask {
|
|
2346
2396
|
taskId: string;
|
|
2347
2397
|
session: ProviderSession;
|
|
2348
2398
|
logFile: string;
|
|
@@ -2361,6 +2411,8 @@ interface RunningTask {
|
|
|
2361
2411
|
keyType: string;
|
|
2362
2412
|
keySuffix: string;
|
|
2363
2413
|
keyIndex: number;
|
|
2414
|
+
/** `authFailureFence` read before the task started (Codex pool only). */
|
|
2415
|
+
authFence?: number;
|
|
2364
2416
|
};
|
|
2365
2417
|
/**
|
|
2366
2418
|
* Harness provider this session was actually spawned/resumed on, snapshotted
|
|
@@ -2392,7 +2444,7 @@ interface RunningTask {
|
|
|
2392
2444
|
}
|
|
2393
2445
|
|
|
2394
2446
|
/** Runner state for tracking concurrent tasks */
|
|
2395
|
-
interface RunnerState {
|
|
2447
|
+
export interface RunnerState {
|
|
2396
2448
|
activeTasks: Map<string, RunningTask>;
|
|
2397
2449
|
maxConcurrent: number;
|
|
2398
2450
|
startedAt: number;
|
|
@@ -2909,6 +2961,16 @@ interface PollOptions {
|
|
|
2909
2961
|
pollInterval: number;
|
|
2910
2962
|
pollTimeout: number;
|
|
2911
2963
|
since?: string; // Optional: for filtering finished tasks
|
|
2964
|
+
/** Live harness provider; keys the MODEL_TIER_* overrides sent with the poll. */
|
|
2965
|
+
harnessProvider?: ProviderName;
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
/**
|
|
2969
|
+
* The worker's own MODEL_TIER_* overrides, parsed from its process env (not
|
|
2970
|
+
* the swarm_config-merged env: global config is already visible server-side).
|
|
2971
|
+
*/
|
|
2972
|
+
function workerModelTierOverrides(provider: ProviderName): ModelTierOverrides {
|
|
2973
|
+
return parseWorkerModelTierOverrides(process.env, provider);
|
|
2912
2974
|
}
|
|
2913
2975
|
|
|
2914
2976
|
type RequesterProfile = NonNullable<Trigger["requestedBy"]>;
|
|
@@ -2940,6 +3002,86 @@ export async function buildRequesterProfilePrompt(
|
|
|
2940
3002
|
return result.skipped ? "" : result.text.trim();
|
|
2941
3003
|
}
|
|
2942
3004
|
|
|
3005
|
+
/** A non-2xx answer from `POST /api/agents`; carries the status for retry triage. */
|
|
3006
|
+
export class AgentRegistrationHttpError extends Error {
|
|
3007
|
+
readonly status: number;
|
|
3008
|
+
readonly body: string;
|
|
3009
|
+
constructor(status: number, body: string) {
|
|
3010
|
+
super(`Failed to register agent: ${status} ${body}`);
|
|
3011
|
+
this.name = "AgentRegistrationHttpError";
|
|
3012
|
+
this.status = status;
|
|
3013
|
+
this.body = body;
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
/**
|
|
3018
|
+
* Whether a boot registration failure is worth retrying. A freshly deployed
|
|
3019
|
+
* API can answer `500 {"error":"database is locked"}` for minutes while boot
|
|
3020
|
+
* work holds the SQLite write lock, and is unreachable while it restarts;
|
|
3021
|
+
* both clear on their own. A 4xx (bad key, bad payload) never will.
|
|
3022
|
+
*/
|
|
3023
|
+
export function isRetryableRegistrationError(err: unknown): boolean {
|
|
3024
|
+
if (err instanceof AgentRegistrationHttpError) {
|
|
3025
|
+
return (
|
|
3026
|
+
err.status >= 500 ||
|
|
3027
|
+
err.status === 408 ||
|
|
3028
|
+
err.status === 429 ||
|
|
3029
|
+
/database is locked/i.test(err.body)
|
|
3030
|
+
);
|
|
3031
|
+
}
|
|
3032
|
+
// Anything else escaped fetch itself: connection refused, reset, DNS, timeout.
|
|
3033
|
+
return true;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
export const REGISTRATION_RETRY_BUDGET_MS = 5 * 60_000;
|
|
3037
|
+
const REGISTRATION_RETRY_BASE_DELAY_MS = 2_000;
|
|
3038
|
+
const REGISTRATION_RETRY_MAX_DELAY_MS = 30_000;
|
|
3039
|
+
|
|
3040
|
+
/**
|
|
3041
|
+
* Boot registration with bounded exponential backoff (2s doubling to 30s,
|
|
3042
|
+
* with jitter) inside a total wall-clock budget. Throws the last error on a
|
|
3043
|
+
* non-retryable failure or once the next wait would overrun the budget, so
|
|
3044
|
+
* the caller still exits and a restart policy can take over.
|
|
3045
|
+
*/
|
|
3046
|
+
export async function registerAgentWithRetry(
|
|
3047
|
+
register: () => Promise<{ serverCapabilities?: string[] }>,
|
|
3048
|
+
opts: {
|
|
3049
|
+
label: string;
|
|
3050
|
+
budgetMs?: number;
|
|
3051
|
+
baseDelayMs?: number;
|
|
3052
|
+
maxDelayMs?: number;
|
|
3053
|
+
sleep?: (ms: number) => Promise<void>;
|
|
3054
|
+
now?: () => number;
|
|
3055
|
+
},
|
|
3056
|
+
): Promise<{ serverCapabilities?: string[] }> {
|
|
3057
|
+
const budgetMs = opts.budgetMs ?? REGISTRATION_RETRY_BUDGET_MS;
|
|
3058
|
+
const baseDelayMs = opts.baseDelayMs ?? REGISTRATION_RETRY_BASE_DELAY_MS;
|
|
3059
|
+
const maxDelayMs = opts.maxDelayMs ?? REGISTRATION_RETRY_MAX_DELAY_MS;
|
|
3060
|
+
const sleep = opts.sleep ?? ((ms: number) => Bun.sleep(ms));
|
|
3061
|
+
const now = opts.now ?? Date.now;
|
|
3062
|
+
const startedAt = now();
|
|
3063
|
+
for (let attempt = 1; ; attempt++) {
|
|
3064
|
+
try {
|
|
3065
|
+
return await register();
|
|
3066
|
+
} catch (err) {
|
|
3067
|
+
if (!isRetryableRegistrationError(err)) throw err;
|
|
3068
|
+
const backoff = Math.min(maxDelayMs, baseDelayMs * 2 ** (attempt - 1));
|
|
3069
|
+
const delay = Math.round(backoff * (0.8 + Math.random() * 0.4));
|
|
3070
|
+
const elapsed = now() - startedAt;
|
|
3071
|
+
if (elapsed + delay > budgetMs) {
|
|
3072
|
+
console.error(
|
|
3073
|
+
`[${opts.label}] Registration still failing after ${attempt} attempts in ${Math.round(elapsed / 1000)}s; giving up`,
|
|
3074
|
+
);
|
|
3075
|
+
throw err;
|
|
3076
|
+
}
|
|
3077
|
+
console.warn(
|
|
3078
|
+
`[${opts.label}] Registration attempt ${attempt} failed (${err}); retrying in ${Math.round(delay / 1000)}s`,
|
|
3079
|
+
);
|
|
3080
|
+
await sleep(delay);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
|
|
2943
3085
|
/** Register agent via HTTP API. Exported so tests can exercise the real boot ordering. */
|
|
2944
3086
|
export async function registerAgent(opts: {
|
|
2945
3087
|
apiUrl: string;
|
|
@@ -2990,12 +3132,14 @@ export async function registerAgent(opts: {
|
|
|
2990
3132
|
provider,
|
|
2991
3133
|
harness_provider: harnessProvider,
|
|
2992
3134
|
runtimeInstanceId: opts.runtimeInstanceId,
|
|
3135
|
+
modelTierOverrides: workerModelTierOverrides(harnessProvider),
|
|
3136
|
+
harnessCliVersion: (await probeHarnessCliVersion(harnessProvider)) ?? undefined,
|
|
2993
3137
|
}),
|
|
2994
3138
|
});
|
|
2995
3139
|
|
|
2996
3140
|
if (!response.ok) {
|
|
2997
3141
|
const error = await response.text();
|
|
2998
|
-
throw new
|
|
3142
|
+
throw new AgentRegistrationHttpError(response.status, error);
|
|
2999
3143
|
}
|
|
3000
3144
|
|
|
3001
3145
|
// The register response carries the SERVER's enabled capability flags (which
|
|
@@ -3035,6 +3179,14 @@ async function pollForTrigger(opts: PollOptions): Promise<Trigger | null> {
|
|
|
3035
3179
|
|
|
3036
3180
|
async function pollForTriggerOnce(opts: PollOptions): Promise<Trigger | null> {
|
|
3037
3181
|
const startTime = Date.now();
|
|
3182
|
+
// Keep the process-wide model catalog fresh (TTL-cached, never throws) so
|
|
3183
|
+
// context windows, pricing and reasoning levels cover models added to the
|
|
3184
|
+
// API's catalog after this worker booted.
|
|
3185
|
+
void refreshRuntimeModelCatalog({
|
|
3186
|
+
apiUrl: opts.apiUrl,
|
|
3187
|
+
apiKey: opts.apiKey,
|
|
3188
|
+
agentId: opts.agentId,
|
|
3189
|
+
});
|
|
3038
3190
|
const headers: Record<string, string> = {
|
|
3039
3191
|
"X-Agent-ID": opts.agentId,
|
|
3040
3192
|
};
|
|
@@ -3045,6 +3197,11 @@ async function pollForTriggerOnce(opts: PollOptions): Promise<Trigger | null> {
|
|
|
3045
3197
|
headers.Authorization = `Bearer ${opts.apiKey}`;
|
|
3046
3198
|
}
|
|
3047
3199
|
injectTraceContext(headers);
|
|
3200
|
+
if (opts.harnessProvider) {
|
|
3201
|
+
headers["X-Model-Tier-Overrides"] = encodeURIComponent(
|
|
3202
|
+
JSON.stringify(workerModelTierOverrides(opts.harnessProvider)),
|
|
3203
|
+
);
|
|
3204
|
+
}
|
|
3048
3205
|
|
|
3049
3206
|
while (Date.now() - startTime < opts.pollTimeout) {
|
|
3050
3207
|
try {
|
|
@@ -3527,6 +3684,9 @@ async function spawnProviderProcess(
|
|
|
3527
3684
|
taskId?: string;
|
|
3528
3685
|
model?: string;
|
|
3529
3686
|
modelTier?: string;
|
|
3687
|
+
/** Server claim-time resolution (task.resolvedModel); wins over the local one. */
|
|
3688
|
+
resolvedModel?: string;
|
|
3689
|
+
modelSource?: string;
|
|
3530
3690
|
effort?: ReasoningEffort;
|
|
3531
3691
|
resumeSessionId?: string;
|
|
3532
3692
|
harnessProvider: ProviderName;
|
|
@@ -3562,7 +3722,7 @@ async function spawnProviderProcess(
|
|
|
3562
3722
|
opts.apiKey,
|
|
3563
3723
|
opts.agentId,
|
|
3564
3724
|
process.env,
|
|
3565
|
-
opts.model,
|
|
3725
|
+
opts.resolvedModel || opts.model,
|
|
3566
3726
|
{
|
|
3567
3727
|
repoId: sessionRepo?.id,
|
|
3568
3728
|
provider: adapter.name as ProviderName,
|
|
@@ -3573,8 +3733,7 @@ async function spawnProviderProcess(
|
|
|
3573
3733
|
));
|
|
3574
3734
|
} catch (err) {
|
|
3575
3735
|
if (err instanceof ModelWindowExhaustedError && realTaskId) {
|
|
3576
|
-
const
|
|
3577
|
-
const reason = `No ${err.keyType} key has ${modelLabel} capacity until ${err.earliestResetAt ?? "unknown"}. Re-dispatch with another model or modelTier.`;
|
|
3736
|
+
const reason = err.message;
|
|
3578
3737
|
console.warn(`[${opts.role}] ${reason}`);
|
|
3579
3738
|
await ensureTaskFinished(
|
|
3580
3739
|
{ apiUrl: opts.apiUrl, apiKey: opts.apiKey, agentId: opts.agentId },
|
|
@@ -3619,8 +3778,44 @@ async function spawnProviderProcess(
|
|
|
3619
3778
|
harnessProvider: opts.harnessProvider,
|
|
3620
3779
|
env: freshEnv,
|
|
3621
3780
|
});
|
|
3622
|
-
|
|
3623
|
-
|
|
3781
|
+
// The server resolves the model at claim time (worker-env > tier-config >
|
|
3782
|
+
// tier-default, `latest:` aliases, guardrails) and records it on the task.
|
|
3783
|
+
// The local resolution stays as a check: a difference usually means the
|
|
3784
|
+
// server saw a stale MODEL_TIER_* override or a swarm_config tier value.
|
|
3785
|
+
if (
|
|
3786
|
+
opts.resolvedModel &&
|
|
3787
|
+
taskModelSelection.model &&
|
|
3788
|
+
taskModelSelection.model !== opts.resolvedModel
|
|
3789
|
+
) {
|
|
3790
|
+
console.log(
|
|
3791
|
+
`[${opts.role}] model resolution mismatch for task ${opts.taskId ?? "?"}: server=${opts.resolvedModel} (${opts.modelSource ?? "?"}) local=${taskModelSelection.model}; using server value`,
|
|
3792
|
+
);
|
|
3793
|
+
}
|
|
3794
|
+
const taskModel = opts.resolvedModel || taskModelSelection.model || "";
|
|
3795
|
+
// Never start a CLI with a model from another harness family (runbooks/model-tiers.md).
|
|
3796
|
+
const spawnModel = guardSpawnModel({
|
|
3797
|
+
taskModel,
|
|
3798
|
+
configModel,
|
|
3799
|
+
harness: opts.harnessProvider,
|
|
3800
|
+
role: opts.role,
|
|
3801
|
+
});
|
|
3802
|
+
if (spawnModel.kind === "mismatch") {
|
|
3803
|
+
console.warn(`[${opts.role}] ${spawnModel.reason}`);
|
|
3804
|
+
if (realTaskId) {
|
|
3805
|
+
await ensureTaskFinished(
|
|
3806
|
+
{ apiUrl: opts.apiUrl, apiKey: opts.apiKey, agentId: opts.agentId },
|
|
3807
|
+
opts.role,
|
|
3808
|
+
realTaskId,
|
|
3809
|
+
1,
|
|
3810
|
+
spawnModel.reason,
|
|
3811
|
+
undefined,
|
|
3812
|
+
opts.harnessProvider,
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3815
|
+
throw new Error(spawnModel.reason);
|
|
3816
|
+
}
|
|
3817
|
+
if (spawnModel.warning) console.warn(spawnModel.warning);
|
|
3818
|
+
const model = spawnModel.model;
|
|
3624
3819
|
|
|
3625
3820
|
// Resolve Codex OAuth pool slot BEFORE building ProviderSessionConfig so we
|
|
3626
3821
|
// can pass codexSlot through and the adapter writes token refreshes back to
|
|
@@ -4389,6 +4584,7 @@ async function spawnProviderProcess(
|
|
|
4389
4584
|
keyType: primarySelection.keyType,
|
|
4390
4585
|
keySuffix: primarySelection.keySuffix,
|
|
4391
4586
|
keyIndex: primarySelection.index,
|
|
4587
|
+
authFence: primarySelection.authFailureFence,
|
|
4392
4588
|
}
|
|
4393
4589
|
: undefined;
|
|
4394
4590
|
|
|
@@ -4428,8 +4624,8 @@ async function spawnProviderProcess(
|
|
|
4428
4624
|
return runningTask;
|
|
4429
4625
|
}
|
|
4430
4626
|
|
|
4431
|
-
/** Check for completed processes and remove them from active tasks */
|
|
4432
|
-
async function checkCompletedProcesses(
|
|
4627
|
+
/** Check for completed processes and remove them from active tasks. Exported for tests. */
|
|
4628
|
+
export async function checkCompletedProcesses(
|
|
4433
4629
|
state: RunnerState,
|
|
4434
4630
|
role: string,
|
|
4435
4631
|
apiConfig?: ApiConfig,
|
|
@@ -4517,77 +4713,26 @@ async function checkCompletedProcesses(
|
|
|
4517
4713
|
console.log(`[${role}] Detected error for task ${taskId.slice(0, 8)}: ${failureReason}`);
|
|
4518
4714
|
}
|
|
4519
4715
|
|
|
4520
|
-
//
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
// window telemetry and the classified model rejection go out as ONE
|
|
4532
|
-
// payload, so an older `allowed` snapshot never overwrites the terminal
|
|
4533
|
-
// rejection. The post is awaited so it completes before the task
|
|
4534
|
-
// finishes.
|
|
4716
|
+
// Record whether this worker's CLI accepts the model (harness_model_support).
|
|
4717
|
+
void reportHarnessModelOutcome({
|
|
4718
|
+
apiUrl: apiConfig.apiUrl,
|
|
4719
|
+
apiKey: apiConfig.apiKey,
|
|
4720
|
+
agentId: apiConfig.agentId,
|
|
4721
|
+
harness: harnessProvider,
|
|
4722
|
+
model,
|
|
4723
|
+
exitCode: result.exitCode,
|
|
4724
|
+
failureReason,
|
|
4725
|
+
});
|
|
4726
|
+
|
|
4535
4727
|
if (credentialInfo) {
|
|
4536
|
-
|
|
4537
|
-
|
|
4728
|
+
await reportKeyCompletionOutcome({
|
|
4729
|
+
apiUrl: apiConfig.apiUrl,
|
|
4730
|
+
apiKey: apiConfig.apiKey,
|
|
4731
|
+
credential: credentialInfo,
|
|
4732
|
+
taskId,
|
|
4733
|
+
exitCode: result.exitCode,
|
|
4538
4734
|
failureReason,
|
|
4539
|
-
|
|
4540
|
-
state.codexCreditsExhaustedCooldownMs,
|
|
4541
|
-
);
|
|
4542
|
-
const keyRateLimitedUntil =
|
|
4543
|
-
outcome.kind === "key"
|
|
4544
|
-
? outcome.rateLimitedUntil
|
|
4545
|
-
: outcome.kind === "model"
|
|
4546
|
-
? outcome.keyRateLimitedUntil
|
|
4547
|
-
: undefined;
|
|
4548
|
-
if (keyRateLimitedUntil) {
|
|
4549
|
-
console.log(`[credentials] Rate limit reset: ${keyRateLimitedUntil}`);
|
|
4550
|
-
reportKeyRateLimit(
|
|
4551
|
-
apiConfig.apiUrl,
|
|
4552
|
-
apiConfig.apiKey,
|
|
4553
|
-
credentialInfo.keyType,
|
|
4554
|
-
credentialInfo.keySuffix,
|
|
4555
|
-
credentialInfo.keyIndex,
|
|
4556
|
-
keyRateLimitedUntil,
|
|
4557
|
-
).catch(() => {});
|
|
4558
|
-
}
|
|
4559
|
-
if (outcome.kind === "model") {
|
|
4560
|
-
const resetsAtIso = new Date(outcome.resetsAtSec * 1000).toISOString();
|
|
4561
|
-
const blockKey = `${credentialInfo.keyType}:${credentialInfo.keyIndex}:${outcome.window}`;
|
|
4562
|
-
state.modelWindowBlocks.set(blockKey, outcome.resetsAtSec * 1000);
|
|
4563
|
-
console.log(
|
|
4564
|
-
`[credential] ${outcome.model} weekly window exhausted (${outcome.window}) on key #${credentialInfo.keyIndex} until ${resetsAtIso}`,
|
|
4565
|
-
);
|
|
4566
|
-
}
|
|
4567
|
-
|
|
4568
|
-
const finalWindows = buildFinalRateLimitWindows(
|
|
4569
|
-
result.rateLimitWindows,
|
|
4570
|
-
outcome,
|
|
4571
|
-
new Date().toISOString(),
|
|
4572
|
-
);
|
|
4573
|
-
if (finalWindows) {
|
|
4574
|
-
const report = reportKeyRateLimitWindows(
|
|
4575
|
-
apiConfig.apiUrl,
|
|
4576
|
-
apiConfig.apiKey,
|
|
4577
|
-
credentialInfo.keyType,
|
|
4578
|
-
credentialInfo.keySuffix,
|
|
4579
|
-
credentialInfo.keyIndex,
|
|
4580
|
-
finalWindows,
|
|
4581
|
-
outcome.kind !== "model",
|
|
4582
|
-
).catch((err) => {
|
|
4583
|
-
console.warn(
|
|
4584
|
-
`[credential] Failed to report rate-limit windows: ${err instanceof Error ? err.message : String(err)}`,
|
|
4585
|
-
);
|
|
4586
|
-
});
|
|
4587
|
-
// A model rejection gates admission on other workers: land it before
|
|
4588
|
-
// the task finishes. Plain telemetry stays fire-and-forget.
|
|
4589
|
-
if (outcome.kind === "model") await report;
|
|
4590
|
-
}
|
|
4735
|
+
});
|
|
4591
4736
|
}
|
|
4592
4737
|
let bridgeDiagnostics: Awaited<ReturnType<typeof getBridgeFailureDiagnostics>> | undefined;
|
|
4593
4738
|
if (result.exitCode !== 0 && harnessProvider === "claude" && workingDir) {
|
|
@@ -4603,19 +4748,34 @@ async function checkCompletedProcesses(
|
|
|
4603
4748
|
bridgeDiagnostics?.paneTail != null
|
|
4604
4749
|
? `Claude bridge final tmux pane tail (${bridgeDiagnostics.artifactPath}):\n${bridgeDiagnostics.paneTail}`
|
|
4605
4750
|
: undefined;
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4751
|
+
// Reports that gate admission on other workers (a seat mismatch, a
|
|
4752
|
+
// model window rejection) land before the task finishes.
|
|
4753
|
+
await reportCredentialOutcomeThenFinish(
|
|
4754
|
+
{
|
|
4755
|
+
apiUrl: apiConfig.apiUrl,
|
|
4756
|
+
apiKey: apiConfig.apiKey,
|
|
4757
|
+
credentialInfo,
|
|
4758
|
+
result,
|
|
4759
|
+
failureReason,
|
|
4760
|
+
model,
|
|
4761
|
+
codexCreditsExhaustedCooldownMs: state.codexCreditsExhaustedCooldownMs,
|
|
4762
|
+
modelWindowBlocks: state.modelWindowBlocks,
|
|
4763
|
+
},
|
|
4764
|
+
() =>
|
|
4765
|
+
ensureTaskFinished(
|
|
4766
|
+
apiConfig,
|
|
4767
|
+
role,
|
|
4768
|
+
taskId,
|
|
4769
|
+
result.exitCode,
|
|
4770
|
+
failureReason,
|
|
4771
|
+
// Runner-buffered last assistant text is a harness-agnostic fallback
|
|
4772
|
+
// for adapters that never populate `ProviderResult.output` (Codex
|
|
4773
|
+
// today, any future adapter). Empty buffer -> `undefined`, byte
|
|
4774
|
+
// identical to pre-fix behavior.
|
|
4775
|
+
resolveProviderOutput(result, assistantText),
|
|
4776
|
+
harnessProvider,
|
|
4777
|
+
bridgeFailureDiagnostics,
|
|
4778
|
+
),
|
|
4619
4779
|
);
|
|
4620
4780
|
|
|
4621
4781
|
telemetry.taskEvent("session_completed", {
|
|
@@ -4646,15 +4806,6 @@ async function checkCompletedProcesses(
|
|
|
4646
4806
|
}
|
|
4647
4807
|
state.tasksProcessed += 1;
|
|
4648
4808
|
|
|
4649
|
-
if (result.exitCode === 0 && credentialInfo) {
|
|
4650
|
-
reportKeyClearRateLimit(
|
|
4651
|
-
apiConfig.apiUrl,
|
|
4652
|
-
apiConfig.apiKey,
|
|
4653
|
-
credentialInfo.keyType,
|
|
4654
|
-
credentialInfo.keySuffix,
|
|
4655
|
-
).catch(() => {});
|
|
4656
|
-
}
|
|
4657
|
-
|
|
4658
4809
|
ensure({
|
|
4659
4810
|
id: "worker_process_finished",
|
|
4660
4811
|
flow: "task",
|
|
@@ -5271,18 +5422,22 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5271
5422
|
}
|
|
5272
5423
|
};
|
|
5273
5424
|
try {
|
|
5274
|
-
const reg = await
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5425
|
+
const reg = await registerAgentWithRetry(
|
|
5426
|
+
() =>
|
|
5427
|
+
registerAgent({
|
|
5428
|
+
apiUrl,
|
|
5429
|
+
apiKey,
|
|
5430
|
+
agentId,
|
|
5431
|
+
name: agentName,
|
|
5432
|
+
role,
|
|
5433
|
+
isLead,
|
|
5434
|
+
capabilities,
|
|
5435
|
+
maxTasks: maxConcurrent,
|
|
5436
|
+
harnessProvider: bootProvider,
|
|
5437
|
+
runtimeInstanceId,
|
|
5438
|
+
}),
|
|
5439
|
+
{ label: role },
|
|
5440
|
+
);
|
|
5286
5441
|
lastServerCapsRefreshAt = Date.now();
|
|
5287
5442
|
// Rebuilds the prompt immediately: the initial build above ran before
|
|
5288
5443
|
// registration (serverCapabilities unknown), and the later identity
|
|
@@ -5911,6 +6066,8 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
5911
6066
|
taskId: task.id,
|
|
5912
6067
|
model: (task as { model?: string }).model,
|
|
5913
6068
|
modelTier: (task as { modelTier?: string }).modelTier,
|
|
6069
|
+
resolvedModel: (task as { resolvedModel?: string }).resolvedModel,
|
|
6070
|
+
modelSource: (task as { modelSource?: string }).modelSource,
|
|
5914
6071
|
effort: (task as { effort?: ReasoningEffort }).effort,
|
|
5915
6072
|
harnessProvider: state.harnessProvider,
|
|
5916
6073
|
cwd: resumeCwd,
|
|
@@ -6127,6 +6284,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
6127
6284
|
pollInterval: PollIntervalMs,
|
|
6128
6285
|
runtimeInstanceId,
|
|
6129
6286
|
pollTimeout: effectiveTimeout,
|
|
6287
|
+
harnessProvider: state.harnessProvider,
|
|
6130
6288
|
});
|
|
6131
6289
|
|
|
6132
6290
|
if (trigger) {
|
|
@@ -6407,6 +6565,16 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
6407
6565
|
.join("\n\n");
|
|
6408
6566
|
const taskSystemPrompt = taskPromptParts + cwdWarning;
|
|
6409
6567
|
|
|
6568
|
+
// The server refused the task's explicit model for this worker's CLI
|
|
6569
|
+
// version (harness_model_support = unsupported): fail fast, no spawn.
|
|
6570
|
+
const modelUnsupported = (trigger.task as { modelUnsupported?: string } | undefined)
|
|
6571
|
+
?.modelUnsupported;
|
|
6572
|
+
if (trigger.taskId && modelUnsupported) {
|
|
6573
|
+
console.log(`[${role}] ${modelUnsupported}`);
|
|
6574
|
+
await ensureTaskFinished(apiConfig, role, trigger.taskId, 1, modelUnsupported);
|
|
6575
|
+
continue;
|
|
6576
|
+
}
|
|
6577
|
+
|
|
6410
6578
|
iteration++;
|
|
6411
6579
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
6412
6580
|
const taskIdSlice = trigger.taskId?.slice(0, 8) || "notask";
|
|
@@ -6472,6 +6640,9 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
6472
6640
|
taskId: trigger.taskId,
|
|
6473
6641
|
model: taskModel,
|
|
6474
6642
|
modelTier: taskModelTier,
|
|
6643
|
+
resolvedModel: (trigger.task as { resolvedModel?: string } | undefined)
|
|
6644
|
+
?.resolvedModel,
|
|
6645
|
+
modelSource: (trigger.task as { modelSource?: string } | undefined)?.modelSource,
|
|
6475
6646
|
effort: taskEffort,
|
|
6476
6647
|
harnessProvider: state.harnessProvider,
|
|
6477
6648
|
cwd: effectiveCwd,
|