@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
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Azure DevOps Integration
|
|
2
|
+
export {
|
|
3
|
+
likeAzureDevOpsComment,
|
|
4
|
+
postAzureDevOpsPullRequestComment,
|
|
5
|
+
resetAzureDevOpsBotIdCache,
|
|
6
|
+
resolveAzureDevOpsBotId,
|
|
7
|
+
} from "./api";
|
|
8
|
+
export {
|
|
9
|
+
AZURE_DEVOPS_BOT_NAME,
|
|
10
|
+
getAzureDevOpsOrgUrl,
|
|
11
|
+
getAzureDevOpsToken,
|
|
12
|
+
initAzureDevOps,
|
|
13
|
+
isAzureDevOpsEnabled,
|
|
14
|
+
resetAzureDevOps,
|
|
15
|
+
verifyAzureDevOpsWebhook,
|
|
16
|
+
} from "./auth";
|
|
17
|
+
export {
|
|
18
|
+
commentedPayloadOf,
|
|
19
|
+
createdPullRequestOf,
|
|
20
|
+
handlePullRequestCommented,
|
|
21
|
+
handlePullRequestCreated,
|
|
22
|
+
} from "./handlers";
|
|
23
|
+
export type {
|
|
24
|
+
AzureDevOpsWebhookEvent,
|
|
25
|
+
PullRequestCommentedEvent,
|
|
26
|
+
PullRequestCreatedEvent,
|
|
27
|
+
} from "./types";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps event prompt template definitions.
|
|
3
|
+
*
|
|
4
|
+
* Each template is registered at module load time via registerTemplate().
|
|
5
|
+
* Handlers import this module for the side-effect of registration.
|
|
6
|
+
*
|
|
7
|
+
* Template text uses {{variable}} syntax. The resolver interpolates variables
|
|
8
|
+
* and expands {{@template[id]}} references before returning the final text.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { registerTemplate } from "../prompts/registry";
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Common building blocks (Azure DevOps-specific)
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
registerTemplate({
|
|
18
|
+
eventType: "common.delegation_instruction.azure_devops",
|
|
19
|
+
header: "",
|
|
20
|
+
defaultBody:
|
|
21
|
+
"\n\n**Delegation instruction:** As the lead agent, analyze this and decide whether to handle it yourself or delegate to a worker agent. Use `send-task` to delegate with clear instructions.",
|
|
22
|
+
variables: [],
|
|
23
|
+
category: "common",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// `az repos` has no comment command, so replies go through `az devops invoke`.
|
|
27
|
+
registerTemplate({
|
|
28
|
+
eventType: "common.command_suggestions.azure_devops_pr",
|
|
29
|
+
header: "",
|
|
30
|
+
defaultBody:
|
|
31
|
+
'Workers have the `az` CLI with the azure-devops extension, authenticated with the swarm PAT. Inspect the PR with `az repos pr show --id {{pr_id}}`. To reply on the PR, write `{"comments":[{"content":"<reply>"}],"status":1}` to a JSON file and run `az devops invoke --area git --resource pullRequestThreads --route-parameters project={{project}} repositoryId={{repository}} pullRequestId={{pr_id}} --http-method POST --in-file <file> --api-version 7.1`.',
|
|
32
|
+
variables: [
|
|
33
|
+
{ name: "pr_id", description: "Pull request ID" },
|
|
34
|
+
{ name: "project", description: "Azure DevOps project name" },
|
|
35
|
+
{ name: "repository", description: "Azure Repos repository name" },
|
|
36
|
+
],
|
|
37
|
+
category: "common",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const SHARED_VARIABLES = [
|
|
41
|
+
{ name: "pr_id", description: "Pull request ID" },
|
|
42
|
+
{ name: "pr_title", description: "Pull request title" },
|
|
43
|
+
{
|
|
44
|
+
name: "repo",
|
|
45
|
+
description: "Repository clone URL (https://dev.azure.com/<org>/<project>/_git/<repo>)",
|
|
46
|
+
},
|
|
47
|
+
{ name: "project", description: "Azure DevOps project name" },
|
|
48
|
+
{ name: "repository", description: "Azure Repos repository name" },
|
|
49
|
+
{ name: "pr_url", description: "Pull request web URL" },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// Pull request events
|
|
54
|
+
// ============================================================================
|
|
55
|
+
|
|
56
|
+
registerTemplate({
|
|
57
|
+
eventType: "azure-devops.pull_request.opened",
|
|
58
|
+
header: "[Azure DevOps PR #{{pr_id}}] {{pr_title}}",
|
|
59
|
+
defaultBody: `Repo: {{repo}}
|
|
60
|
+
Author: {{username}}
|
|
61
|
+
Branch: {{source_branch}} → {{target_branch}}
|
|
62
|
+
URL: {{pr_url}}
|
|
63
|
+
|
|
64
|
+
{{context_section}}{{@template[common.command_suggestions.azure_devops_pr]}}{{@template[common.delegation_instruction.azure_devops]}}`,
|
|
65
|
+
variables: [
|
|
66
|
+
...SHARED_VARIABLES,
|
|
67
|
+
{
|
|
68
|
+
name: "username",
|
|
69
|
+
description:
|
|
70
|
+
"Author identity — resolved canonical name (e.g. 'Luis (azure-devops:luis@example.com)') or the UNKNOWN sentinel",
|
|
71
|
+
},
|
|
72
|
+
{ name: "source_branch", description: "Source branch name" },
|
|
73
|
+
{ name: "target_branch", description: "Target branch name" },
|
|
74
|
+
{ name: "context_section", description: "Context section with description or empty string" },
|
|
75
|
+
],
|
|
76
|
+
category: "event",
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Pull request comment events
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
registerTemplate({
|
|
84
|
+
eventType: "azure-devops.comment.mentioned",
|
|
85
|
+
header: "[Azure DevOps Comment on PR #{{pr_id}}] {{username}} mentioned bot",
|
|
86
|
+
defaultBody: `Repo: {{repo}}
|
|
87
|
+
PR: {{pr_title}}
|
|
88
|
+
URL: {{pr_url}}
|
|
89
|
+
|
|
90
|
+
Comment:
|
|
91
|
+
{{context}}{{existing_task_note}}
|
|
92
|
+
|
|
93
|
+
{{@template[common.command_suggestions.azure_devops_pr]}}{{@template[common.delegation_instruction.azure_devops]}}`,
|
|
94
|
+
variables: [
|
|
95
|
+
...SHARED_VARIABLES,
|
|
96
|
+
{
|
|
97
|
+
name: "username",
|
|
98
|
+
description:
|
|
99
|
+
"Comment author identity — resolved canonical name (e.g. 'Luis (azure-devops:luis@example.com)') or the UNKNOWN sentinel",
|
|
100
|
+
},
|
|
101
|
+
{ name: "context", description: "Extracted mention context from comment" },
|
|
102
|
+
{
|
|
103
|
+
name: "existing_task_note",
|
|
104
|
+
description: "Note about existing active task, or empty string",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
category: "event",
|
|
108
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps service-hook payload types.
|
|
3
|
+
*
|
|
4
|
+
* Based on https://learn.microsoft.com/azure/devops/service-hooks/events
|
|
5
|
+
* (resource version 1.0 for pull requests, 2.0 for pull request comments).
|
|
6
|
+
* Only the fields we actually use are typed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface AzureDevOpsIdentityRef {
|
|
10
|
+
id: string; // identity GUID; a picker @mention stores it as `@<GUID>`
|
|
11
|
+
displayName: string;
|
|
12
|
+
uniqueName?: string; // usually the sign-in email
|
|
13
|
+
url?: string;
|
|
14
|
+
imageUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AzureDevOpsProjectRef {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
url?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AzureDevOpsRepository {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
url: string; // REST URL of the repository
|
|
27
|
+
project: AzureDevOpsProjectRef;
|
|
28
|
+
defaultBranch?: string;
|
|
29
|
+
remoteUrl: string; // clone URL, may carry a `user@` prefix
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AzureDevOpsPullRequest {
|
|
33
|
+
repository: AzureDevOpsRepository;
|
|
34
|
+
pullRequestId: number;
|
|
35
|
+
status: string; // "active" | "abandoned" | "completed"
|
|
36
|
+
createdBy: AzureDevOpsIdentityRef;
|
|
37
|
+
title: string;
|
|
38
|
+
description?: string | null;
|
|
39
|
+
sourceRefName: string; // e.g. "refs/heads/feature"
|
|
40
|
+
targetRefName: string;
|
|
41
|
+
url: string; // REST URL of the pull request
|
|
42
|
+
_links?: { web?: { href: string } };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AzureDevOpsComment {
|
|
46
|
+
id: number;
|
|
47
|
+
parentCommentId: number;
|
|
48
|
+
author: AzureDevOpsIdentityRef;
|
|
49
|
+
content: string;
|
|
50
|
+
publishedDate: string;
|
|
51
|
+
lastContentUpdatedDate?: string;
|
|
52
|
+
commentType: string; // "text" | "system" | "codeChange"
|
|
53
|
+
_links?: {
|
|
54
|
+
self?: { href: string };
|
|
55
|
+
threads?: { href: string };
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface ResourceContainer {
|
|
60
|
+
id: string;
|
|
61
|
+
baseUrl?: string; // e.g. "https://dev.azure.com/fabrikam/"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ServiceHookEvent<TType extends string, TResource> {
|
|
65
|
+
id: string;
|
|
66
|
+
eventType: TType;
|
|
67
|
+
publisherId: string;
|
|
68
|
+
resource: TResource;
|
|
69
|
+
resourceVersion?: string;
|
|
70
|
+
resourceContainers?: {
|
|
71
|
+
collection?: ResourceContainer;
|
|
72
|
+
account?: ResourceContainer;
|
|
73
|
+
project?: ResourceContainer;
|
|
74
|
+
};
|
|
75
|
+
createdDate?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** `git.pullrequest.created` */
|
|
79
|
+
export type PullRequestCreatedEvent = ServiceHookEvent<
|
|
80
|
+
"git.pullrequest.created",
|
|
81
|
+
AzureDevOpsPullRequest
|
|
82
|
+
>;
|
|
83
|
+
|
|
84
|
+
/** `ms.vss-code.git-pullrequest-comment-event` */
|
|
85
|
+
export type PullRequestCommentedEvent = ServiceHookEvent<
|
|
86
|
+
"ms.vss-code.git-pullrequest-comment-event",
|
|
87
|
+
{ comment: AzureDevOpsComment; pullRequest: AzureDevOpsPullRequest }
|
|
88
|
+
>;
|
|
89
|
+
|
|
90
|
+
export type AzureDevOpsWebhookEvent = PullRequestCreatedEvent | PullRequestCommentedEvent;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { deriveProviderFromKeyType } from "../../utils/credentials";
|
|
2
|
+
import type { ModelFamily } from "../../utils/model-rate-limit-windows";
|
|
3
|
+
import { planAllowsModelFamily } from "../../utils/subscription-plans";
|
|
4
|
+
import { getDbClient } from "./runtime";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Records a `credits_required` rejection: the key's seat cannot run `model`.
|
|
8
|
+
* Sets `lastSeatMismatchAt` / `lastSeatMismatchModel` on every scope row of
|
|
9
|
+
* the key. A Claude key whose plan the operator did not pick gets
|
|
10
|
+
* `claude_team_standard` / `detected`, the only plan that excludes Fable,
|
|
11
|
+
* but only when that plan excludes `model`: an Opus or Sonnet rejection is
|
|
12
|
+
* no evidence of a standard seat. A `manual` plan is never changed; a
|
|
13
|
+
* contradiction is logged instead. The key `status` is not touched.
|
|
14
|
+
*/
|
|
15
|
+
export async function recordKeySeatMismatch(
|
|
16
|
+
keyType: string,
|
|
17
|
+
keySuffix: string,
|
|
18
|
+
keyIndex: number,
|
|
19
|
+
model: ModelFamily,
|
|
20
|
+
scope = "global",
|
|
21
|
+
scopeId: string | null = null,
|
|
22
|
+
): Promise<{ planChanged: boolean }> {
|
|
23
|
+
const now = new Date().toISOString();
|
|
24
|
+
const effectiveScopeId = scopeId ?? "";
|
|
25
|
+
const provider = deriveProviderFromKeyType(keyType);
|
|
26
|
+
return getDbClient().transaction(async (tx) => {
|
|
27
|
+
await tx.run(
|
|
28
|
+
`INSERT INTO api_key_status (keyType, keySuffix, keyIndex, scope, scopeId, provider, updatedAt)
|
|
29
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
30
|
+
ON CONFLICT(keyType, keySuffix, scope, scopeId)
|
|
31
|
+
DO UPDATE SET
|
|
32
|
+
keyIndex = excluded.keyIndex,
|
|
33
|
+
provider = excluded.provider,
|
|
34
|
+
updatedAt = excluded.updatedAt`,
|
|
35
|
+
[keyType, keySuffix, keyIndex, scope, effectiveScopeId, provider, now],
|
|
36
|
+
);
|
|
37
|
+
await tx.run(
|
|
38
|
+
`UPDATE api_key_status SET lastSeatMismatchAt = ?, lastSeatMismatchModel = ?
|
|
39
|
+
WHERE keyType = ? AND keySuffix = ?`,
|
|
40
|
+
[now, model, keyType, keySuffix],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
let planChanged = false;
|
|
44
|
+
if (
|
|
45
|
+
keyType === "CLAUDE_CODE_OAUTH_TOKEN" &&
|
|
46
|
+
!planAllowsModelFamily("claude_team_standard", model)
|
|
47
|
+
) {
|
|
48
|
+
const result = await tx.run(
|
|
49
|
+
`UPDATE api_key_status SET plan = 'claude_team_standard', planSource = 'detected'
|
|
50
|
+
WHERE keyType = ? AND keySuffix = ? AND COALESCE(planSource, '') != 'manual'`,
|
|
51
|
+
[keyType, keySuffix],
|
|
52
|
+
);
|
|
53
|
+
planChanged = result.changes > 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!planChanged) {
|
|
57
|
+
const stored = await tx.get<{ plan: string | null }>(
|
|
58
|
+
`SELECT plan FROM api_key_status
|
|
59
|
+
WHERE keyType = ? AND keySuffix = ? AND scope = ? AND scopeId = ?`,
|
|
60
|
+
[keyType, keySuffix, scope, effectiveScopeId],
|
|
61
|
+
);
|
|
62
|
+
if (planAllowsModelFamily(stored?.plan, model)) {
|
|
63
|
+
console.warn(
|
|
64
|
+
`[api-keys] seat mismatch: key ...${keySuffix} (${keyType}) has plan ${stored?.plan ?? "none"} but cannot run ${model}`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { planChanged };
|
|
69
|
+
});
|
|
70
|
+
}
|
package/src/be/db/tasks/read.ts
CHANGED
|
@@ -288,7 +288,7 @@ export function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
288
288
|
slackReplySent: !!row.slackReplySent,
|
|
289
289
|
slackProgressMessageTs: row.slackProgressMessageTs ?? undefined,
|
|
290
290
|
slackTreeRootMessageTs: row.slackTreeRootMessageTs ?? undefined,
|
|
291
|
-
vcsProvider: (row.vcsProvider as "github" | "gitlab" | null) ?? undefined,
|
|
291
|
+
vcsProvider: (row.vcsProvider as "github" | "gitlab" | "azure-devops" | null) ?? undefined,
|
|
292
292
|
vcsRepo: row.vcsRepo ?? undefined,
|
|
293
293
|
vcsEventType: row.vcsEventType ?? undefined,
|
|
294
294
|
vcsNumber: row.vcsNumber ?? undefined,
|
package/src/be/db/tasks/write.ts
CHANGED
|
@@ -317,6 +317,22 @@ export async function updateTaskClaudeSessionId(
|
|
|
317
317
|
return row ? rowToAgentTask(row) : null;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Records the harness that ran (or tried to run) a task when no session ever
|
|
322
|
+
* reported it. `provider` is otherwise written only by the session-init path,
|
|
323
|
+
* so a task whose harness failed to spawn kept `provider` NULL and looked like
|
|
324
|
+
* a task that never started. Never overwrites a provider already recorded.
|
|
325
|
+
*/
|
|
326
|
+
export async function recordTaskProviderIfUnset(
|
|
327
|
+
taskId: string,
|
|
328
|
+
provider: ProviderName,
|
|
329
|
+
): Promise<void> {
|
|
330
|
+
await getDbClient().run("UPDATE agent_tasks SET provider = ? WHERE id = ? AND provider IS NULL", [
|
|
331
|
+
provider,
|
|
332
|
+
taskId,
|
|
333
|
+
]);
|
|
334
|
+
}
|
|
335
|
+
|
|
320
336
|
/**
|
|
321
337
|
* Sets or clears a task's display title (session rename). Trims the input and
|
|
322
338
|
* normalizes an empty string to NULL (clear). Deliberately does NOT touch
|
package/src/be/db-client.ts
CHANGED
|
@@ -68,6 +68,9 @@ export interface DbClient extends DbExecutor {
|
|
|
68
68
|
* really did occupy the driver and block the event loop, up to
|
|
69
69
|
* `attemptSpinMs` per BUSY attempt. It excludes all lock waiting and all
|
|
70
70
|
* backoff sleeping.
|
|
71
|
+
*
|
|
72
|
+
* `changes` counts only the rows the statement itself changed. Unlike
|
|
73
|
+
* `run`, it excludes rows touched by foreign-key actions.
|
|
71
74
|
*/
|
|
72
75
|
runTimed(sql: string, params?: DbParam[]): Promise<{ changes: number; executionMs: number }>;
|
|
73
76
|
/**
|
|
@@ -278,8 +281,14 @@ class BunSqliteClient implements DbClient {
|
|
|
278
281
|
const result = await this.execute(
|
|
279
282
|
sql,
|
|
280
283
|
(db) => {
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
db.query(sql).run(...params);
|
|
285
|
+
// bun:sqlite's `run().changes` also counts rows touched by foreign-key
|
|
286
|
+
// actions (an ON DELETE SET NULL child update counts as a change), so
|
|
287
|
+
// a DELETE on a self-referencing table reports up to twice the rows it
|
|
288
|
+
// removed. SQLite's changes() counts only the statement's own rows.
|
|
289
|
+
// Same connection, still inside the lock: nothing can run in between.
|
|
290
|
+
const own = db.query("SELECT changes() AS n").get() as { n: number } | null;
|
|
291
|
+
return { changes: own?.n ?? 0 };
|
|
283
292
|
},
|
|
284
293
|
(ms) => {
|
|
285
294
|
executionMs += ms;
|
package/src/be/db-retention.ts
CHANGED
|
@@ -20,33 +20,63 @@ const YIELD_MS = 25;
|
|
|
20
20
|
* This is deliberately a closed list. Neither table nor column names may come
|
|
21
21
|
* from operator configuration: a retention policy must never target a table
|
|
22
22
|
* that code review has not explicitly approved as safe to delete from.
|
|
23
|
+
*
|
|
24
|
+
* Two policies exist:
|
|
25
|
+
* - `age`: the env value is a number of days; rows whose `timeColumn` is older
|
|
26
|
+
* than that horizon are deleted.
|
|
27
|
+
* - `keepLatest`: the env value is a count; within each `partitionBy` group,
|
|
28
|
+
* only the newest `rankBy` rows are kept. The newest row of a group is
|
|
29
|
+
* never deleted, because the smallest accepted count is 1.
|
|
23
30
|
*/
|
|
24
31
|
export const DB_RETENTION_TABLES = [
|
|
25
32
|
{
|
|
26
33
|
table: "session_logs",
|
|
34
|
+
policy: "age",
|
|
27
35
|
timeColumn: "createdAt",
|
|
28
36
|
envKey: "SESSION_LOG_RETENTION_DAYS",
|
|
29
37
|
metricsKey: "sessionLogs",
|
|
30
38
|
},
|
|
31
39
|
{
|
|
32
40
|
table: "agent_log",
|
|
41
|
+
policy: "age",
|
|
33
42
|
timeColumn: "createdAt",
|
|
34
43
|
envKey: "AGENT_LOG_RETENTION_DAYS",
|
|
35
44
|
metricsKey: "agentLog",
|
|
36
45
|
},
|
|
37
46
|
{
|
|
38
47
|
table: "events",
|
|
48
|
+
policy: "age",
|
|
39
49
|
timeColumn: "createdAt",
|
|
40
50
|
envKey: "EVENTS_RETENTION_DAYS",
|
|
41
51
|
metricsKey: "events",
|
|
42
52
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
{
|
|
54
|
+
// Every profile self-edit stores a full copy of the field, so a large,
|
|
55
|
+
// frequently edited field grows this table without bound. Ranking runs on
|
|
56
|
+
// the covering idx_cv_agent_field index, so neither the COUNT nor the
|
|
57
|
+
// candidate scan reads `content`. Rows are large (a version can be
|
|
58
|
+
// hundreds of KB), so batches start and stay small.
|
|
59
|
+
table: "context_versions",
|
|
60
|
+
policy: "keepLatest",
|
|
61
|
+
partitionBy: "agentId, field",
|
|
62
|
+
rankBy: "version",
|
|
63
|
+
envKey: "CONTEXT_VERSIONS_KEEP_LATEST",
|
|
64
|
+
metricsKey: "contextVersions",
|
|
65
|
+
initialBatchSize: 50,
|
|
66
|
+
maxBatchSize: 100,
|
|
67
|
+
},
|
|
68
|
+
] as const satisfies ReadonlyArray<
|
|
69
|
+
{
|
|
70
|
+
table: string;
|
|
71
|
+
envKey: string;
|
|
72
|
+
metricsKey: string;
|
|
73
|
+
initialBatchSize?: number;
|
|
74
|
+
maxBatchSize?: number;
|
|
75
|
+
} & (
|
|
76
|
+
| { policy: "age"; timeColumn: string }
|
|
77
|
+
| { policy: "keepLatest"; partitionBy: string; rankBy: string }
|
|
78
|
+
)
|
|
79
|
+
>;
|
|
50
80
|
|
|
51
81
|
type RetentionTable = (typeof DB_RETENTION_TABLES)[number];
|
|
52
82
|
type RetentionMetricsKey = RetentionTable["metricsKey"];
|
|
@@ -261,27 +291,65 @@ function yieldTick(): Promise<void> {
|
|
|
261
291
|
return new Promise((resolve) => setTimeout(resolve, YIELD_MS));
|
|
262
292
|
}
|
|
263
293
|
|
|
264
|
-
|
|
294
|
+
/** Days for an `age` table, kept-version count for a `keepLatest` table; null when disabled. */
|
|
295
|
+
function retentionValue(table: RetentionTable): number | null {
|
|
265
296
|
return readPositiveIntEnv(table.envKey);
|
|
266
297
|
}
|
|
267
298
|
|
|
299
|
+
function initialBatchSize(table: RetentionTable): number {
|
|
300
|
+
return "initialBatchSize" in table ? table.initialBatchSize : DEFAULT_BATCH_SIZE;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function maxBatchSize(table: RetentionTable): number {
|
|
304
|
+
return "maxBatchSize" in table ? table.maxBatchSize : MAX_BATCH_SIZE;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** The backlog COUNT and the batched DELETE for one table under its policy. */
|
|
308
|
+
type SweepStatements = {
|
|
309
|
+
backlogSql: string;
|
|
310
|
+
/** Takes `params` followed by the batch LIMIT. */
|
|
311
|
+
deleteSql: string;
|
|
312
|
+
params: Array<string | number>;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
export function sweepStatements(table: RetentionTable, value: number, now: Date): SweepStatements {
|
|
316
|
+
if (table.policy === "keepLatest") {
|
|
317
|
+
// ROW_NUMBER over the (partition, rank DESC) index: rank 1 is the newest
|
|
318
|
+
// row of its group. The DELETE removes the deepest history first, so an
|
|
319
|
+
// interrupted sweep leaves each group's surviving versions contiguous.
|
|
320
|
+
const ranked = `SELECT rowid AS rid, ROW_NUMBER() OVER (PARTITION BY ${table.partitionBy} ORDER BY ${table.rankBy} DESC) AS rn FROM ${table.table}`;
|
|
321
|
+
return {
|
|
322
|
+
backlogSql: `SELECT COUNT(*) AS n FROM (${ranked}) WHERE rn > ?`,
|
|
323
|
+
deleteSql: `DELETE FROM ${table.table} WHERE rowid IN (
|
|
324
|
+
SELECT rid FROM (${ranked}) WHERE rn > ? ORDER BY rn DESC LIMIT ?
|
|
325
|
+
)`,
|
|
326
|
+
params: [value],
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
const cutoff = new Date(now.getTime() - value * DAY_MS).toISOString();
|
|
330
|
+
return {
|
|
331
|
+
backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${table.timeColumn} < ?`,
|
|
332
|
+
deleteSql: `DELETE FROM ${table.table} WHERE rowid IN (
|
|
333
|
+
SELECT rowid FROM ${table.table} WHERE ${table.timeColumn} < ? ORDER BY ${table.timeColumn} LIMIT ?
|
|
334
|
+
)`,
|
|
335
|
+
params: [cutoff],
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
268
339
|
function dryRunEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
269
340
|
const raw = env.DB_RETENTION_DRY_RUN;
|
|
270
341
|
if (raw === undefined || raw.trim() === "") return false;
|
|
271
342
|
return isEnvFlagEnabled("DB_RETENTION_DRY_RUN", true, env);
|
|
272
343
|
}
|
|
273
344
|
|
|
274
|
-
async function indexedBacklogCount(
|
|
275
|
-
const row = await getDbClient().get<{ n: number }>(
|
|
276
|
-
`SELECT COUNT(*) AS n FROM ${table.table} WHERE ${table.timeColumn} < ?`,
|
|
277
|
-
[cutoff],
|
|
278
|
-
);
|
|
345
|
+
async function indexedBacklogCount(statements: SweepStatements): Promise<number> {
|
|
346
|
+
const row = await getDbClient().get<{ n: number }>(statements.backlogSql, statements.params);
|
|
279
347
|
return row?.n ?? 0;
|
|
280
348
|
}
|
|
281
349
|
|
|
282
350
|
async function sweepTable(
|
|
283
351
|
table: RetentionTable,
|
|
284
|
-
|
|
352
|
+
statements: SweepStatements,
|
|
285
353
|
dryRun: boolean,
|
|
286
354
|
deadline: number,
|
|
287
355
|
signal: AbortSignal,
|
|
@@ -290,33 +358,29 @@ async function sweepTable(
|
|
|
290
358
|
const client = getDbClient();
|
|
291
359
|
|
|
292
360
|
if (dryRun) {
|
|
293
|
-
const backlogRemaining = await indexedBacklogCount(
|
|
361
|
+
const backlogRemaining = await indexedBacklogCount(statements);
|
|
294
362
|
return {
|
|
295
363
|
rowsDeleted: 0,
|
|
296
364
|
batches: 0,
|
|
297
365
|
backlogRemaining,
|
|
298
366
|
drained: backlogRemaining === 0,
|
|
299
367
|
slowestStatementMs: 0,
|
|
300
|
-
batchSize: batchSizeByTable[table.metricsKey] ??
|
|
368
|
+
batchSize: batchSizeByTable[table.metricsKey] ?? initialBatchSize(table),
|
|
301
369
|
};
|
|
302
370
|
}
|
|
303
371
|
|
|
304
372
|
let rowsDeleted = 0;
|
|
305
373
|
let batches = 0;
|
|
306
374
|
let slowestStatementMs = 0;
|
|
307
|
-
let size = batchSizeByTable[table.metricsKey] ??
|
|
375
|
+
let size = batchSizeByTable[table.metricsKey] ?? initialBatchSize(table);
|
|
376
|
+
const ceiling = maxBatchSize(table);
|
|
308
377
|
|
|
309
378
|
try {
|
|
310
379
|
while (!signal.aborted && Date.now() < deadline) {
|
|
311
380
|
const limitUsed = size;
|
|
312
381
|
// Never wrap multiple batches in a transaction: one autocommit DELETE per
|
|
313
382
|
// batch, so the write lock and any event-loop stall end with each statement.
|
|
314
|
-
const result = await client.runTimed(
|
|
315
|
-
`DELETE FROM ${table.table} WHERE rowid IN (
|
|
316
|
-
SELECT rowid FROM ${table.table} WHERE ${table.timeColumn} < ? ORDER BY ${table.timeColumn} LIMIT ?
|
|
317
|
-
)`,
|
|
318
|
-
[cutoff, limitUsed],
|
|
319
|
-
);
|
|
383
|
+
const result = await client.runTimed(statements.deleteSql, [...statements.params, limitUsed]);
|
|
320
384
|
// Execution time only. Wall time around the call also covers waiting for
|
|
321
385
|
// the client's FIFO lock and its BUSY backoff sleeps, neither of which
|
|
322
386
|
// this statement spent in the driver: charging those to the stall metric
|
|
@@ -331,7 +395,7 @@ async function sweepTable(
|
|
|
331
395
|
if (elapsed > maxStatementMs) {
|
|
332
396
|
size = Math.max(MIN_BATCH_SIZE, Math.floor(size / 2));
|
|
333
397
|
} else if (elapsed < maxStatementMs / 5) {
|
|
334
|
-
size = Math.min(
|
|
398
|
+
size = Math.min(ceiling, size * 2);
|
|
335
399
|
}
|
|
336
400
|
|
|
337
401
|
// A DELETE that changed fewer rows than the LIMIT it used means the
|
|
@@ -351,7 +415,7 @@ async function sweepTable(
|
|
|
351
415
|
// backlogRemaining > 0 drops the table from `undrained`, leaves catch-up
|
|
352
416
|
// unarmed, and publishes that contradiction on /api/metrics until the next
|
|
353
417
|
// hourly tick.
|
|
354
|
-
const backlogRemaining = await indexedBacklogCount(
|
|
418
|
+
const backlogRemaining = await indexedBacklogCount(statements);
|
|
355
419
|
return {
|
|
356
420
|
rowsDeleted,
|
|
357
421
|
batches,
|
|
@@ -409,7 +473,7 @@ export function runDbRetentionTick(options: DbRetentionTickOptions = {}): Promis
|
|
|
409
473
|
const sweepAllTables = async (rawTickSpan: SwarmSpan): Promise<void> => {
|
|
410
474
|
const tickSpan = bestEffortSpan(rawTickSpan);
|
|
411
475
|
const tickDeadline = tickStartedAt + budget;
|
|
412
|
-
const enabled = DB_RETENTION_TABLES.filter((table) =>
|
|
476
|
+
const enabled = DB_RETENTION_TABLES.filter((table) => retentionValue(table) !== null);
|
|
413
477
|
if (enabled.length === 0) {
|
|
414
478
|
lastSweepOrder = [];
|
|
415
479
|
tickSpan.setAttributes({
|
|
@@ -431,18 +495,17 @@ export function runDbRetentionTick(options: DbRetentionTickOptions = {}): Promis
|
|
|
431
495
|
const undrained = new Set<RetentionMetricsKey>();
|
|
432
496
|
|
|
433
497
|
const sweepOne = async (table: RetentionTable, tableDeadline: number): Promise<void> => {
|
|
434
|
-
const
|
|
435
|
-
if (
|
|
498
|
+
const value = retentionValue(table);
|
|
499
|
+
if (value === null) return;
|
|
436
500
|
const startedAt = Date.now();
|
|
437
501
|
const previous = retentionStats[table.metricsKey];
|
|
438
502
|
const tableSpan = bestEffortStartSpan("db.retention.table", {
|
|
439
503
|
"agentswarm.retention.table": table.table,
|
|
440
504
|
});
|
|
441
505
|
try {
|
|
442
|
-
const cutoff = new Date(cutoffBase.getTime() - days * DAY_MS).toISOString();
|
|
443
506
|
const result = await sweepTable(
|
|
444
507
|
table,
|
|
445
|
-
|
|
508
|
+
sweepStatements(table, value, cutoffBase),
|
|
446
509
|
dryRun,
|
|
447
510
|
tableDeadline,
|
|
448
511
|
abortController.signal,
|
|
@@ -529,7 +592,7 @@ export function runDbRetentionTick(options: DbRetentionTickOptions = {}): Promis
|
|
|
529
592
|
partial?.progress.batchSize ??
|
|
530
593
|
previous?.batchSize ??
|
|
531
594
|
batchSizeByTable[table.metricsKey] ??
|
|
532
|
-
|
|
595
|
+
initialBatchSize(table);
|
|
533
596
|
// Committed rows advance the running total and justify the vacuum,
|
|
534
597
|
// exactly as they would have on the success path.
|
|
535
598
|
const cumulative = (cumulativeRowsDeleted[table.metricsKey] ?? 0) + rowsDeleted;
|
|
@@ -670,7 +733,7 @@ export function _getLastSweepOrderForTests(): RetentionMetricsKey[] {
|
|
|
670
733
|
export async function startDbRetention(intervalMs = RETENTION_INTERVAL_MS): Promise<void> {
|
|
671
734
|
if (retentionTimer) return;
|
|
672
735
|
const configured = DB_RETENTION_TABLES.map(
|
|
673
|
-
(table) => `${table.table}=${
|
|
736
|
+
(table) => `${table.table}=${retentionValue(table) ?? "disabled"}`,
|
|
674
737
|
).join(", ");
|
|
675
738
|
console.log(`[db-retention] starting (${configured}, dryRun=${dryRunEnabled()})`);
|
|
676
739
|
retentionTimer = scheduleContextFree(() =>
|