@desplega.ai/agent-swarm 1.159.0 → 1.161.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{acp-adapter-qhch0n2v.js → acp-adapter-xx489vvb.js} +286 -75
- package/dist/{actions-dtsh1mfb.js → actions-ykjkn0m9.js} +32 -30
- package/dist/{anthropic-messages-f2h06k64.js → anthropic-messages-5qx80j9k.js} +99 -14
- package/dist/{app-y1b9srva.js → app-0hdqa4k1.js} +13 -11
- package/dist/{assistant-31hwy5xj.js → assistant-am2g5g8a.js} +40 -32
- package/dist/{azure-openai-responses-0k1mfax5.js → azure-openai-responses-fszbkp0e.js} +3 -3
- package/dist/{boot-reembed-48d2qpkt.js → boot-reembed-gt5gjkt4.js} +14 -12
- package/dist/{boot-reembed-w0bryhkr.js → boot-reembed-xy9t7avg.js} +15 -13
- package/dist/{boot-scrub-logs-t65wbrn7.js → boot-scrub-logs-9x0985y5.js} +12 -10
- package/dist/boot-seeds-trv0d4vg.js +29 -0
- package/dist/{claude-adapter-1t6611ne.js → claude-adapter-jb6e1e54.js} +32 -26
- package/dist/{claude-managed-adapter-werp659j.js → claude-managed-adapter-yxkfxg8j.js} +7 -7
- package/dist/{claude-managed-setup-y6rdgbc1.js → claude-managed-setup-d1q9hv2b.js} +26 -27
- package/dist/{claude-sdk-session-zhkyk8yw.js → claude-sdk-session-zga700s2.js} +11737 -11256
- package/dist/{cli-79aq9cgb.js → cli-0383bp7f.js} +1222 -406
- package/dist/{cli-xgpf00sk.js → cli-0c7ata9h.js} +24 -23
- package/dist/{cli-qjxy52w7.js → cli-121ph74b.js} +2 -2
- package/dist/{cli-20035trh.js → cli-17xpf7cm.js} +14 -7
- package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
- package/dist/{cli-g9df2m37.js → cli-1cz0c18q.js} +249 -200
- package/dist/{cli-fjtp3463.js → cli-1er0rhz8.js} +13 -12
- package/dist/{cli-ca2w7zv7.js → cli-2hhfhfq5.js} +11 -6
- package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
- package/dist/{cli-rykfmgwg.js → cli-2x0e561b.js} +1 -1
- package/dist/{cli-503ya656.js → cli-35pj2yva.js} +20 -150
- package/dist/cli-3qhyh31j.js +166 -0
- package/dist/{cli-cygyqj3b.js → cli-3zc55ctx.js} +8 -6
- package/dist/{cli-96qd5psa.js → cli-58e8yr0d.js} +1 -1
- package/dist/{cli-4aj25szq.js → cli-5nbmpy8w.js} +2 -2
- package/dist/{cli-mg24hkt4.js → cli-5p3x4zna.js} +2 -2
- package/dist/{cli-vwbbaecp.js → cli-7119ja3w.js} +3 -3
- package/dist/{cli-mzkqpxee.js → cli-798vkbks.js} +2 -2
- package/dist/{cli-3gvrr8vj.js → cli-82c1pacn.js} +111 -54
- package/dist/{cli-hgqfttfc.js → cli-89s4ngw3.js} +1 -1
- package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
- package/dist/{cli-b6thtzac.js → cli-8g6mc14k.js} +7 -7
- package/dist/{cli-eg7cdg68.js → cli-9m03pzga.js} +5 -5
- package/dist/cli-9s68w752.js +303 -0
- package/dist/{cli-48527fpw.js → cli-a8c82p2t.js} +16 -15
- package/dist/{cli-5f2hq128.js → cli-ad4qxm6j.js} +12 -11
- package/dist/{cli-e4xnc0qp.js → cli-akfj32vj.js} +33 -7
- package/dist/{cli-ejpygnqz.js → cli-bh7jed3k.js} +212 -22
- package/dist/{cli-0z2v4nhw.js → cli-cat6h73s.js} +1 -1
- package/dist/{cli-e0ndxhtk.js → cli-cfkrztza.js} +190 -13
- package/dist/{cli-kc3dp84d.js → cli-d56tgd45.js} +216 -59
- package/dist/cli-dbmwby6a.js +9 -0
- package/dist/{cli-0n2e4x49.js → cli-ecfxwnyb.js} +15 -2
- package/dist/{cli-gzyh0j0g.js → cli-ee8bc46j.js} +66 -166
- package/dist/{cli-kdnehe0t.js → cli-et8m9xsv.js} +1 -1
- package/dist/cli-f9w1semm.js +413 -0
- package/dist/cli-gt4hxb8p.js +99 -0
- package/dist/{cli-qv4jv8bx.js → cli-hgmnf38m.js} +2 -2
- package/dist/{cli-10ym38qc.js → cli-hn04t9db.js} +3 -3
- package/dist/{cli-qvnnx4ct.js → cli-jpf7e1zq.js} +105 -243
- package/dist/cli-jyy6pm2f.js +333872 -0
- package/dist/{cli-dvjpkkjd.js → cli-kgd3p0bm.js} +7 -7
- package/dist/cli-ma3zvh39.js +10404 -0
- package/dist/{cli-r2ap2czm.js → cli-nexqx4ve.js} +6 -0
- package/dist/{cli-j9z8mfx3.js → cli-nsdxtcbg.js} +37 -20
- package/dist/{cli-wgjx0q33.js → cli-phfg8vy8.js} +392 -53
- package/dist/{cli-rgjprct3.js → cli-ptr8h7kp.js} +19 -1
- package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
- package/dist/{cli-bv0a38v9.js → cli-qwsnmjdd.js} +515 -229
- package/dist/{cli-68bmme5p.js → cli-r6fsxc76.js} +40018 -52654
- package/dist/{cli-rrqmqr1s.js → cli-rtx9dygp.js} +1 -1
- package/dist/{cli-rfezr056.js → cli-sqm3r5ps.js} +83 -15
- package/dist/{cli-zw65mab6.js → cli-t6v2ah3r.js} +67 -13
- package/dist/{cli-vn0qv9cj.js → cli-t845n9xk.js} +28 -14
- package/dist/cli-trc24wk2.js +143 -0
- package/dist/{cli-wd9hz40d.js → cli-tre4bdgq.js} +5 -5
- package/dist/{cli-9yg65c1j.js → cli-tsk3nz8a.js} +29 -1
- package/dist/{cli-phsaj4xq.js → cli-v0pvvhfq.js} +1 -1
- package/dist/{cli-hj65wsts.js → cli-vnnz5ncg.js} +4695 -4915
- package/dist/{cli-cpvsaqsw.js → cli-w0bwte75.js} +8 -5
- package/dist/{cli-z9x0sh1t.js → cli-we0q7t0e.js} +3 -3
- package/dist/{cli-r94z9p1z.js → cli-wgbezhw2.js} +3 -0
- package/dist/{cli-19jenss3.js → cli-xk79303e.js} +51 -17
- package/dist/{cli-31nkw3g3.js → cli-ybgv4kw2.js} +15 -8
- package/dist/{cli-ardpzhjm.js → cli-yrg7c73k.js} +13 -6
- package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
- package/dist/{cli-vhjwh6cz.js → cli-yy6dew39.js} +2 -2
- package/dist/{cli-bgv70kym.js → cli-zb6xbk61.js} +3 -2
- package/dist/{cli-4tvgz99m.js → cli-ze1d3wzv.js} +79 -27
- package/dist/cli.js +33 -32
- package/dist/{cloudflare-workers-ai-system-one-1sg586qv.js → cloudflare-workers-ai-system-one-k6fbxw9d.js} +2 -2
- package/dist/{codex-adapter-jqfqqa21.js → codex-adapter-04v97vep.js} +23 -20
- package/dist/{codex-hook-5eys3dya.js → codex-hook-20me6byw.js} +2 -2
- package/dist/{codex-login-he9vrn90.js → codex-login-cf7mzsgg.js} +48 -3
- package/dist/{codex-session-runner-zd341dsm.js → codex-session-runner-ax69mqq3.js} +21 -20
- package/dist/{commands-vfsysz4s.js → commands-18gy08n1.js} +12 -10
- package/dist/{db-s3znhvbn.js → db-d2pvjpyt.js} +22 -10
- package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
- package/dist/{dispatcher-5xn0c7rf.js → dispatcher-8wbwyzjg.js} +31 -29
- package/dist/{dsh-adapter-894mgfvs.js → dsh-adapter-ysqk9snv.js} +9 -4
- package/dist/{e2b-ez07znam.js → e2b-esmt1r16.js} +3 -1
- package/dist/{execute-71ysgv35.js → execute-cmagrbrz.js} +235 -52
- package/dist/{google-generative-ai-1nfcdphp.js → google-generative-ai-k6n5nbpp.js} +3 -3
- package/dist/{google-vertex-1tqcd7b1.js → google-vertex-44xxtcvp.js} +3 -3
- package/dist/{handlers-5w4jwycr.js → handlers-6b69m5kp.js} +34 -32
- package/dist/{hook-z0hbxj85.js → hook-k3mydf2n.js} +16 -14
- package/dist/{hook-853bxrr6.js → hook-srnkt0hb.js} +16 -14
- package/dist/{http-akc3wy3m.js → http-hrf80ca1.js} +836 -189
- package/dist/{index-ttpbhnjg.js → index-1asbaj62.js} +32 -30
- package/dist/{index-cd151qkq.js → index-45evq4ee.js} +31 -29
- package/dist/{index-k661dzzr.js → index-9rxdvj6w.js} +32 -30
- package/dist/index-k4nj18qs.js +31 -0
- package/dist/{index-5sz16ksh.js → index-xmevk2b9.js} +89 -61
- package/dist/{keepalive-8p9rpvz5.js → keepalive-sfdz6ksp.js} +14 -12
- package/dist/{lead-jp69z5h3.js → lead-ej91e9hw.js} +52 -50
- package/dist/{llama-cpp-classify-t2tccams.js → llama-cpp-classify-tgj35k8d.js} +1 -1
- package/dist/{maintenance-fwx4ev0k.js → maintenance-80dnd7ke.js} +15 -13
- package/dist/{mistral-conversations-bhvwqcnk.js → mistral-conversations-pc3ntnxt.js} +1 -1
- package/dist/node-f0ykebbv.js +2107 -0
- package/dist/node-wyamey5r.js +19 -0
- package/dist/{oauth-refresh-sweep-cwcq1ctx.js → oauth-refresh-sweep-m1etk2mx.js} +13 -11
- package/dist/{onboard-2b4q0t84.js → onboard-0q8sdfqc.js} +2 -2
- package/dist/{openai-codex-responses-nekthgks.js → openai-codex-responses-n7n683p2.js} +2 -2
- package/dist/{openai-completions-hxtzwj0s.js → openai-completions-jpaj5g2b.js} +2 -2
- package/dist/{openai-responses-w4r118w7.js → openai-responses-9a3nme9j.js} +3 -3
- package/dist/{opencode-adapter-zz7xvjj6.js → opencode-adapter-4wcgmvgf.js} +13 -11
- package/dist/{openrouter-images-b6sqqjgn.js → openrouter-images-8yx3487g.js} +1 -1
- package/dist/{otel-impl-g8rs4vwr.js → otel-impl-hnqm9mxq.js} +2 -2
- package/dist/pi-logo-animation-e9a0t68z.js +1003 -0
- package/dist/{pi-mono-adapter-n0me28wt.js → pi-mono-adapter-d6sqm9wr.js} +301 -78
- package/dist/{pricing-refresh-0v77385v.js → pricing-refresh-y60z64pm.js} +14 -13
- package/dist/quickjs-r1pq2107.wasm +0 -0
- package/dist/{rbac-roles-krjyazbj.js → rbac-roles-8pa0754b.js} +13 -11
- package/dist/{render-v2-3wjsp9aw.js → render-v2-418s1vj7.js} +13 -11
- package/dist/{runtime-ktjysacx.js → runtime-3pknc168.js} +5 -4
- package/dist/{setup-yeqryke6.js → setup-yghdkj4x.js} +2 -2
- package/dist/{typesafe-system-one-96960jxp.js → typesafe-system-one-2ef30pec.js} +2 -2
- package/dist/{virtual-modules-dzdeq1sf.js → virtual-modules-jcceevt5.js} +8 -6
- package/dist/{work-objects-3pakpkw0.js → work-objects-j1sz20v9.js} +34 -32
- package/dist/{worker-85testgj.js → worker-d4gcvkjt.js} +52 -50
- package/dist/{x-n3e0v3xa.js → x-f1gt1pz3.js} +2 -2
- package/openapi.json +587 -19
- package/package.json +16 -15
- package/src/azure-devops/api.ts +121 -0
- package/src/azure-devops/auth.ts +78 -0
- package/src/azure-devops/handlers.ts +413 -0
- package/src/azure-devops/index.ts +27 -0
- package/src/azure-devops/templates.ts +108 -0
- package/src/azure-devops/types.ts +90 -0
- package/src/be/db/api-keys.ts +70 -0
- package/src/be/db/tasks/read.ts +1 -1
- package/src/be/db/tasks/write.ts +16 -0
- package/src/be/db-client.ts +11 -2
- package/src/be/db-retention.ts +95 -32
- package/src/be/db.ts +187 -24
- package/src/be/memory/constants.ts +16 -0
- package/src/be/memory/graph-expansion.ts +8 -1
- package/src/be/memory/index-content.ts +20 -1
- package/src/be/memory/key-guard.ts +93 -0
- package/src/be/memory/key-paths.ts +103 -0
- package/src/be/memory/providers/sqlite-store.ts +203 -60
- package/src/be/memory/raters/llm-summarizer.ts +10 -4
- package/src/be/memory/raters/llm.ts +15 -5
- package/src/be/memory/raters/store.ts +6 -3
- package/src/be/memory/raters/types.ts +11 -0
- package/src/be/memory/reranker.ts +38 -7
- package/src/be/memory/types.ts +12 -1
- 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/migrations/190_memory_rating_model.sql +7 -0
- package/src/be/migrations/191_context_versions_previous_index.sql +8 -0
- package/src/be/model-tier-keys.ts +16 -1
- package/src/be/model-tier-resolution.ts +63 -18
- package/src/be/model-validation.ts +86 -10
- package/src/be/pricing-normalize.ts +4 -2
- package/src/be/scripts/typecheck.ts +4 -3
- package/src/be/seed/runner.ts +18 -12
- package/src/be/seed/types.ts +1 -0
- package/src/be/seed-pricing.ts +16 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +26 -26
- package/src/be/swarm-config-guard.ts +13 -1
- package/src/commands/claude-managed-setup.ts +33 -31
- package/src/commands/codex-login.ts +67 -0
- package/src/commands/credential-outcome-report.ts +191 -0
- package/src/commands/provider-credentials.ts +28 -15
- package/src/commands/rate-limit-outcome.ts +34 -4
- package/src/commands/runner.ts +479 -228
- package/src/commands/seat-mismatch-report.ts +46 -0
- package/src/e2b/env.ts +2 -0
- package/src/extensions/apply-task-create.ts +27 -1
- package/src/extensions/catalog.generated.json +17 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/github/handlers.ts +10 -74
- package/src/github/reactions.ts +119 -138
- package/src/github/task-reactions.ts +34 -11
- package/src/heartbeat/heartbeat.ts +15 -2
- package/src/hooks/hook.ts +1 -1
- package/src/http/agents.ts +15 -2
- package/src/http/api-keys.ts +140 -2
- package/src/http/codex-oauth-keep-warm.ts +3 -5
- package/src/http/core.ts +12 -0
- package/src/http/extensions.ts +51 -27
- package/src/http/index.ts +4 -0
- package/src/http/mcp-user.ts +8 -13
- package/src/http/mcp.ts +19 -12
- package/src/http/memory.ts +91 -18
- package/src/http/poll.ts +9 -1
- package/src/http/schedules.ts +17 -2
- package/src/http/script-runs.ts +12 -0
- package/src/http/session-data.ts +6 -4
- package/src/http/stats.ts +1 -0
- package/src/http/status.ts +15 -1
- package/src/http/tasks.ts +80 -8
- package/src/http/users.ts +1 -1
- package/src/http/webhooks.ts +120 -2
- package/src/http/workflows.ts +11 -0
- 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 +22 -1
- package/src/providers/acp-adapter.ts +1 -0
- package/src/providers/claude-adapter.ts +98 -21
- package/src/providers/claude-managed-adapter.ts +30 -2
- package/src/providers/claude-sdk-session.ts +3 -1
- package/src/providers/codex-adapter.ts +11 -11
- package/src/providers/codex-skill-resolver.ts +6 -0
- package/src/providers/devin-adapter.ts +1 -0
- package/src/providers/dsh-adapter.ts +205 -7
- package/src/providers/harness-version.ts +83 -7
- package/src/providers/opencode-adapter.ts +77 -4
- 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 +387 -83
- package/src/providers/pi-mono-extension.ts +17 -2
- package/src/providers/pricing-sources.md +5 -1
- package/src/providers/reasoning-effort.ts +10 -2
- package/src/providers/types.ts +9 -1
- package/src/rbac/legacy-policy.ts +20 -0
- package/src/rbac/permissions.ts +15 -0
- package/src/scripts-runtime/types/stdlib.d.ts +13 -5
- package/src/scripts-runtime/types/swarm-extension.d.ts +4 -2
- package/src/scripts-runtime/types/swarm-sdk.d.ts +13 -5
- package/src/slack/assistant.ts +13 -0
- package/src/slack/render-v2.ts +87 -37
- package/src/slack/session-status.ts +541 -0
- package/src/tasks/context-key.ts +38 -1
- package/src/tasks/sibling-awareness.ts +3 -2
- package/src/telemetry.ts +5 -4
- package/src/templates.d.ts +6 -0
- 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/azure-devops-auth.test.ts +100 -0
- package/src/tests/azure-devops-handlers.test.ts +324 -0
- package/src/tests/azure-devops-webhook-malformed.test.ts +96 -0
- package/src/tests/base-prompt.test.ts +40 -2
- package/src/tests/claude-adapter.test.ts +58 -0
- package/src/tests/claude-default-route.test.ts +260 -0
- package/src/tests/claude-managed-adapter.test.ts +47 -0
- package/src/tests/claude-managed-setup.test.ts +48 -0
- package/src/tests/claude-prompt-body-once.test.ts +117 -0
- package/src/tests/claude-routes-e2e.test.ts +316 -0
- package/src/tests/codex-auth-failure.test.ts +52 -0
- package/src/tests/codex-login.test.ts +116 -0
- package/src/tests/context-versions-retention.test.ts +314 -0
- package/src/tests/core-auth.test.ts +7 -0
- 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-retention.test.ts +14 -14
- package/src/tests/db-task-read-contract.test.ts +6 -0
- package/src/tests/db-task-write-contract.test.ts +533 -1
- 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 +134 -2
- package/src/tests/dsh-usage.test.ts +153 -0
- package/src/tests/explicit-model-validation.test.ts +253 -2
- package/src/tests/extensions-catalog.test.ts +1 -0
- package/src/tests/extensions-example-deploy-awareness.test.ts +301 -0
- package/src/tests/extensions-http.test.ts +137 -10
- package/src/tests/extensions-mcp-tools.test.ts +28 -0
- package/src/tests/extensions-pre-task.test.ts +73 -0
- package/src/tests/fetch-resolved-env.test.ts +70 -0
- package/src/tests/fixtures/azure-devops/pull-request-commented.json +129 -0
- package/src/tests/fixtures/azure-devops/pull-request-created.json +88 -0
- package/src/tests/fixtures/fake-claude-routes.ts +229 -0
- package/src/tests/github-handlers-reactions.test.ts +486 -0
- package/src/tests/github-reactions.test.ts +280 -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-cli-version.test.ts +62 -0
- package/src/tests/harness-model-guard.test.ts +123 -0
- package/src/tests/harness-version.test.ts +70 -3
- package/src/tests/http-api-integration.test.ts +21 -0
- package/src/tests/http-task-write-ownership.test.ts +195 -0
- package/src/tests/internal-ai/complete-structured.test.ts +94 -0
- package/src/tests/internal-ai/credentials.test.ts +22 -0
- package/src/tests/internal-ai/models.test.ts +36 -2
- package/src/tests/internal-ai/schema-parity.test.ts +25 -1
- package/src/tests/internal-ai/summarize-session.test.ts +23 -7
- package/src/tests/mcp-user-route.test.ts +133 -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/memory-key-paths.test.ts +1055 -0
- package/src/tests/memory-rate-endpoint.test.ts +66 -0
- package/src/tests/memory-rater-llm-summarizer.test.ts +2 -1
- package/src/tests/memory-rater-llm.test.ts +73 -0
- package/src/tests/memory-rater-store.test.ts +31 -0
- package/src/tests/memory-reranker.test.ts +40 -0
- package/src/tests/model-rate-limit-windows.test.ts +19 -0
- package/src/tests/model-tier-resolution.test.ts +92 -0
- package/src/tests/opencode-adapter.test.ts +214 -2
- package/src/tests/opencode-plugin.test.ts +4 -0
- package/src/tests/pi-codemode.test.ts +324 -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 +9 -0
- package/src/tests/prompt-template-session.test.ts +5 -3
- package/src/tests/provider-registration.test.ts +0 -2
- package/src/tests/providers/pi-cost.test.ts +190 -4
- 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 +41 -2
- 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/runner-slot-reconcile.test.ts +199 -0
- package/src/tests/script-connections.test.ts +8 -0
- package/src/tests/seat-mismatch-report.test.ts +85 -0
- package/src/tests/seed-scripts.test.ts +49 -0
- package/src/tests/seed.test.ts +25 -0
- package/src/tests/session-costs-recompute-all-providers.test.ts +23 -0
- package/src/tests/slack-render-v2.test.ts +96 -0
- package/src/tests/slack-session-status.test.ts +626 -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-citations.test.ts +3 -2
- package/src/tests/task-reactions.test.ts +29 -6
- package/src/tests/vcs-azure-devops.test.ts +73 -0
- package/src/tests/webhooks-task-blocked.test.ts +23 -0
- package/src/tests/workflow-agent-task.test.ts +30 -0
- package/src/tests/workflow-llm.test.ts +14 -0
- package/src/tests/workflow-triggers-v2.test.ts +320 -0
- package/src/tools/context-diff.ts +20 -0
- package/src/tools/extension-install.ts +27 -16
- package/src/tools/memory-edit.ts +47 -3
- package/src/tools/memory-search.ts +13 -1
- package/src/tools/memory-store.ts +55 -3
- package/src/tools/schedules/create-schedule.ts +1 -1
- package/src/tools/schedules/patch-schedule.ts +16 -3
- package/src/tools/schedules/update-schedule.ts +16 -3
- package/src/tools/send-task.ts +10 -7
- package/src/tools/store-progress.ts +49 -4
- package/src/tools/task-action.ts +2 -1
- package/src/tools/workflows/create-workflow.ts +8 -2
- package/src/tools/workflows/update-workflow.ts +8 -2
- package/src/types.ts +54 -7
- package/src/utils/codex-auth-failure.ts +34 -0
- package/src/utils/credentials.test.ts +31 -1
- package/src/utils/credentials.ts +92 -39
- package/src/utils/dsh-usage.ts +53 -0
- package/src/utils/error-tracker.ts +80 -0
- package/src/utils/harness-cli-version.ts +6 -4
- package/src/utils/internal-ai/complete-structured.ts +26 -3
- package/src/utils/internal-ai/credentials.ts +23 -9
- package/src/utils/internal-ai/index.ts +8 -1
- package/src/utils/internal-ai/models.ts +34 -8
- package/src/utils/internal-ai/summarize-session.ts +22 -8
- package/src/utils/model-rate-limit-windows.ts +12 -0
- package/src/utils/runtime-model-catalog.ts +15 -0
- package/src/utils/secret-scrubber.ts +8 -0
- package/src/utils/spawn-model-guard.ts +43 -0
- package/src/utils/subscription-plans.ts +22 -0
- package/src/vcs/azure-devops.ts +80 -0
- package/src/vcs/index.ts +5 -1
- package/src/vcs/types.ts +2 -2
- package/src/workflows/executors/agent-task.ts +7 -6
- package/src/workflows/model-validation.ts +45 -0
- package/src/workflows/patch-definition.ts +5 -0
- package/src/workflows/triggers.ts +85 -0
- package/templates/community/open-prompt-showreel/PLAYBOOK.md +336 -0
- package/templates/community/open-prompt-showreel/README.md +33 -0
- package/templates/community/open-prompt-showreel/example/tla-races/facts.ts +145 -0
- package/templates/community/open-prompt-showreel/example/tla-races/facts.v3.json +140 -0
- package/templates/community/open-prompt-showreel/example/tla-races/music.mist-city.json +8 -0
- package/templates/community/open-prompt-showreel/example/tla-races/reel.html +805 -0
- package/templates/community/open-prompt-showreel/example/tla-races/smoke.sh +48 -0
- package/templates/community/open-prompt-showreel/lead-prompt.md +89 -0
- package/templates/community/open-prompt-showreel/setup.sh +167 -0
- package/templates/community/open-prompt-showreel/skills/motion-design-replication/SKILL.md +85 -0
- package/templates/community/open-prompt-showreel/skills/motion-design-video-analysis/SKILL.md +115 -0
- package/templates/community/open-prompt-showreel/skills/open-prompt-showreel/SKILL.md +147 -0
- package/templates/community/open-prompt-showreel/skills/video-generation/SKILL.md +195 -0
- package/templates/community/open-prompt-showreel/tools/fetch-music.sh +65 -0
- package/templates/community/open-prompt-showreel/tools/music-analyze.py +69 -0
- package/templates/community/open-prompt-showreel/tools/music-current.sh +34 -0
- package/templates/community/open-prompt-showreel/tools/music-cut.sh +36 -0
- package/templates/community/open-prompt-showreel/tools/music-refine.py +39 -0
- package/templates/community/open-prompt-showreel/tools/render.mjs +157 -0
- package/templates/community/open-prompt-showreel/tools/sheet.sh +44 -0
- package/templates/community/open-prompt-showreel/tools/web-compress.sh +17 -0
- package/templates/community/open-prompt-showreel/tools/x-reencode.sh +21 -0
- package/templates/extensions/README.md +1 -0
- package/templates/extensions/deploy-awareness/README.md +28 -0
- package/templates/extensions/deploy-awareness/hooks.ts +152 -0
- package/templates/extensions/deploy-awareness/manifest.json +8 -0
- package/templates/skills/memory/config.json +2 -2
- package/templates/skills/memory/content.md +59 -5
- package/templates/skills/swarm-extensions/config.json +1 -1
- package/templates/skills/swarm-extensions/content.md +28 -5
- package/templates/skills/workflow-iterate/content.md +1 -0
- package/dist/boot-seeds-h7c32hvm.js +0 -27
- package/dist/cli-2djtr51b.js +0 -48
- package/dist/cli-7zttzetj.js +0 -324
- package/dist/cli-j490egb5.js +0 -5632
- package/dist/cli-m4excttz.js +0 -333481
- package/dist/index-bjmjh9h4.js +0 -29
package/src/utils/credentials.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { deriveDefaultRoute, routeCredentialStatus } from "@desplega/model-routing";
|
|
2
3
|
import { type ModelFamily, modelFamilyOf, windowForModelFamily } from "./model-rate-limit-windows";
|
|
3
4
|
|
|
4
5
|
/** Env vars that may contain comma-separated credential pools */
|
|
@@ -113,8 +114,12 @@ export interface CredentialSelection {
|
|
|
113
114
|
modelBlockedIndices?: number[];
|
|
114
115
|
/** ISO of the earliest reset among modelBlockedIndices, or null/undefined when none. */
|
|
115
116
|
earliestModelResetAt?: string | null;
|
|
117
|
+
/** Indices excluded because the key's subscription plan cannot run the requested model. */
|
|
118
|
+
seatBlockedIndices?: number[];
|
|
116
119
|
/** Subscription plan id detected on the credential (`SUBSCRIPTION_PLANS`), reported with its usage. */
|
|
117
120
|
plan?: string | null;
|
|
121
|
+
/** `authFailureFence` from `GET /api/keys/available`, read before the task (Codex pool only). */
|
|
122
|
+
authFailureFence?: number;
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
const MODEL_LABELS: Record<ModelFamily, string> = {
|
|
@@ -126,33 +131,49 @@ const MODEL_LABELS: Record<ModelFamily, string> = {
|
|
|
126
131
|
|
|
127
132
|
/**
|
|
128
133
|
* Thrown by `resolveCredentialPools` at task admission (`enforceModelCapacity`)
|
|
129
|
-
* when
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* `
|
|
133
|
-
*
|
|
134
|
+
* when no key for a pool can run the requested model: every key is key-wide
|
|
135
|
+
* rate-limited, blocked by the model's weekly window, or on a subscription
|
|
136
|
+
* seat that cannot run the model (`seatBlockedCount`). A window block throws
|
|
137
|
+
* only when `MODEL_WINDOW_EXHAUSTED_POLICY` is `fail` (the default); a seat
|
|
138
|
+
* block never resets, so it throws under every policy. The caller must not
|
|
139
|
+
* spawn the CLI on this error — see `spawnProviderProcess` in
|
|
140
|
+
* `src/commands/runner.ts`. Taskless configuration loads never throw it.
|
|
134
141
|
*/
|
|
135
142
|
export class ModelWindowExhaustedError extends Error {
|
|
136
143
|
readonly model: ModelFamily;
|
|
137
144
|
readonly window: string;
|
|
138
145
|
readonly earliestResetAt: string | null;
|
|
139
146
|
readonly keyType: string;
|
|
147
|
+
readonly seatBlockedCount: number;
|
|
148
|
+
readonly modelBlockedCount: number;
|
|
140
149
|
|
|
141
150
|
constructor(opts: {
|
|
142
151
|
model: ModelFamily;
|
|
143
152
|
window: string;
|
|
144
153
|
earliestResetAt: string | null;
|
|
145
154
|
keyType: string;
|
|
155
|
+
seatBlockedCount?: number;
|
|
156
|
+
modelBlockedCount?: number;
|
|
146
157
|
}) {
|
|
147
158
|
const modelLabel = MODEL_LABELS[opts.model];
|
|
159
|
+
const seatBlockedCount = opts.seatBlockedCount ?? 0;
|
|
160
|
+
const modelBlockedCount = opts.modelBlockedCount ?? 0;
|
|
161
|
+
const windowClause =
|
|
162
|
+
modelBlockedCount > 0 && opts.earliestResetAt
|
|
163
|
+
? `${modelBlockedCount} keys have the ${modelLabel} window exhausted until ${opts.earliestResetAt}`
|
|
164
|
+
: `${modelBlockedCount} keys have the ${modelLabel} window exhausted`;
|
|
148
165
|
super(
|
|
149
|
-
|
|
166
|
+
seatBlockedCount > 0
|
|
167
|
+
? `No ${opts.keyType} key can run ${modelLabel}: ${seatBlockedCount} keys are on a seat without ${modelLabel}, ${windowClause}. Re-dispatch with another model or modelTier.`
|
|
168
|
+
: `No ${opts.keyType} key has ${modelLabel} capacity until ${opts.earliestResetAt ?? "unknown"}. Re-dispatch with another model or modelTier.`,
|
|
150
169
|
);
|
|
151
170
|
this.name = "ModelWindowExhaustedError";
|
|
152
171
|
this.model = opts.model;
|
|
153
172
|
this.window = opts.window;
|
|
154
173
|
this.earliestResetAt = opts.earliestResetAt;
|
|
155
174
|
this.keyType = opts.keyType;
|
|
175
|
+
this.seatBlockedCount = seatBlockedCount;
|
|
176
|
+
this.modelBlockedCount = modelBlockedCount;
|
|
156
177
|
}
|
|
157
178
|
}
|
|
158
179
|
|
|
@@ -173,6 +194,15 @@ function isJsonObject(value: string): boolean {
|
|
|
173
194
|
* Falls back to random selection from all credentials if no available indices match.
|
|
174
195
|
* A JSON object value (the CODEX_OAUTH blob) is always one credential.
|
|
175
196
|
*/
|
|
197
|
+
function splitCredentialPool(value: string): string[] {
|
|
198
|
+
return isJsonObject(value)
|
|
199
|
+
? [value.trim()]
|
|
200
|
+
: value
|
|
201
|
+
.split(",")
|
|
202
|
+
.map((s) => s.trim())
|
|
203
|
+
.filter(Boolean);
|
|
204
|
+
}
|
|
205
|
+
|
|
176
206
|
export function selectCredential(
|
|
177
207
|
value: string,
|
|
178
208
|
availableIndices?: number[],
|
|
@@ -183,12 +213,7 @@ export function selectCredential(
|
|
|
183
213
|
// handed out fragments such as `"accountId":"..."}` as the selected credential
|
|
184
214
|
// and stamped `965"}` as the key suffix on task records. Codex pools live in
|
|
185
215
|
// config-store slots (codex_oauth_<n>), resolved by the runner instead.
|
|
186
|
-
const credentials =
|
|
187
|
-
? [value.trim()]
|
|
188
|
-
: value
|
|
189
|
-
.split(",")
|
|
190
|
-
.map((s) => s.trim())
|
|
191
|
-
.filter(Boolean);
|
|
216
|
+
const credentials = splitCredentialPool(value);
|
|
192
217
|
if (credentials.length <= 1) {
|
|
193
218
|
const selected = value.trim();
|
|
194
219
|
const isRateLimitFallback = availableIndices !== undefined && availableIndices.length === 0;
|
|
@@ -247,17 +272,27 @@ export function selectRandomCredential(value: string): {
|
|
|
247
272
|
return { selected: result.selected, index: result.index, total: result.total };
|
|
248
273
|
}
|
|
249
274
|
|
|
275
|
+
export const CLAUDE_CREDENTIALS_HINT =
|
|
276
|
+
"Set CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY, or route Claude Code through a gateway (ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY), Microsoft Foundry (CLAUDE_CODE_USE_FOUNDRY), Amazon Bedrock (CLAUDE_CODE_USE_BEDROCK), or Google Vertex AI (CLAUDE_CODE_USE_VERTEX).";
|
|
277
|
+
|
|
278
|
+
const CLAUDE_CREDENTIAL_TYPE_BY_PROVIDER: Record<string, string> = {
|
|
279
|
+
"claude-subscription": "oauth",
|
|
280
|
+
anthropic: "api_key",
|
|
281
|
+
"anthropic-gateway": "gateway",
|
|
282
|
+
};
|
|
283
|
+
|
|
250
284
|
/**
|
|
251
|
-
* Validate that
|
|
252
|
-
*
|
|
253
|
-
* Returns the credential type found,
|
|
285
|
+
* Validate that the claude harness has a usable default route (see
|
|
286
|
+
* `deriveDefaultRoute` in @desplega/model-routing for the precedence).
|
|
287
|
+
* Returns the credential type found ("oauth", "api_key", "gateway", "foundry",
|
|
288
|
+
* "bedrock", "vertex"), or throws with what is missing.
|
|
254
289
|
*/
|
|
255
|
-
export function validateClaudeCredentials(
|
|
256
|
-
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
if (
|
|
260
|
-
|
|
290
|
+
export function validateClaudeCredentials(env: Record<string, string | undefined>): string {
|
|
291
|
+
const route = deriveDefaultRoute("claude", env);
|
|
292
|
+
if (!route) throw new Error(`No Claude credentials found. ${CLAUDE_CREDENTIALS_HINT}`);
|
|
293
|
+
const status = routeCredentialStatus(route, env);
|
|
294
|
+
if (!status.ready) throw new Error(`No Claude credentials found. ${status.hint}`);
|
|
295
|
+
return CLAUDE_CREDENTIAL_TYPE_BY_PROVIDER[route.provider] ?? route.provider;
|
|
261
296
|
}
|
|
262
297
|
|
|
263
298
|
/**
|
|
@@ -283,6 +318,8 @@ export interface AvailabilityInfo {
|
|
|
283
318
|
availableIndices: number[];
|
|
284
319
|
modelBlockedIndices?: number[];
|
|
285
320
|
earliestModelResetAt?: string | null;
|
|
321
|
+
/** Indices excluded because the key's subscription plan cannot run the model. */
|
|
322
|
+
seatBlockedIndices?: number[];
|
|
286
323
|
}
|
|
287
324
|
|
|
288
325
|
/**
|
|
@@ -315,11 +352,13 @@ async function fetchAvailableIndices(
|
|
|
315
352
|
availableIndices: number[];
|
|
316
353
|
modelBlockedIndices?: number[];
|
|
317
354
|
earliestModelResetAt?: string | null;
|
|
355
|
+
seatBlockedIndices?: number[];
|
|
318
356
|
};
|
|
319
357
|
availableIndicesMap[envVar] = {
|
|
320
358
|
availableIndices: data.availableIndices,
|
|
321
359
|
modelBlockedIndices: data.modelBlockedIndices,
|
|
322
360
|
earliestModelResetAt: data.earliestModelResetAt,
|
|
361
|
+
seatBlockedIndices: data.seatBlockedIndices,
|
|
323
362
|
};
|
|
324
363
|
if (data.availableIndices.length < totalKeys) {
|
|
325
364
|
console.log(
|
|
@@ -374,7 +413,9 @@ export async function resolveCredentialPools(
|
|
|
374
413
|
localBlocks?: Map<string, number>;
|
|
375
414
|
/**
|
|
376
415
|
* Set only at task admission (`spawnProviderProcess`). When true, an
|
|
377
|
-
* exhausted model window
|
|
416
|
+
* exhausted model window, or a pool where every remaining key is on a
|
|
417
|
+
* seat that cannot run the model, fails fast with
|
|
418
|
+
* `ModelWindowExhaustedError`.
|
|
378
419
|
* Taskless configuration loads (worker boot, credential recovery,
|
|
379
420
|
* periodic reconciliation) leave it unset: they still pick a key, so an
|
|
380
421
|
* exhausted default model never blocks boot or config refresh, and the
|
|
@@ -413,32 +454,43 @@ export async function resolveCredentialPools(
|
|
|
413
454
|
modelBlockedCount += beforeCount - available.length;
|
|
414
455
|
}
|
|
415
456
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
) {
|
|
457
|
+
const seatBlockedIndices = info?.seatBlockedIndices ?? [];
|
|
458
|
+
const seatBlockedCount = seatBlockedIndices.length;
|
|
459
|
+
let seatFallbackIndices: number[] | undefined;
|
|
460
|
+
|
|
461
|
+
// Every key is key-wide rate-limited, blocked by this model's weekly
|
|
462
|
+
// window, or on a seat that cannot run the model, and at least one is
|
|
463
|
+
// blocked specifically for the model (not just legacy key-wide rate
|
|
464
|
+
// limiting) — the picker can't make progress for this model on this
|
|
465
|
+
// pool. Default policy fails fast instead of looping the worker
|
|
466
|
+
// through the same exhausted key every few minutes. A seat block is a
|
|
467
|
+
// plan fact with no window and no reset, so the fallback pick excludes
|
|
468
|
+
// seat-blocked keys: a pick from them is a guaranteed failure. It fails
|
|
469
|
+
// only when every key is seat-blocked.
|
|
470
|
+
if (opts?.enforceModelCapacity && modelFamily && available && available.length === 0) {
|
|
430
471
|
const policy = (env.MODEL_WINDOW_EXHAUSTED_POLICY ?? "fail").trim().toLowerCase();
|
|
431
|
-
|
|
472
|
+
const windowExhausted =
|
|
473
|
+
window !== undefined && modelBlockedCount > 0 && policy !== "fallback";
|
|
474
|
+
if (seatBlockedCount > 0) {
|
|
475
|
+
seatFallbackIndices = splitCredentialPool(val)
|
|
476
|
+
.map((_, i) => i)
|
|
477
|
+
.filter((i) => !seatBlockedIndices.includes(i));
|
|
478
|
+
}
|
|
479
|
+
if (windowExhausted || seatFallbackIndices?.length === 0) {
|
|
432
480
|
throw new ModelWindowExhaustedError({
|
|
433
481
|
model: modelFamily,
|
|
434
|
-
window,
|
|
482
|
+
window: window ?? "",
|
|
435
483
|
earliestResetAt: info?.earliestModelResetAt ?? null,
|
|
436
484
|
keyType: envVar,
|
|
485
|
+
seatBlockedCount,
|
|
486
|
+
modelBlockedCount,
|
|
437
487
|
});
|
|
438
488
|
}
|
|
439
489
|
}
|
|
440
490
|
|
|
441
|
-
const result =
|
|
491
|
+
const result = seatFallbackIndices
|
|
492
|
+
? { ...selectCredential(val, seatFallbackIndices, envVar), isRateLimitFallback: true }
|
|
493
|
+
: selectCredential(val, available, envVar);
|
|
442
494
|
env[envVar] = result.selected;
|
|
443
495
|
const availInfo = available ? ` (${available.length} available of ${result.total})` : "";
|
|
444
496
|
console.log(
|
|
@@ -448,6 +500,7 @@ export async function resolveCredentialPools(
|
|
|
448
500
|
...result,
|
|
449
501
|
modelBlockedIndices: info?.modelBlockedIndices,
|
|
450
502
|
earliestModelResetAt: info?.earliestModelResetAt,
|
|
503
|
+
seatBlockedIndices: info?.seatBlockedIndices,
|
|
451
504
|
});
|
|
452
505
|
}
|
|
453
506
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh `status.step_end.usage` normalization, shared by the worker adapter
|
|
3
|
+
* (session cost row) and the dashboard log parser (turn summary row) so both
|
|
4
|
+
* surfaces count the same tokens. Pure, no imports: `apps/ui` bundles it.
|
|
5
|
+
*
|
|
6
|
+
* dsh counts are disjoint and `totalTokens` is always their sum:
|
|
7
|
+
* `inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens` on both
|
|
8
|
+
* routes (pi-ai `parseChunkUsage` for OpenRouter, `dsh-llm-deepseek` for the
|
|
9
|
+
* direct API). Reasoning is folded into `outputTokens`, not added on top.
|
|
10
|
+
*
|
|
11
|
+
* The cache buckets can go missing while `totalTokens` keeps them: dsh omits a
|
|
12
|
+
* zero cache field, and when a step is retried `dsh-headless` sums an optional
|
|
13
|
+
* bucket only if every attempt reported it. A failed attempt reports zeroed
|
|
14
|
+
* usage, so the step's `cacheReadTokens` disappears and only `totalTokens`
|
|
15
|
+
* still carries it. The missing remainder is derived from `totalTokens`.
|
|
16
|
+
*/
|
|
17
|
+
export interface DshStepUsage {
|
|
18
|
+
/** Prompt tokens not served from cache. */
|
|
19
|
+
input: number;
|
|
20
|
+
output: number;
|
|
21
|
+
cacheRead: number;
|
|
22
|
+
cacheWrite: number;
|
|
23
|
+
/** Subset of `output`; only some routes report it. */
|
|
24
|
+
reasoning: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function count(value: unknown): number {
|
|
28
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Normalizes one `step_end.usage` object; `null` when the step reported none. */
|
|
32
|
+
export function normalizeDshStepUsage(usage: unknown): DshStepUsage | null {
|
|
33
|
+
if (!usage || typeof usage !== "object") return null;
|
|
34
|
+
const u = usage as Record<string, unknown>;
|
|
35
|
+
const input = count(u.inputTokens);
|
|
36
|
+
const output = count(u.outputTokens);
|
|
37
|
+
const cacheWrite = count(u.cacheWriteTokens);
|
|
38
|
+
const cacheRead =
|
|
39
|
+
typeof u.cacheReadTokens === "number"
|
|
40
|
+
? count(u.cacheReadTokens)
|
|
41
|
+
: Math.max(0, count(u.totalTokens) - input - output - cacheWrite);
|
|
42
|
+
return { input, output, cacheRead, cacheWrite, reasoning: count(u.reasoningTokens) };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function addDshStepUsage(acc: DshStepUsage | undefined, step: DshStepUsage): DshStepUsage {
|
|
46
|
+
return {
|
|
47
|
+
input: (acc?.input ?? 0) + step.input,
|
|
48
|
+
output: (acc?.output ?? 0) + step.output,
|
|
49
|
+
cacheRead: (acc?.cacheRead ?? 0) + step.cacheRead,
|
|
50
|
+
cacheWrite: (acc?.cacheWrite ?? 0) + step.cacheWrite,
|
|
51
|
+
reasoning: (acc?.reasoning ?? 0) + step.reasoning,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -95,6 +95,51 @@ export function parseRateLimitWindowTelemetry(
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* `rate_limit_info` fields that describe the seat's billing state (the
|
|
100
|
+
* `credits_required` payload). `scrubSecrets` does not match them, so they
|
|
101
|
+
* are dropped structurally before a log egress.
|
|
102
|
+
*/
|
|
103
|
+
const SEAT_PAYLOAD_FIELDS = [
|
|
104
|
+
"overageDisabledReason",
|
|
105
|
+
"canUserPurchaseCredits",
|
|
106
|
+
"hasChargeableSavedPaymentMethod",
|
|
107
|
+
] as const;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns a `rate_limit_event` message without the seat billing fields of
|
|
111
|
+
* its `rate_limit_info`. Any other message is returned unchanged. Error
|
|
112
|
+
* tracking reads the original message; only log egress uses the result.
|
|
113
|
+
*/
|
|
114
|
+
export function redactRateLimitEvent<T>(message: T): T {
|
|
115
|
+
if (!message || typeof message !== "object") return message;
|
|
116
|
+
const json = message as Record<string, unknown>;
|
|
117
|
+
if (json.type !== "rate_limit_event") return message;
|
|
118
|
+
const info = json.rate_limit_info;
|
|
119
|
+
if (!info || typeof info !== "object") return message;
|
|
120
|
+
if (!SEAT_PAYLOAD_FIELDS.some((field) => field in info)) return message;
|
|
121
|
+
const redactedInfo = { ...(info as Record<string, unknown>) };
|
|
122
|
+
for (const field of SEAT_PAYLOAD_FIELDS) delete redactedInfo[field];
|
|
123
|
+
return { ...json, rate_limit_info: redactedInfo } as T;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Line form of `redactRateLimitEvent` for the CLI's stream-json output. A
|
|
128
|
+
* line that is not a `rate_limit_event` with seat billing fields is returned
|
|
129
|
+
* byte for byte.
|
|
130
|
+
*/
|
|
131
|
+
export function redactRateLimitEventLine(line: string): string {
|
|
132
|
+
if (!line.includes('"rate_limit_event"')) return line;
|
|
133
|
+
let parsed: unknown;
|
|
134
|
+
try {
|
|
135
|
+
parsed = JSON.parse(line);
|
|
136
|
+
} catch {
|
|
137
|
+
return line;
|
|
138
|
+
}
|
|
139
|
+
const redacted = redactRateLimitEvent(parsed);
|
|
140
|
+
return redacted === parsed ? line : JSON.stringify(redacted);
|
|
141
|
+
}
|
|
142
|
+
|
|
98
143
|
/**
|
|
99
144
|
* Maximum cooldown horizon for a rate-limit reset. A weekly OAuth limit resets
|
|
100
145
|
* up to ~7 days out, so the cap must be at least that or a weekly-limited key
|
|
@@ -186,6 +231,14 @@ export class SessionErrorTracker {
|
|
|
186
231
|
private modelRateLimit:
|
|
187
232
|
| { window: string; model: ModelFamily; resetAtMs: number; observedAt: string }
|
|
188
233
|
| undefined;
|
|
234
|
+
/**
|
|
235
|
+
* Stashed `credits_required` rejection: the key's seat cannot run the
|
|
236
|
+
* session's model (e.g. "Fable 5.1 requires usage credits"). A seat fact,
|
|
237
|
+
* not a rate limit, so it never lands in `keyWideRejections`.
|
|
238
|
+
*/
|
|
239
|
+
private creditsRequired:
|
|
240
|
+
| { observedAt: string; resetsAtMs?: number; overageDisabledReason?: string }
|
|
241
|
+
| undefined;
|
|
189
242
|
private rateLimitWindows: RateLimitWindowTelemetry = {};
|
|
190
243
|
|
|
191
244
|
/** Record an error from an assistant message with message.error field */
|
|
@@ -265,6 +318,21 @@ export class SessionErrorTracker {
|
|
|
265
318
|
return;
|
|
266
319
|
}
|
|
267
320
|
|
|
321
|
+
// Checked before the resetsAt validation: the observed event carries a
|
|
322
|
+
// resetsAt, but this branch must not depend on it.
|
|
323
|
+
if (info.errorCode === "credits_required") {
|
|
324
|
+
this.creditsRequired = {
|
|
325
|
+
observedAt,
|
|
326
|
+
resetsAtMs:
|
|
327
|
+
typeof info.resetsAt === "number" && Number.isFinite(info.resetsAt)
|
|
328
|
+
? info.resetsAt * 1000
|
|
329
|
+
: undefined,
|
|
330
|
+
overageDisabledReason:
|
|
331
|
+
typeof info.overageDisabledReason === "string" ? info.overageDisabledReason : undefined,
|
|
332
|
+
};
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
268
336
|
const resetsAtSec = info.resetsAt;
|
|
269
337
|
if (typeof resetsAtSec !== "number" || !Number.isFinite(resetsAtSec) || resetsAtSec <= 0) {
|
|
270
338
|
console.warn(
|
|
@@ -344,6 +412,18 @@ export class SessionErrorTracker {
|
|
|
344
412
|
};
|
|
345
413
|
}
|
|
346
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Returns the stashed `credits_required` rejection, or undefined if none was
|
|
417
|
+
* seen in this session. It never sets the key-wide reset time.
|
|
418
|
+
*/
|
|
419
|
+
getCreditsRequired(): { observedAt: string; overageDisabledReason?: string } | undefined {
|
|
420
|
+
if (!this.creditsRequired) return undefined;
|
|
421
|
+
return {
|
|
422
|
+
observedAt: this.creditsRequired.observedAt,
|
|
423
|
+
overageDisabledReason: this.creditsRequired.overageDisabledReason,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
347
427
|
hasErrors(): boolean {
|
|
348
428
|
return this.errors.length > 0;
|
|
349
429
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The worker's harness CLI version (`claude --version`
|
|
2
|
+
* The worker's harness CLI version (`claude --version`, `codex --version`, or `pi --version`),
|
|
3
3
|
* reported on register and used to key harness_model_support rows. Worker-safe
|
|
4
4
|
* (no DB). Probed once per process; null when the CLI is missing or silent.
|
|
5
|
+
* An unprobed harness returns a blank string to clear stale registration data.
|
|
5
6
|
*/
|
|
6
7
|
import { isUnknownModelError } from "./harness-model-error";
|
|
7
8
|
import { scrubSecrets } from "./secret-scrubber";
|
|
8
9
|
|
|
9
|
-
const CLI_BINARY: Record<string, string> = { claude: "claude", codex: "codex" };
|
|
10
|
+
const CLI_BINARY: Record<string, string> = { claude: "claude", codex: "codex", pi: "pi" };
|
|
10
11
|
const PROBE_TIMEOUT_MS = 10_000;
|
|
11
12
|
const VERSION_RE = /\d+\.\d+\.\d+(?:[-+][\w.]+)?/;
|
|
12
13
|
|
|
@@ -18,7 +19,7 @@ export function parseCliVersion(output: string): string | null {
|
|
|
18
19
|
|
|
19
20
|
export function probeHarnessCliVersion(harness: string): Promise<string | null> {
|
|
20
21
|
const binary = CLI_BINARY[harness];
|
|
21
|
-
if (!binary) return Promise.resolve(
|
|
22
|
+
if (!binary) return Promise.resolve("");
|
|
22
23
|
let pending = probed.get(harness);
|
|
23
24
|
if (!pending) {
|
|
24
25
|
pending = (async () => {
|
|
@@ -66,7 +67,8 @@ export async function reportHarnessModelOutcome(opts: {
|
|
|
66
67
|
failureReason?: string;
|
|
67
68
|
fetchImpl?: typeof fetch;
|
|
68
69
|
}): Promise<void> {
|
|
69
|
-
|
|
70
|
+
// Only harnesses with verified unknown-model error classification report outcomes.
|
|
71
|
+
if (!opts.model || (opts.harness !== "claude" && opts.harness !== "codex")) return;
|
|
70
72
|
const cliVersion = await cachedHarnessCliVersion(opts.harness);
|
|
71
73
|
if (!cliVersion) return;
|
|
72
74
|
const status =
|
|
@@ -192,6 +192,17 @@ export async function defaultSpawnClaudeCli(
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/** Parsed output plus the model string that produced it. */
|
|
196
|
+
export interface CompleteStructuredResult<TData> {
|
|
197
|
+
data: TData;
|
|
198
|
+
/**
|
|
199
|
+
* Model that served the call, as resolved from the credential
|
|
200
|
+
* (`provider/model-id`, or the `claude -p` alias such as `haiku`). Lets
|
|
201
|
+
* callers record which judge produced the output.
|
|
202
|
+
*/
|
|
203
|
+
model: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
195
206
|
/**
|
|
196
207
|
* Run a structured-output completion. Returns the parsed object on success,
|
|
197
208
|
* `null` on auth-missing or exhausted retries (errors logged, never thrown).
|
|
@@ -199,6 +210,18 @@ export async function defaultSpawnClaudeCli(
|
|
|
199
210
|
export async function completeStructured<TZod extends z.ZodTypeAny>(
|
|
200
211
|
opts: CompleteStructuredOptions<TZod>,
|
|
201
212
|
): Promise<z.infer<TZod> | null> {
|
|
213
|
+
const result = await completeStructuredWithModel(opts);
|
|
214
|
+
return result ? result.data : null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Same as {@link completeStructured}, but also reports the model that served
|
|
219
|
+
* the call. Use it when the output must be attributable (e.g. `llm` memory
|
|
220
|
+
* ratings record their judge).
|
|
221
|
+
*/
|
|
222
|
+
export async function completeStructuredWithModel<TZod extends z.ZodTypeAny>(
|
|
223
|
+
opts: CompleteStructuredOptions<TZod>,
|
|
224
|
+
): Promise<CompleteStructuredResult<z.infer<TZod>> | null> {
|
|
202
225
|
const retries = opts.retries ?? 3;
|
|
203
226
|
const callerTag = opts.callerTag ?? "<unset>";
|
|
204
227
|
|
|
@@ -254,7 +277,7 @@ export async function completeStructured<TZod extends z.ZodTypeAny>(
|
|
|
254
277
|
}
|
|
255
278
|
const validated = opts.zodSchema.safeParse(parsedJson);
|
|
256
279
|
if (validated.success) {
|
|
257
|
-
return validated.data;
|
|
280
|
+
return { data: validated.data, model: cred.modelDefault };
|
|
258
281
|
}
|
|
259
282
|
lastErr = validated.error;
|
|
260
283
|
} catch (err) {
|
|
@@ -343,7 +366,7 @@ export async function completeStructured<TZod extends z.ZodTypeAny>(
|
|
|
343
366
|
if (parsedText !== undefined) {
|
|
344
367
|
const validatedText = opts.zodSchema.safeParse(parsedText);
|
|
345
368
|
if (validatedText.success) {
|
|
346
|
-
return validatedText.data;
|
|
369
|
+
return { data: validatedText.data, model: cred.modelDefault };
|
|
347
370
|
}
|
|
348
371
|
}
|
|
349
372
|
}
|
|
@@ -354,7 +377,7 @@ export async function completeStructured<TZod extends z.ZodTypeAny>(
|
|
|
354
377
|
|
|
355
378
|
const validated = opts.zodSchema.safeParse(toolCall.arguments);
|
|
356
379
|
if (validated.success) {
|
|
357
|
-
return validated.data;
|
|
380
|
+
return { data: validated.data, model: cred.modelDefault };
|
|
358
381
|
}
|
|
359
382
|
userPrompt = `${userPrompt}\n\nThe ${opts.toolName} arguments did not validate: ${validated.error.message}. Please retry with correct arguments.`;
|
|
360
383
|
lastErr = validated.error;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* Worker-safe: uses fetch() only, no bun:sqlite import.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { isFirstPartyAnthropicUrl } from "@desplega/model-routing";
|
|
18
19
|
import {
|
|
19
20
|
InMemoryCredentialStore,
|
|
20
21
|
type OAuthCredential,
|
|
@@ -24,7 +25,7 @@ import { registerBunOAuthFlows } from "@earendil-works/pi-ai/bun-oauth";
|
|
|
24
25
|
import { getEnvApiKey } from "@earendil-works/pi-ai/compat";
|
|
25
26
|
import { builtinModels } from "@earendil-works/pi-ai/providers/all";
|
|
26
27
|
import { getValidCodexOAuth, persistCodexOAuth } from "../../providers/codex-oauth/storage.js";
|
|
27
|
-
import { type CredentialKind, DEFAULT_MODEL,
|
|
28
|
+
import { type CredentialKind, DEFAULT_MODEL, resolveRaterModelString } from "./models.js";
|
|
28
29
|
|
|
29
30
|
registerBunOAuthFlows();
|
|
30
31
|
|
|
@@ -69,6 +70,12 @@ const resolveOAuthApiKey: OAuthApiKeyResolver = async (providerId, credentials)
|
|
|
69
70
|
};
|
|
70
71
|
};
|
|
71
72
|
|
|
73
|
+
/**
|
|
74
|
+
* `modelDefault` is the session-summary / `llm` memory-rater model for the
|
|
75
|
+
* credential kind (`resolveRaterModelString`: `MEMORY_RATER_MODEL` env, else
|
|
76
|
+
* the pinned `MEMORY_RATER_DEFAULT_MODEL`). It is not the general
|
|
77
|
+
* `DEFAULT_MODEL`; callers that want that (workflow LLM nodes) read it directly.
|
|
78
|
+
*/
|
|
72
79
|
export type ResolvedCredential =
|
|
73
80
|
| {
|
|
74
81
|
kind: "openrouter" | "anthropic" | "openai" | "openai-codex";
|
|
@@ -107,7 +114,8 @@ export interface ResolveCredentialOptions {
|
|
|
107
114
|
*
|
|
108
115
|
* Precedence (top wins):
|
|
109
116
|
* 1. `env.OPENROUTER_API_KEY` (via pi-ai `getEnvApiKey("openrouter")`)
|
|
110
|
-
* 2. `env.ANTHROPIC_API_KEY` (via pi-ai `getEnvApiKey("anthropic")`)
|
|
117
|
+
* 2. `env.ANTHROPIC_API_KEY` (via pi-ai `getEnvApiKey("anthropic")`), unless
|
|
118
|
+
* `ANTHROPIC_BASE_URL` points at a gateway (the key is the gateway's)
|
|
111
119
|
* 3. `env.OPENAI_API_KEY` (via pi-ai `getEnvApiKey("openai")`)
|
|
112
120
|
* 4. codex OAuth (only when `apiUrl && apiKey` are provided)
|
|
113
121
|
* 5. `env.CLAUDE_CODE_OAUTH_TOKEN` → claude-cli fallback
|
|
@@ -128,17 +136,23 @@ export async function resolveCredential(
|
|
|
128
136
|
return {
|
|
129
137
|
kind: "openrouter",
|
|
130
138
|
apiKey: openrouterKey,
|
|
131
|
-
modelDefault:
|
|
139
|
+
modelDefault: resolveRaterModelString("openrouter"),
|
|
132
140
|
};
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
// 2. Anthropic.
|
|
136
|
-
|
|
143
|
+
// 2. Anthropic. pi-ai sends this key to api.anthropic.com, so skip it when
|
|
144
|
+
// ANTHROPIC_BASE_URL names a gateway: the key belongs to the gateway (#1800).
|
|
145
|
+
const anthropicBaseUrl = env.ANTHROPIC_BASE_URL?.trim();
|
|
146
|
+
const anthropicKeyIsForGateway =
|
|
147
|
+
Boolean(anthropicBaseUrl) && !isFirstPartyAnthropicUrl(anthropicBaseUrl ?? "");
|
|
148
|
+
const anthropicKey = anthropicKeyIsForGateway
|
|
149
|
+
? undefined
|
|
150
|
+
: (env.ANTHROPIC_API_KEY ?? getEnvKey("anthropic"));
|
|
137
151
|
if (anthropicKey) {
|
|
138
152
|
return {
|
|
139
153
|
kind: "anthropic",
|
|
140
154
|
apiKey: anthropicKey,
|
|
141
|
-
modelDefault:
|
|
155
|
+
modelDefault: resolveRaterModelString("anthropic"),
|
|
142
156
|
};
|
|
143
157
|
}
|
|
144
158
|
|
|
@@ -148,7 +162,7 @@ export async function resolveCredential(
|
|
|
148
162
|
return {
|
|
149
163
|
kind: "openai",
|
|
150
164
|
apiKey: openaiKey,
|
|
151
|
-
modelDefault:
|
|
165
|
+
modelDefault: resolveRaterModelString("openai"),
|
|
152
166
|
};
|
|
153
167
|
}
|
|
154
168
|
|
|
@@ -190,7 +204,7 @@ export async function resolveCredential(
|
|
|
190
204
|
return {
|
|
191
205
|
kind: "openai-codex",
|
|
192
206
|
apiKey: oauthResult.apiKey,
|
|
193
|
-
modelDefault:
|
|
207
|
+
modelDefault: resolveRaterModelString("openai-codex"),
|
|
194
208
|
};
|
|
195
209
|
}
|
|
196
210
|
}
|
|
@@ -210,7 +224,7 @@ export async function resolveCredential(
|
|
|
210
224
|
if (env.AGENT_SWARM_CLAUDE_OAUTH_TOKEN || env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
211
225
|
return {
|
|
212
226
|
kind: "claude-cli",
|
|
213
|
-
modelDefault:
|
|
227
|
+
modelDefault: resolveRaterModelString("claude-cli"),
|
|
214
228
|
};
|
|
215
229
|
}
|
|
216
230
|
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
export {
|
|
16
16
|
type CompleteStructuredOptions,
|
|
17
|
+
type CompleteStructuredResult,
|
|
17
18
|
completeStructured,
|
|
19
|
+
completeStructuredWithModel,
|
|
18
20
|
} from "./complete-structured.js";
|
|
19
21
|
export {
|
|
20
22
|
type CredentialKind,
|
|
@@ -23,9 +25,14 @@ export {
|
|
|
23
25
|
type ResolvedCredential,
|
|
24
26
|
resolveCredential,
|
|
25
27
|
} from "./credentials.js";
|
|
26
|
-
export {
|
|
28
|
+
export {
|
|
29
|
+
MEMORY_RATER_DEFAULT_MODEL,
|
|
30
|
+
parseModelStr,
|
|
31
|
+
resolveRaterModelString,
|
|
32
|
+
} from "./models.js";
|
|
27
33
|
export {
|
|
28
34
|
type SummarizeSessionOptions,
|
|
35
|
+
type SummarizeSessionResult,
|
|
29
36
|
summarizeSession,
|
|
30
37
|
summaryToolSchema,
|
|
31
38
|
} from "./summarize-session.js";
|