@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
|
@@ -2,33 +2,16 @@ import {
|
|
|
2
2
|
COMPOSIO_HTTP_METHODS,
|
|
3
3
|
composioArgsFromParts,
|
|
4
4
|
executeComposioRequest
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-cat6h73s.js";
|
|
6
6
|
import {
|
|
7
7
|
LlmRater,
|
|
8
8
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
9
9
|
getMemoryRaterNames,
|
|
10
10
|
sanitizeReferencesSource
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-w0bwte75.js";
|
|
12
12
|
import {
|
|
13
13
|
isMultiRuntimeEnabled
|
|
14
14
|
} from "./cli-re8z5p8p.js";
|
|
15
|
-
import {
|
|
16
|
-
AgentFsProvider,
|
|
17
|
-
getFileStorageProvider,
|
|
18
|
-
providerPath
|
|
19
|
-
} from "./cli-jsp14b6c.js";
|
|
20
|
-
import {
|
|
21
|
-
ensurePricingSeeded,
|
|
22
|
-
ensureRbacSeeded,
|
|
23
|
-
getUserGrant
|
|
24
|
-
} from "./cli-z9x0sh1t.js";
|
|
25
|
-
import {
|
|
26
|
-
can,
|
|
27
|
-
decideAdmission,
|
|
28
|
-
grantLeadEquivalence,
|
|
29
|
-
isRbacEnabled,
|
|
30
|
-
revokeLeadEquivalence
|
|
31
|
-
} from "./cli-9yg65c1j.js";
|
|
32
15
|
import {
|
|
33
16
|
buildCatalogEntries,
|
|
34
17
|
getCatalogGeneration,
|
|
@@ -38,10 +21,7 @@ import {
|
|
|
38
21
|
requestModelCatalogRefresh,
|
|
39
22
|
startPricingRefreshLoop,
|
|
40
23
|
upsertModelCatalogOverlay
|
|
41
|
-
} from "./cli-
|
|
42
|
-
import {
|
|
43
|
-
loadModelsDevCache
|
|
44
|
-
} from "./cli-0n2e4x49.js";
|
|
24
|
+
} from "./cli-3zc55ctx.js";
|
|
45
25
|
import {
|
|
46
26
|
AppDefinitionSchema,
|
|
47
27
|
AppElementsSchema,
|
|
@@ -121,7 +101,7 @@ import {
|
|
|
121
101
|
validateDefinition,
|
|
122
102
|
validateScriptImports,
|
|
123
103
|
writeBareImportShim
|
|
124
|
-
} from "./cli-
|
|
104
|
+
} from "./cli-1er0rhz8.js";
|
|
125
105
|
import {
|
|
126
106
|
detachedProcessGroup,
|
|
127
107
|
registerProcessGroup,
|
|
@@ -130,9 +110,14 @@ import {
|
|
|
130
110
|
import {
|
|
131
111
|
getApiKey
|
|
132
112
|
} from "./cli-f14fvzag.js";
|
|
113
|
+
import {
|
|
114
|
+
AgentFsProvider,
|
|
115
|
+
getFileStorageProvider,
|
|
116
|
+
providerPath
|
|
117
|
+
} from "./cli-jsp14b6c.js";
|
|
133
118
|
import {
|
|
134
119
|
embedScript
|
|
135
|
-
} from "./cli-
|
|
120
|
+
} from "./cli-7119ja3w.js";
|
|
136
121
|
import {
|
|
137
122
|
buildAuthorizationUrl,
|
|
138
123
|
createOAuthApp,
|
|
@@ -147,23 +132,48 @@ import {
|
|
|
147
132
|
listAuthorizationsForApp,
|
|
148
133
|
onAuthorizationRefreshed,
|
|
149
134
|
upsertOAuthApp
|
|
150
|
-
} from "./cli-
|
|
135
|
+
} from "./cli-hgmnf38m.js";
|
|
136
|
+
import {
|
|
137
|
+
ensurePricingSeeded,
|
|
138
|
+
ensureRbacSeeded,
|
|
139
|
+
getUserGrant
|
|
140
|
+
} from "./cli-we0q7t0e.js";
|
|
141
|
+
import {
|
|
142
|
+
can,
|
|
143
|
+
decideAdmission,
|
|
144
|
+
grantLeadEquivalence,
|
|
145
|
+
isRbacEnabled,
|
|
146
|
+
revokeLeadEquivalence
|
|
147
|
+
} from "./cli-tsk3nz8a.js";
|
|
148
|
+
import {
|
|
149
|
+
loadModelsDevCache
|
|
150
|
+
} from "./cli-ecfxwnyb.js";
|
|
151
151
|
import {
|
|
152
152
|
ZodFirstPartyTypeKind,
|
|
153
153
|
objectType
|
|
154
154
|
} from "./cli-fad8m16k.js";
|
|
155
155
|
import {
|
|
156
156
|
CANDIDATE_SET_MULTIPLIER,
|
|
157
|
+
LONGTERM_ROOT,
|
|
158
|
+
MEMORY_KEY_MAX_LENGTH,
|
|
159
|
+
MEMORY_KEY_PATTERN,
|
|
160
|
+
MEMORY_KEY_PATTERN_MESSAGE,
|
|
157
161
|
computeScore,
|
|
162
|
+
consolidatedKeyMessage,
|
|
158
163
|
getEmbeddingProvider,
|
|
159
164
|
getMemoryStore,
|
|
160
165
|
init_constants as init_constants2,
|
|
166
|
+
init_key_paths,
|
|
161
167
|
init_reranker,
|
|
162
168
|
init_sqlite_store,
|
|
169
|
+
isConsolidatedKey,
|
|
163
170
|
isGraphExpansionEnabled,
|
|
171
|
+
isLongtermKey,
|
|
172
|
+
longtermKeyError,
|
|
164
173
|
rerank,
|
|
174
|
+
resolveStoreKey,
|
|
165
175
|
rowToCandidate
|
|
166
|
-
} from "./cli-
|
|
176
|
+
} from "./cli-d56tgd45.js";
|
|
167
177
|
import {
|
|
168
178
|
require_dist
|
|
169
179
|
} from "./cli-51tf7ac3.js";
|
|
@@ -189,7 +199,7 @@ import {
|
|
|
189
199
|
taskCitationWarnings,
|
|
190
200
|
upsertTaskCitations,
|
|
191
201
|
withSpan
|
|
192
|
-
} from "./cli-
|
|
202
|
+
} from "./cli-phfg8vy8.js";
|
|
193
203
|
import {
|
|
194
204
|
init_task_attachment_links,
|
|
195
205
|
taskAttachmentDisplayUrl,
|
|
@@ -204,6 +214,7 @@ import {
|
|
|
204
214
|
acceptTask,
|
|
205
215
|
agentContextKey,
|
|
206
216
|
agentmailContextKey,
|
|
217
|
+
azureDevOpsContextKey,
|
|
207
218
|
beginRequestAuthScope,
|
|
208
219
|
buildJiraContextKey,
|
|
209
220
|
buildRoutingAffinityFromAgent,
|
|
@@ -458,7 +469,7 @@ import {
|
|
|
458
469
|
upsertSwarmConfig,
|
|
459
470
|
validateConfigValue,
|
|
460
471
|
workflowContextKey
|
|
461
|
-
} from "./cli-
|
|
472
|
+
} from "./cli-1cz0c18q.js";
|
|
462
473
|
import {
|
|
463
474
|
$OpenAPIRegistry,
|
|
464
475
|
$OpenApiGeneratorV31,
|
|
@@ -505,6 +516,7 @@ import {
|
|
|
505
516
|
WorkflowNodePatchSchema,
|
|
506
517
|
WorkflowRunStatusSchema,
|
|
507
518
|
canWriteAssetKey,
|
|
519
|
+
checkExtensionInstallSource,
|
|
508
520
|
init_bundle_path,
|
|
509
521
|
init_dist,
|
|
510
522
|
init_key,
|
|
@@ -516,18 +528,13 @@ import {
|
|
|
516
528
|
parseAssetKey,
|
|
517
529
|
parseModelTier,
|
|
518
530
|
splitLegacyModelAlias
|
|
519
|
-
} from "./cli-
|
|
531
|
+
} from "./cli-akfj32vj.js";
|
|
520
532
|
import {
|
|
521
533
|
generateDefaultClaudeMd,
|
|
522
534
|
generateDefaultIdentityMd,
|
|
523
535
|
generateDefaultSoulMd,
|
|
524
536
|
init_defaults
|
|
525
|
-
} from "./cli-
|
|
526
|
-
import {
|
|
527
|
-
getSlackConfiguration,
|
|
528
|
-
init_config,
|
|
529
|
-
isSlackConfigured
|
|
530
|
-
} from "./cli-n7h1kqpf.js";
|
|
537
|
+
} from "./cli-yrg7c73k.js";
|
|
531
538
|
import {
|
|
532
539
|
deepInterpolate,
|
|
533
540
|
findInterpolationTokens,
|
|
@@ -538,7 +545,12 @@ import {
|
|
|
538
545
|
interpolate,
|
|
539
546
|
registerTemplate,
|
|
540
547
|
resolveTemplate
|
|
541
|
-
} from "./cli-
|
|
548
|
+
} from "./cli-ptr8h7kp.js";
|
|
549
|
+
import {
|
|
550
|
+
getSlackConfiguration,
|
|
551
|
+
init_config,
|
|
552
|
+
isSlackConfigured
|
|
553
|
+
} from "./cli-n7h1kqpf.js";
|
|
542
554
|
import {
|
|
543
555
|
MAX_PROFILE_FILE_LENGTH,
|
|
544
556
|
getAppUrl,
|
|
@@ -556,12 +568,13 @@ import {
|
|
|
556
568
|
claudeCatalogModelId,
|
|
557
569
|
harnessCatalogSection,
|
|
558
570
|
harnessModelIds,
|
|
571
|
+
harnessModelMismatch,
|
|
559
572
|
init_src,
|
|
560
573
|
isAlias,
|
|
561
574
|
modelFamilyKey,
|
|
562
575
|
parseAlias,
|
|
563
576
|
resolveAlias
|
|
564
|
-
} from "./cli-
|
|
577
|
+
} from "./cli-jyy6pm2f.js";
|
|
565
578
|
import {
|
|
566
579
|
exports_zod,
|
|
567
580
|
init_zod
|
|
@@ -610,7 +623,7 @@ import {
|
|
|
610
623
|
import {
|
|
611
624
|
init_package,
|
|
612
625
|
package_default
|
|
613
|
-
} from "./cli-
|
|
626
|
+
} from "./cli-a8c82p2t.js";
|
|
614
627
|
import {
|
|
615
628
|
init_secret_scrubber,
|
|
616
629
|
isSensitiveKey,
|
|
@@ -618,7 +631,7 @@ import {
|
|
|
618
631
|
registerVolatileSecret,
|
|
619
632
|
scrubObject,
|
|
620
633
|
scrubSecrets
|
|
621
|
-
} from "./cli-
|
|
634
|
+
} from "./cli-nexqx4ve.js";
|
|
622
635
|
import {
|
|
623
636
|
init_event_bus,
|
|
624
637
|
workflowEventBus
|
|
@@ -14349,7 +14362,7 @@ async function notifyAutomationPreflightFailure(preflight) {
|
|
|
14349
14362
|
return;
|
|
14350
14363
|
}
|
|
14351
14364
|
try {
|
|
14352
|
-
const { getSlackApp: getSlackApp2 } = await import("./app-
|
|
14365
|
+
const { getSlackApp: getSlackApp2 } = await import("./app-0hdqa4k1.js");
|
|
14353
14366
|
const app = getSlackApp2();
|
|
14354
14367
|
if (!app) {
|
|
14355
14368
|
console.warn("[Automation Preflight] Slack not available, cannot send notification");
|
|
@@ -17093,6 +17106,23 @@ async function verifyWebhookRequest(trigger, rawBody, headers) {
|
|
|
17093
17106
|
}
|
|
17094
17107
|
return;
|
|
17095
17108
|
}
|
|
17109
|
+
if (verification.format === "standard-webhooks") {
|
|
17110
|
+
const key = decodeStandardWebhookSecret(secret);
|
|
17111
|
+
if (!key) {
|
|
17112
|
+
throw new WebhookError("Webhook trigger `standard-webhooks` secret must be base64 (optionally prefixed with `whsec_`)", 500);
|
|
17113
|
+
}
|
|
17114
|
+
const id = getHeader(headers, "webhook-id");
|
|
17115
|
+
const timestamp = getHeader(headers, "webhook-timestamp");
|
|
17116
|
+
const signature2 = getHeader(headers, "webhook-signature");
|
|
17117
|
+
if (!id || !timestamp || !signature2) {
|
|
17118
|
+
throw new WebhookError("Missing signature", 401);
|
|
17119
|
+
}
|
|
17120
|
+
const isValid2 = verifyStandardWebhookSignature(key, rawBody, { id, timestamp, signature: signature2 }, { toleranceSeconds: verification.toleranceSeconds });
|
|
17121
|
+
if (!isValid2) {
|
|
17122
|
+
throw new WebhookError("Invalid signature", 401);
|
|
17123
|
+
}
|
|
17124
|
+
return;
|
|
17125
|
+
}
|
|
17096
17126
|
const header = verification.header || DEFAULT_HMAC_HEADER;
|
|
17097
17127
|
const signature = getHeader(headers, header);
|
|
17098
17128
|
if (!signature) {
|
|
@@ -17226,6 +17256,36 @@ function verifyTimestampedHmacSignature(secret, body, headerValue, opts = {}, no
|
|
|
17226
17256
|
const expected = Buffer.from(expectedHex, "hex");
|
|
17227
17257
|
return signatures.some((signature) => timingSafeEqualHex(signature, expected));
|
|
17228
17258
|
}
|
|
17259
|
+
var STANDARD_WEBHOOK_SECRET_PREFIX = "whsec_";
|
|
17260
|
+
function decodeStandardWebhookSecret(secret) {
|
|
17261
|
+
const encoded = secret.startsWith(STANDARD_WEBHOOK_SECRET_PREFIX) ? secret.slice(STANDARD_WEBHOOK_SECRET_PREFIX.length) : secret;
|
|
17262
|
+
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(encoded) || encoded.length % 4 === 1) {
|
|
17263
|
+
return null;
|
|
17264
|
+
}
|
|
17265
|
+
const key = Buffer.from(encoded, "base64");
|
|
17266
|
+
return key.length > 0 ? key : null;
|
|
17267
|
+
}
|
|
17268
|
+
function verifyStandardWebhookSignature(key, body, headers, opts = {}, nowMs = Date.now()) {
|
|
17269
|
+
const toleranceSeconds = opts.toleranceSeconds ?? 300;
|
|
17270
|
+
if (!/^\d+$/.test(headers.timestamp)) {
|
|
17271
|
+
return false;
|
|
17272
|
+
}
|
|
17273
|
+
const timestampSeconds = Number(headers.timestamp);
|
|
17274
|
+
if (!Number.isSafeInteger(timestampSeconds)) {
|
|
17275
|
+
return false;
|
|
17276
|
+
}
|
|
17277
|
+
if (Math.abs(nowMs / 1000 - timestampSeconds) > toleranceSeconds) {
|
|
17278
|
+
return false;
|
|
17279
|
+
}
|
|
17280
|
+
const expected = Buffer.from(crypto2.createHmac("sha256", key).update(`${headers.id}.${headers.timestamp}.${body}`).digest("base64"));
|
|
17281
|
+
return headers.signature.split(" ").some((entry) => {
|
|
17282
|
+
const separatorIndex = entry.indexOf(",");
|
|
17283
|
+
if (separatorIndex <= 0 || entry.slice(0, separatorIndex) !== "v1")
|
|
17284
|
+
return false;
|
|
17285
|
+
const provided = Buffer.from(entry.slice(separatorIndex + 1));
|
|
17286
|
+
return provided.length === expected.length && crypto2.timingSafeEqual(provided, expected);
|
|
17287
|
+
});
|
|
17288
|
+
}
|
|
17229
17289
|
function verifyTokenEquality(secret, providedToken) {
|
|
17230
17290
|
const secretDigest = crypto2.createHash("sha256").update(secret).digest();
|
|
17231
17291
|
const providedDigest = crypto2.createHash("sha256").update(providedToken).digest();
|
|
@@ -17601,22 +17661,45 @@ function taskModelCandidates(input) {
|
|
|
17601
17661
|
}
|
|
17602
17662
|
return candidates;
|
|
17603
17663
|
}
|
|
17664
|
+
function harnessMismatchReason(model, harness) {
|
|
17665
|
+
return `[model-harness-mismatch] Model "${model}" does not run on the ${harness} harness of this worker. The task pinned a model from another harness family. Re-create the task with modelTier or with a ${harness} model.`;
|
|
17666
|
+
}
|
|
17604
17667
|
async function resolveTaskModel(input) {
|
|
17668
|
+
const harness = input.harnessProvider ?? null;
|
|
17669
|
+
const judged = harness !== null && harnessCatalogSection(harness) !== null;
|
|
17670
|
+
const sections = judged ? (await loadResolutionCatalog()).catalog : {};
|
|
17605
17671
|
for (const candidate of taskModelCandidates(input)) {
|
|
17672
|
+
let resolution = null;
|
|
17606
17673
|
if (!isAlias(candidate.value)) {
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
const resolved = await resolveLatestAlias(candidate.value, input.now, {
|
|
17610
|
-
record: input.record
|
|
17611
|
-
});
|
|
17612
|
-
if (resolved) {
|
|
17613
|
-
return {
|
|
17614
|
-
resolvedModel: resolved,
|
|
17674
|
+
resolution = {
|
|
17675
|
+
resolvedModel: candidate.value,
|
|
17615
17676
|
modelSource: candidate.source,
|
|
17616
|
-
modelAlias:
|
|
17677
|
+
modelAlias: null
|
|
17617
17678
|
};
|
|
17679
|
+
} else {
|
|
17680
|
+
const resolved = await resolveLatestAlias(candidate.value, input.now, {
|
|
17681
|
+
record: input.record
|
|
17682
|
+
});
|
|
17683
|
+
if (resolved) {
|
|
17684
|
+
resolution = {
|
|
17685
|
+
resolvedModel: resolved,
|
|
17686
|
+
modelSource: candidate.source,
|
|
17687
|
+
modelAlias: candidate.value.trim().toLowerCase()
|
|
17688
|
+
};
|
|
17689
|
+
}
|
|
17618
17690
|
}
|
|
17619
|
-
|
|
17691
|
+
if (!resolution) {
|
|
17692
|
+
console.warn(`[model-tiers] ${candidate.source} alias ${candidate.value} resolved to nothing; trying next layer`);
|
|
17693
|
+
continue;
|
|
17694
|
+
}
|
|
17695
|
+
if (judged && harnessModelMismatch(resolution.resolvedModel, harness, sections)) {
|
|
17696
|
+
if (candidate.source === "model") {
|
|
17697
|
+
return { harnessMismatch: harnessMismatchReason(candidate.value, harness) };
|
|
17698
|
+
}
|
|
17699
|
+
console.warn(`[model-tiers] ${candidate.source} value ${candidate.value} does not run on ${harness}; trying next layer`);
|
|
17700
|
+
continue;
|
|
17701
|
+
}
|
|
17702
|
+
return resolution;
|
|
17620
17703
|
}
|
|
17621
17704
|
return null;
|
|
17622
17705
|
}
|
|
@@ -17636,15 +17719,16 @@ async function previewModelTiers(opts = {}) {
|
|
|
17636
17719
|
now: opts.now,
|
|
17637
17720
|
record: false
|
|
17638
17721
|
});
|
|
17722
|
+
const previewed = resolution && "harnessMismatch" in resolution ? null : resolution;
|
|
17639
17723
|
rows.push({
|
|
17640
17724
|
provider,
|
|
17641
17725
|
tier,
|
|
17642
17726
|
key,
|
|
17643
17727
|
defaultValue: DEFAULT_MODEL_TIER_MAP[provider][tier],
|
|
17644
17728
|
configured,
|
|
17645
|
-
source:
|
|
17646
|
-
resolvedModel:
|
|
17647
|
-
alias:
|
|
17729
|
+
source: previewed?.modelSource === "tier-config" ? "tier-config" : "tier-default",
|
|
17730
|
+
resolvedModel: previewed?.resolvedModel ?? null,
|
|
17731
|
+
alias: previewed?.modelAlias ?? null
|
|
17648
17732
|
});
|
|
17649
17733
|
}
|
|
17650
17734
|
}
|
|
@@ -17678,6 +17762,8 @@ async function recordClaimModelResolution(task, agent) {
|
|
|
17678
17762
|
});
|
|
17679
17763
|
if (!resolved)
|
|
17680
17764
|
return {};
|
|
17765
|
+
if ("harnessMismatch" in resolved)
|
|
17766
|
+
return { modelUnsupported: resolved.harnessMismatch };
|
|
17681
17767
|
const checked = await applyCliSupport(resolved, harnessProvider, await getAgentHarnessCliVersion(agent.id));
|
|
17682
17768
|
if ("unsupported" in checked) {
|
|
17683
17769
|
return { modelUnsupported: checked.unsupported };
|
|
@@ -17716,12 +17802,31 @@ function isKnownCatalogModel(model, catalog) {
|
|
|
17716
17802
|
const anthropic = catalog.anthropic?.models;
|
|
17717
17803
|
return Object.hasOwn(buildClaudeShortnameMap(anthropic), id);
|
|
17718
17804
|
}
|
|
17805
|
+
async function harnessModelErrorFor(model, harness) {
|
|
17806
|
+
const { providers } = await loadModelsCatalog();
|
|
17807
|
+
return harnessModelMismatch(model, harness, providers, {});
|
|
17808
|
+
}
|
|
17809
|
+
async function poolTaskRunsOnHarness(task, harness) {
|
|
17810
|
+
const model = task?.model?.trim();
|
|
17811
|
+
if (!model)
|
|
17812
|
+
return true;
|
|
17813
|
+
return await harnessModelErrorFor(model, harness) === null;
|
|
17814
|
+
}
|
|
17719
17815
|
async function explicitModelError(check) {
|
|
17720
17816
|
const model = check.model?.trim();
|
|
17721
|
-
if (!model
|
|
17817
|
+
if (!model)
|
|
17722
17818
|
return null;
|
|
17723
17819
|
if (check.harnessProvider && FREE_FORM_HARNESSES.has(check.harnessProvider))
|
|
17724
17820
|
return null;
|
|
17821
|
+
const { providers } = await loadModelsCatalog();
|
|
17822
|
+
const catalog = providers;
|
|
17823
|
+
if (check.harnessProvider) {
|
|
17824
|
+
const mismatch = harnessModelMismatch(model, check.harnessProvider, catalog, { agentId: check.agentId, agentName: check.agentName });
|
|
17825
|
+
if (mismatch)
|
|
17826
|
+
return mismatch;
|
|
17827
|
+
}
|
|
17828
|
+
if (check.allowCustomModel)
|
|
17829
|
+
return null;
|
|
17725
17830
|
if (isAlias(model)) {
|
|
17726
17831
|
if (!parseAlias(model)) {
|
|
17727
17832
|
return `Invalid model alias "${model}". Use latest:<provider>/<family>[@stable|@any], e.g. latest:anthropic/opus.`;
|
|
@@ -17729,8 +17834,6 @@ async function explicitModelError(check) {
|
|
|
17729
17834
|
const resolved = await resolveLatestAlias(model, new Date, { record: false });
|
|
17730
17835
|
return resolved ? null : `Model alias "${model}" matches no model in the catalog. Check the provider and family, or use a concrete model id.`;
|
|
17731
17836
|
}
|
|
17732
|
-
const { providers } = await loadModelsCatalog();
|
|
17733
|
-
const catalog = providers;
|
|
17734
17837
|
if (Object.keys(catalog).length === 0)
|
|
17735
17838
|
return null;
|
|
17736
17839
|
if (isKnownCatalogModel(model, catalog))
|
|
@@ -17738,10 +17841,40 @@ async function explicitModelError(check) {
|
|
|
17738
17841
|
return `Unknown model "${model}": it is not in the model catalog. Use a catalog model id, a Claude CLI shortname (opus, sonnet, haiku, fable), a latest:<provider>/<family> alias, or modelTier. To run a custom model id anyway, set allowCustomModel: true (allow_custom_model on the agent runtime).`;
|
|
17739
17842
|
}
|
|
17740
17843
|
async function explicitModelErrorForAgent(check) {
|
|
17741
|
-
|
|
17844
|
+
const model = check.model?.trim();
|
|
17845
|
+
if (!model)
|
|
17742
17846
|
return null;
|
|
17743
17847
|
const agent = check.agentId ? await getAgentById(check.agentId) : null;
|
|
17744
|
-
|
|
17848
|
+
if (agent) {
|
|
17849
|
+
return explicitModelError({
|
|
17850
|
+
...check,
|
|
17851
|
+
agentId: agent.id,
|
|
17852
|
+
agentName: agent.name,
|
|
17853
|
+
harnessProvider: agent.harnessProvider ?? agent.provider ?? null
|
|
17854
|
+
});
|
|
17855
|
+
}
|
|
17856
|
+
if (!check.agentId && !isAlias(model)) {
|
|
17857
|
+
const poolError = await poolHarnessModelError(model);
|
|
17858
|
+
if (poolError)
|
|
17859
|
+
return poolError;
|
|
17860
|
+
}
|
|
17861
|
+
return explicitModelError({ ...check, harnessProvider: null });
|
|
17862
|
+
}
|
|
17863
|
+
async function poolHarnessModelError(model) {
|
|
17864
|
+
const agents = await getAllAgents({ slim: true });
|
|
17865
|
+
if (agents.length === 0)
|
|
17866
|
+
return null;
|
|
17867
|
+
const { providers } = await loadModelsCatalog();
|
|
17868
|
+
const sections = providers;
|
|
17869
|
+
const harnesses = new Set;
|
|
17870
|
+
for (const agent of agents) {
|
|
17871
|
+
const harness = agent.harnessProvider ?? agent.provider ?? null;
|
|
17872
|
+
if (!harnessModelMismatch(model, harness, sections))
|
|
17873
|
+
return null;
|
|
17874
|
+
if (harness)
|
|
17875
|
+
harnesses.add(harness);
|
|
17876
|
+
}
|
|
17877
|
+
return `Model "${model}" does not run on any registered agent harness (${[...harnesses].sort().join(", ")}). Use modelTier (smol, regular, smart, ultra) for portable intent, or omit model and let the claiming agent resolve it.`;
|
|
17745
17878
|
}
|
|
17746
17879
|
|
|
17747
17880
|
// src/extensions/apply-task-create.ts
|
|
@@ -17969,7 +18102,8 @@ async function prepareTaskWithSiblingAwareness(description, options, args = {})
|
|
|
17969
18102
|
const preCreate = await applyPreTaskCreate({
|
|
17970
18103
|
description,
|
|
17971
18104
|
options,
|
|
17972
|
-
origin: args.origin ?? "rest"
|
|
18105
|
+
origin: args.origin ?? "rest",
|
|
18106
|
+
allowCustomModel: args.allowCustomModel
|
|
17973
18107
|
});
|
|
17974
18108
|
if (preCreate.kind === "blocked") {
|
|
17975
18109
|
throw new TaskCreationBlockedError(preCreate.reason, preCreate.extension);
|
|
@@ -24030,6 +24164,10 @@ init_steering();
|
|
|
24030
24164
|
|
|
24031
24165
|
// src/github/task-reactions.ts
|
|
24032
24166
|
init_task_lifecycle_events();
|
|
24167
|
+
init_secret_scrubber();
|
|
24168
|
+
|
|
24169
|
+
// src/github/reactions.ts
|
|
24170
|
+
init_secret_scrubber();
|
|
24033
24171
|
|
|
24034
24172
|
// src/github/app.ts
|
|
24035
24173
|
var initialized = false;
|
|
@@ -24181,18 +24319,25 @@ async function getInstallationToken(installationId) {
|
|
|
24181
24319
|
}
|
|
24182
24320
|
|
|
24183
24321
|
// src/github/reactions.ts
|
|
24184
|
-
async function
|
|
24185
|
-
if (
|
|
24186
|
-
|
|
24187
|
-
|
|
24188
|
-
|
|
24189
|
-
|
|
24190
|
-
|
|
24191
|
-
|
|
24322
|
+
async function resolveReactionToken(installationId) {
|
|
24323
|
+
if (installationId && isReactionsEnabled()) {
|
|
24324
|
+
const appToken = await getInstallationToken(installationId);
|
|
24325
|
+
if (appToken)
|
|
24326
|
+
return appToken;
|
|
24327
|
+
console.log("[GitHub] No installation token, trying GITHUB_TOKEN for reaction");
|
|
24328
|
+
}
|
|
24329
|
+
const pat = process.env.GITHUB_TOKEN?.trim();
|
|
24330
|
+
if (pat)
|
|
24331
|
+
return pat;
|
|
24332
|
+
console.log("[GitHub] No App installation and no GITHUB_TOKEN, skipping reaction");
|
|
24333
|
+
return null;
|
|
24334
|
+
}
|
|
24335
|
+
async function postRestReaction(repo, target, reaction, installationId, label) {
|
|
24336
|
+
const token = await resolveReactionToken(installationId);
|
|
24337
|
+
if (!token)
|
|
24192
24338
|
return false;
|
|
24193
|
-
}
|
|
24194
24339
|
try {
|
|
24195
|
-
const response = await fetch(`https://api.github.com/repos/${repo}
|
|
24340
|
+
const response = await fetch(`https://api.github.com/repos/${repo}/${target}/reactions`, {
|
|
24196
24341
|
method: "POST",
|
|
24197
24342
|
headers: {
|
|
24198
24343
|
Accept: "application/vnd.github+json",
|
|
@@ -24204,92 +24349,29 @@ async function addReaction(repo, commentId, reaction, installationId) {
|
|
|
24204
24349
|
});
|
|
24205
24350
|
if (!response.ok) {
|
|
24206
24351
|
const errorText2 = await response.text();
|
|
24207
|
-
console.error(`[GitHub] Failed to add reaction: ${response.status} ${errorText2}`);
|
|
24352
|
+
console.error(`[GitHub] Failed to add ${label} reaction: ${response.status} ${scrubSecrets(errorText2)}`);
|
|
24208
24353
|
return false;
|
|
24209
24354
|
}
|
|
24210
|
-
console.log(`[GitHub] Added ${reaction} reaction to
|
|
24355
|
+
console.log(`[GitHub] Added ${reaction} reaction to ${label}`);
|
|
24211
24356
|
return true;
|
|
24212
24357
|
} catch (error) {
|
|
24213
|
-
console.error(
|
|
24358
|
+
console.error(`[GitHub] Error adding ${label} reaction:`, scrubSecrets(error instanceof Error ? error.message : String(error)));
|
|
24214
24359
|
return false;
|
|
24215
24360
|
}
|
|
24216
24361
|
}
|
|
24362
|
+
async function addReaction(repo, commentId, reaction, installationId) {
|
|
24363
|
+
return postRestReaction(repo, `issues/comments/${commentId}`, reaction, installationId, `comment ${commentId}`);
|
|
24364
|
+
}
|
|
24217
24365
|
async function addIssueReaction(repo, issueNumber, reaction, installationId) {
|
|
24218
|
-
|
|
24219
|
-
console.log("[GitHub] Reactions not enabled, skipping");
|
|
24220
|
-
return false;
|
|
24221
|
-
}
|
|
24222
|
-
const token = await getInstallationToken(installationId);
|
|
24223
|
-
if (!token) {
|
|
24224
|
-
console.log("[GitHub] No installation token, skipping reaction");
|
|
24225
|
-
return false;
|
|
24226
|
-
}
|
|
24227
|
-
try {
|
|
24228
|
-
const response = await fetch(`https://api.github.com/repos/${repo}/issues/${issueNumber}/reactions`, {
|
|
24229
|
-
method: "POST",
|
|
24230
|
-
headers: {
|
|
24231
|
-
Accept: "application/vnd.github+json",
|
|
24232
|
-
Authorization: `Bearer ${token}`,
|
|
24233
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
24234
|
-
"Content-Type": "application/json"
|
|
24235
|
-
},
|
|
24236
|
-
body: JSON.stringify({ content: reaction })
|
|
24237
|
-
});
|
|
24238
|
-
if (!response.ok) {
|
|
24239
|
-
const errorText2 = await response.text();
|
|
24240
|
-
console.error(`[GitHub] Failed to add issue reaction: ${response.status} ${errorText2}`);
|
|
24241
|
-
return false;
|
|
24242
|
-
}
|
|
24243
|
-
console.log(`[GitHub] Added ${reaction} reaction to issue/PR #${issueNumber}`);
|
|
24244
|
-
return true;
|
|
24245
|
-
} catch (error) {
|
|
24246
|
-
console.error("[GitHub] Error adding issue reaction:", error);
|
|
24247
|
-
return false;
|
|
24248
|
-
}
|
|
24366
|
+
return postRestReaction(repo, `issues/${issueNumber}`, reaction, installationId, `issue/PR #${issueNumber}`);
|
|
24249
24367
|
}
|
|
24250
24368
|
async function addPullReviewCommentReaction(repo, commentId, reaction, installationId) {
|
|
24251
|
-
|
|
24252
|
-
console.log("[GitHub] Reactions not enabled, skipping");
|
|
24253
|
-
return false;
|
|
24254
|
-
}
|
|
24255
|
-
const token = await getInstallationToken(installationId);
|
|
24256
|
-
if (!token) {
|
|
24257
|
-
console.log("[GitHub] No installation token, skipping reaction");
|
|
24258
|
-
return false;
|
|
24259
|
-
}
|
|
24260
|
-
try {
|
|
24261
|
-
const response = await fetch(`https://api.github.com/repos/${repo}/pulls/comments/${commentId}/reactions`, {
|
|
24262
|
-
method: "POST",
|
|
24263
|
-
headers: {
|
|
24264
|
-
Accept: "application/vnd.github+json",
|
|
24265
|
-
Authorization: `Bearer ${token}`,
|
|
24266
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
24267
|
-
"Content-Type": "application/json"
|
|
24268
|
-
},
|
|
24269
|
-
body: JSON.stringify({ content: reaction })
|
|
24270
|
-
});
|
|
24271
|
-
if (!response.ok) {
|
|
24272
|
-
const errorText2 = await response.text();
|
|
24273
|
-
console.error(`[GitHub] Failed to add PR review comment reaction: ${response.status} ${errorText2}`);
|
|
24274
|
-
return false;
|
|
24275
|
-
}
|
|
24276
|
-
console.log(`[GitHub] Added ${reaction} reaction to PR review comment ${commentId}`);
|
|
24277
|
-
return true;
|
|
24278
|
-
} catch (error) {
|
|
24279
|
-
console.error("[GitHub] Error adding PR review comment reaction:", error);
|
|
24280
|
-
return false;
|
|
24281
|
-
}
|
|
24369
|
+
return postRestReaction(repo, `pulls/comments/${commentId}`, reaction, installationId, `PR review comment ${commentId}`);
|
|
24282
24370
|
}
|
|
24283
24371
|
async function addGraphQLReaction(nodeId, reaction, installationId) {
|
|
24284
|
-
|
|
24285
|
-
|
|
24286
|
-
return false;
|
|
24287
|
-
}
|
|
24288
|
-
const token = await getInstallationToken(installationId);
|
|
24289
|
-
if (!token) {
|
|
24290
|
-
console.log("[GitHub] No installation token, skipping GraphQL reaction");
|
|
24372
|
+
const token = await resolveReactionToken(installationId);
|
|
24373
|
+
if (!token)
|
|
24291
24374
|
return false;
|
|
24292
|
-
}
|
|
24293
24375
|
try {
|
|
24294
24376
|
const response = await fetch("https://api.github.com/graphql", {
|
|
24295
24377
|
method: "POST",
|
|
@@ -24310,28 +24392,26 @@ async function addGraphQLReaction(nodeId, reaction, installationId) {
|
|
|
24310
24392
|
});
|
|
24311
24393
|
if (!response.ok) {
|
|
24312
24394
|
const errorText2 = await response.text();
|
|
24313
|
-
console.error(`[GitHub] GraphQL reaction failed: ${response.status} ${errorText2}`);
|
|
24395
|
+
console.error(`[GitHub] GraphQL reaction failed: ${response.status} ${scrubSecrets(errorText2)}`);
|
|
24314
24396
|
return false;
|
|
24315
24397
|
}
|
|
24316
24398
|
const data = await response.json();
|
|
24317
24399
|
if (data.errors?.length) {
|
|
24318
|
-
console.error(`[GitHub] GraphQL reaction errors: ${JSON.stringify(data.errors)}`);
|
|
24400
|
+
console.error(`[GitHub] GraphQL reaction errors: ${scrubSecrets(JSON.stringify(data.errors))}`);
|
|
24319
24401
|
return false;
|
|
24320
24402
|
}
|
|
24321
24403
|
console.log(`[GitHub] Added ${reaction} GraphQL reaction to node ${nodeId}`);
|
|
24322
24404
|
return true;
|
|
24323
24405
|
} catch (error) {
|
|
24324
|
-
console.error("[GitHub] Error adding GraphQL reaction:", error);
|
|
24406
|
+
console.error("[GitHub] Error adding GraphQL reaction:", scrubSecrets(error instanceof Error ? error.message : String(error)));
|
|
24325
24407
|
return false;
|
|
24326
24408
|
}
|
|
24327
24409
|
}
|
|
24328
24410
|
|
|
24329
24411
|
// src/github/task-reactions.ts
|
|
24330
|
-
async function
|
|
24412
|
+
async function addEyesReactionToTaskSource(task) {
|
|
24331
24413
|
if (task.source !== "github" || task.vcsProvider !== "github")
|
|
24332
24414
|
return;
|
|
24333
|
-
if (!task.vcsInstallationId)
|
|
24334
|
-
return;
|
|
24335
24415
|
const installationId = task.vcsInstallationId;
|
|
24336
24416
|
const repo = task.vcsRepo;
|
|
24337
24417
|
if (!repo)
|
|
@@ -24353,6 +24433,8 @@ async function addEyesReactionOnTaskStart(task) {
|
|
|
24353
24433
|
case "pull_request_review": {
|
|
24354
24434
|
if (task.vcsNodeId) {
|
|
24355
24435
|
await addGraphQLReaction(task.vcsNodeId, "EYES", installationId);
|
|
24436
|
+
} else if (task.vcsNumber) {
|
|
24437
|
+
await addIssueReaction(repo, task.vcsNumber, "eyes", installationId);
|
|
24356
24438
|
}
|
|
24357
24439
|
break;
|
|
24358
24440
|
}
|
|
@@ -24365,9 +24447,12 @@ async function addEyesReactionOnTaskStart(task) {
|
|
|
24365
24447
|
}
|
|
24366
24448
|
}
|
|
24367
24449
|
} catch (error) {
|
|
24368
|
-
console.error("[GitHub] Failed to add eyes reaction
|
|
24450
|
+
console.error("[GitHub] Failed to add eyes reaction:", scrubSecrets(error instanceof Error ? error.message : String(error)));
|
|
24369
24451
|
}
|
|
24370
24452
|
}
|
|
24453
|
+
async function addEyesReactionOnTaskStart(task) {
|
|
24454
|
+
await addEyesReactionToTaskSource(task);
|
|
24455
|
+
}
|
|
24371
24456
|
var registered = false;
|
|
24372
24457
|
function registerGithubTaskReactions() {
|
|
24373
24458
|
if (registered)
|
|
@@ -25230,6 +25315,510 @@ async function handleMessageReceived(payload) {
|
|
|
25230
25315
|
console.log(`[AgentMail] Created unassigned task ${task.id} (no lead or mapping available)`);
|
|
25231
25316
|
return { created: true, taskId: task.id };
|
|
25232
25317
|
}
|
|
25318
|
+
// src/azure-devops/auth.ts
|
|
25319
|
+
init_env_flag();
|
|
25320
|
+
var initialized3 = false;
|
|
25321
|
+
var webhookSecret3 = null;
|
|
25322
|
+
var apiToken = null;
|
|
25323
|
+
var orgUrl = null;
|
|
25324
|
+
function isAzureDevOpsEnabled() {
|
|
25325
|
+
return !!process.env.AZURE_DEVOPS_WEBHOOK_SECRET && !isEnvFlagEnabled("AZURE_DEVOPS_DISABLE", false);
|
|
25326
|
+
}
|
|
25327
|
+
function initAzureDevOps() {
|
|
25328
|
+
if (initialized3)
|
|
25329
|
+
return;
|
|
25330
|
+
if (!isAzureDevOpsEnabled()) {
|
|
25331
|
+
console.log("[AzureDevOps] Integration disabled (AZURE_DEVOPS_WEBHOOK_SECRET not set)");
|
|
25332
|
+
return;
|
|
25333
|
+
}
|
|
25334
|
+
webhookSecret3 = process.env.AZURE_DEVOPS_WEBHOOK_SECRET;
|
|
25335
|
+
apiToken = process.env.AZURE_DEVOPS_TOKEN ?? null;
|
|
25336
|
+
orgUrl = normalizeOrgUrl(process.env.AZURE_DEVOPS_ORG_URL);
|
|
25337
|
+
initialized3 = true;
|
|
25338
|
+
console.log(`[AzureDevOps] Integration initialized (org: ${orgUrl ?? "from payload"})`);
|
|
25339
|
+
}
|
|
25340
|
+
function verifyAzureDevOpsWebhook(authorizationHeader) {
|
|
25341
|
+
if (!webhookSecret3)
|
|
25342
|
+
return false;
|
|
25343
|
+
if (!authorizationHeader?.startsWith("Basic "))
|
|
25344
|
+
return false;
|
|
25345
|
+
const decoded = Buffer.from(authorizationHeader.slice("Basic ".length), "base64").toString();
|
|
25346
|
+
const separator = decoded.indexOf(":");
|
|
25347
|
+
if (separator === -1)
|
|
25348
|
+
return false;
|
|
25349
|
+
const password = decoded.slice(separator + 1);
|
|
25350
|
+
if (password.length !== webhookSecret3.length)
|
|
25351
|
+
return false;
|
|
25352
|
+
return crypto.timingSafeEqual(Buffer.from(password), Buffer.from(webhookSecret3));
|
|
25353
|
+
}
|
|
25354
|
+
function getAzureDevOpsToken() {
|
|
25355
|
+
return apiToken;
|
|
25356
|
+
}
|
|
25357
|
+
function getAzureDevOpsOrgUrl() {
|
|
25358
|
+
return orgUrl;
|
|
25359
|
+
}
|
|
25360
|
+
function normalizeOrgUrl(url) {
|
|
25361
|
+
const trimmed = url?.trim().replace(/\/+$/, "");
|
|
25362
|
+
return trimmed ? trimmed : null;
|
|
25363
|
+
}
|
|
25364
|
+
var AZURE_DEVOPS_BOT_NAME = process.env.AZURE_DEVOPS_BOT_NAME ?? "agent-swarm-bot";
|
|
25365
|
+
function resetAzureDevOps() {
|
|
25366
|
+
initialized3 = false;
|
|
25367
|
+
webhookSecret3 = null;
|
|
25368
|
+
apiToken = null;
|
|
25369
|
+
orgUrl = null;
|
|
25370
|
+
}
|
|
25371
|
+
|
|
25372
|
+
// src/azure-devops/api.ts
|
|
25373
|
+
var API_VERSION = "7.1";
|
|
25374
|
+
function headers() {
|
|
25375
|
+
const token = getAzureDevOpsToken();
|
|
25376
|
+
if (!token)
|
|
25377
|
+
throw new Error("[AzureDevOps] No API token configured");
|
|
25378
|
+
return {
|
|
25379
|
+
Authorization: `Basic ${Buffer.from(`:${token}`).toString("base64")}`,
|
|
25380
|
+
"Content-Type": "application/json",
|
|
25381
|
+
Accept: "application/json"
|
|
25382
|
+
};
|
|
25383
|
+
}
|
|
25384
|
+
function pullRequestBase(ref) {
|
|
25385
|
+
return `${ref.orgUrl}/${encodeURIComponent(ref.projectId)}/_apis/git/repositories/` + `${encodeURIComponent(ref.repositoryId)}/pullRequests/${ref.pullRequestId}`;
|
|
25386
|
+
}
|
|
25387
|
+
var cachedBotId = null;
|
|
25388
|
+
async function resolveAzureDevOpsBotId(orgBaseUrl) {
|
|
25389
|
+
const fromEnv = process.env.AZURE_DEVOPS_BOT_ID?.trim();
|
|
25390
|
+
if (fromEnv)
|
|
25391
|
+
return fromEnv;
|
|
25392
|
+
const orgUrl2 = normalizeOrgUrl(orgBaseUrl) ?? getAzureDevOpsOrgUrl();
|
|
25393
|
+
if (!orgUrl2 || !getAzureDevOpsToken())
|
|
25394
|
+
return null;
|
|
25395
|
+
if (cachedBotId?.orgUrl === orgUrl2)
|
|
25396
|
+
return cachedBotId.id;
|
|
25397
|
+
try {
|
|
25398
|
+
const resp = await fetch(`${orgUrl2}/_apis/connectionData`, { headers: headers() });
|
|
25399
|
+
if (!resp.ok) {
|
|
25400
|
+
console.error(`[AzureDevOps] Failed to resolve bot identity: ${resp.status}`);
|
|
25401
|
+
return null;
|
|
25402
|
+
}
|
|
25403
|
+
const data = await resp.json();
|
|
25404
|
+
const id = data.authenticatedUser?.id;
|
|
25405
|
+
if (!id)
|
|
25406
|
+
return null;
|
|
25407
|
+
cachedBotId = { orgUrl: orgUrl2, id };
|
|
25408
|
+
return id;
|
|
25409
|
+
} catch (err) {
|
|
25410
|
+
console.error(`[AzureDevOps] Error resolving bot identity:`, err);
|
|
25411
|
+
return null;
|
|
25412
|
+
}
|
|
25413
|
+
}
|
|
25414
|
+
function resetAzureDevOpsBotIdCache() {
|
|
25415
|
+
cachedBotId = null;
|
|
25416
|
+
}
|
|
25417
|
+
async function likeAzureDevOpsComment(ref, threadId, commentId) {
|
|
25418
|
+
const url = `${pullRequestBase(ref)}/threads/${threadId}/comments/${commentId}/likes?api-version=${API_VERSION}`;
|
|
25419
|
+
try {
|
|
25420
|
+
const resp = await fetch(url, { method: "POST", headers: headers() });
|
|
25421
|
+
if (!resp.ok) {
|
|
25422
|
+
console.error(`[AzureDevOps] Failed to like comment: ${resp.status} ${await resp.text()}`);
|
|
25423
|
+
}
|
|
25424
|
+
} catch (err) {
|
|
25425
|
+
console.error(`[AzureDevOps] Error liking comment:`, err);
|
|
25426
|
+
}
|
|
25427
|
+
}
|
|
25428
|
+
// src/azure-devops/handlers.ts
|
|
25429
|
+
init_db();
|
|
25430
|
+
init_resolver();
|
|
25431
|
+
init_context_key();
|
|
25432
|
+
|
|
25433
|
+
// src/vcs/azure-devops.ts
|
|
25434
|
+
function isAzureDevOpsUrl(url) {
|
|
25435
|
+
return /(^|[/@.])dev\.azure\.com[/:]|\.visualstudio\.com[/:]/i.test(url);
|
|
25436
|
+
}
|
|
25437
|
+
function canonicalAzureDevOpsRepoUrl(url) {
|
|
25438
|
+
const trimmed = url.trim();
|
|
25439
|
+
const ssh = trimmed.match(/^(?:ssh:\/\/)?[^@]+@ssh\.dev\.azure\.com[:/]v3\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
25440
|
+
if (ssh)
|
|
25441
|
+
return `https://dev.azure.com/${ssh[1]}/${ssh[2]}/_git/${ssh[3]}`;
|
|
25442
|
+
let parsed;
|
|
25443
|
+
try {
|
|
25444
|
+
parsed = new URL(trimmed);
|
|
25445
|
+
} catch {
|
|
25446
|
+
return trimmed;
|
|
25447
|
+
}
|
|
25448
|
+
parsed.username = "";
|
|
25449
|
+
parsed.password = "";
|
|
25450
|
+
parsed.search = "";
|
|
25451
|
+
parsed.hash = "";
|
|
25452
|
+
const parts = parsed.pathname.replace(/\.git\/?$/, "").split("/").filter(Boolean);
|
|
25453
|
+
if (parsed.hostname === "dev.azure.com" && parts.length === 3 && parts[1] === "_git") {
|
|
25454
|
+
parts.splice(1, 0, parts[2]);
|
|
25455
|
+
}
|
|
25456
|
+
parsed.pathname = `/${parts.join("/")}`;
|
|
25457
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
25458
|
+
}
|
|
25459
|
+
function parseAzureDevOpsRepoUrl(url) {
|
|
25460
|
+
const canonical = canonicalAzureDevOpsRepoUrl(url);
|
|
25461
|
+
let parsed;
|
|
25462
|
+
try {
|
|
25463
|
+
parsed = new URL(canonical);
|
|
25464
|
+
} catch {
|
|
25465
|
+
return null;
|
|
25466
|
+
}
|
|
25467
|
+
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
25468
|
+
const gitIndex = parts.indexOf("_git");
|
|
25469
|
+
const repository = parts[gitIndex + 1];
|
|
25470
|
+
if (gitIndex < 1 || !repository) {
|
|
25471
|
+
if (gitIndex === 0 && repository) {
|
|
25472
|
+
return { orgUrl: parsed.origin, project: repository, repository };
|
|
25473
|
+
}
|
|
25474
|
+
return null;
|
|
25475
|
+
}
|
|
25476
|
+
const collectionOnly = parts[gitIndex - 1]?.toLowerCase() === "defaultcollection";
|
|
25477
|
+
const project = collectionOnly ? repository : parts[gitIndex - 1];
|
|
25478
|
+
const orgPath = parts.slice(0, collectionOnly ? gitIndex : gitIndex - 1).join("/");
|
|
25479
|
+
return {
|
|
25480
|
+
orgUrl: orgPath ? `${parsed.origin}/${orgPath}` : parsed.origin,
|
|
25481
|
+
project: decodeURIComponent(project),
|
|
25482
|
+
repository: decodeURIComponent(repository)
|
|
25483
|
+
};
|
|
25484
|
+
}
|
|
25485
|
+
|
|
25486
|
+
// src/azure-devops/templates.ts
|
|
25487
|
+
init_registry();
|
|
25488
|
+
registerTemplate({
|
|
25489
|
+
eventType: "common.delegation_instruction.azure_devops",
|
|
25490
|
+
header: "",
|
|
25491
|
+
defaultBody: "\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.",
|
|
25492
|
+
variables: [],
|
|
25493
|
+
category: "common"
|
|
25494
|
+
});
|
|
25495
|
+
registerTemplate({
|
|
25496
|
+
eventType: "common.command_suggestions.azure_devops_pr",
|
|
25497
|
+
header: "",
|
|
25498
|
+
defaultBody: '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`.',
|
|
25499
|
+
variables: [
|
|
25500
|
+
{ name: "pr_id", description: "Pull request ID" },
|
|
25501
|
+
{ name: "project", description: "Azure DevOps project name" },
|
|
25502
|
+
{ name: "repository", description: "Azure Repos repository name" }
|
|
25503
|
+
],
|
|
25504
|
+
category: "common"
|
|
25505
|
+
});
|
|
25506
|
+
var SHARED_VARIABLES = [
|
|
25507
|
+
{ name: "pr_id", description: "Pull request ID" },
|
|
25508
|
+
{ name: "pr_title", description: "Pull request title" },
|
|
25509
|
+
{
|
|
25510
|
+
name: "repo",
|
|
25511
|
+
description: "Repository clone URL (https://dev.azure.com/<org>/<project>/_git/<repo>)"
|
|
25512
|
+
},
|
|
25513
|
+
{ name: "project", description: "Azure DevOps project name" },
|
|
25514
|
+
{ name: "repository", description: "Azure Repos repository name" },
|
|
25515
|
+
{ name: "pr_url", description: "Pull request web URL" }
|
|
25516
|
+
];
|
|
25517
|
+
registerTemplate({
|
|
25518
|
+
eventType: "azure-devops.pull_request.opened",
|
|
25519
|
+
header: "[Azure DevOps PR #{{pr_id}}] {{pr_title}}",
|
|
25520
|
+
defaultBody: `Repo: {{repo}}
|
|
25521
|
+
Author: {{username}}
|
|
25522
|
+
Branch: {{source_branch}} → {{target_branch}}
|
|
25523
|
+
URL: {{pr_url}}
|
|
25524
|
+
|
|
25525
|
+
{{context_section}}{{@template[common.command_suggestions.azure_devops_pr]}}{{@template[common.delegation_instruction.azure_devops]}}`,
|
|
25526
|
+
variables: [
|
|
25527
|
+
...SHARED_VARIABLES,
|
|
25528
|
+
{
|
|
25529
|
+
name: "username",
|
|
25530
|
+
description: "Author identity — resolved canonical name (e.g. 'Luis (azure-devops:luis@example.com)') or the UNKNOWN sentinel"
|
|
25531
|
+
},
|
|
25532
|
+
{ name: "source_branch", description: "Source branch name" },
|
|
25533
|
+
{ name: "target_branch", description: "Target branch name" },
|
|
25534
|
+
{ name: "context_section", description: "Context section with description or empty string" }
|
|
25535
|
+
],
|
|
25536
|
+
category: "event"
|
|
25537
|
+
});
|
|
25538
|
+
registerTemplate({
|
|
25539
|
+
eventType: "azure-devops.comment.mentioned",
|
|
25540
|
+
header: "[Azure DevOps Comment on PR #{{pr_id}}] {{username}} mentioned bot",
|
|
25541
|
+
defaultBody: `Repo: {{repo}}
|
|
25542
|
+
PR: {{pr_title}}
|
|
25543
|
+
URL: {{pr_url}}
|
|
25544
|
+
|
|
25545
|
+
Comment:
|
|
25546
|
+
{{context}}{{existing_task_note}}
|
|
25547
|
+
|
|
25548
|
+
{{@template[common.command_suggestions.azure_devops_pr]}}{{@template[common.delegation_instruction.azure_devops]}}`,
|
|
25549
|
+
variables: [
|
|
25550
|
+
...SHARED_VARIABLES,
|
|
25551
|
+
{
|
|
25552
|
+
name: "username",
|
|
25553
|
+
description: "Comment author identity — resolved canonical name (e.g. 'Luis (azure-devops:luis@example.com)') or the UNKNOWN sentinel"
|
|
25554
|
+
},
|
|
25555
|
+
{ name: "context", description: "Extracted mention context from comment" },
|
|
25556
|
+
{
|
|
25557
|
+
name: "existing_task_note",
|
|
25558
|
+
description: "Note about existing active task, or empty string"
|
|
25559
|
+
}
|
|
25560
|
+
],
|
|
25561
|
+
category: "event"
|
|
25562
|
+
});
|
|
25563
|
+
|
|
25564
|
+
// src/azure-devops/handlers.ts
|
|
25565
|
+
var processedEvents2 = new Map;
|
|
25566
|
+
var DEDUP_TTL_MS = 60000;
|
|
25567
|
+
function isDuplicate2(key) {
|
|
25568
|
+
const now = Date.now();
|
|
25569
|
+
for (const [k, ts] of processedEvents2) {
|
|
25570
|
+
if (now - ts > DEDUP_TTL_MS)
|
|
25571
|
+
processedEvents2.delete(k);
|
|
25572
|
+
}
|
|
25573
|
+
if (processedEvents2.has(key))
|
|
25574
|
+
return true;
|
|
25575
|
+
processedEvents2.set(key, now);
|
|
25576
|
+
return false;
|
|
25577
|
+
}
|
|
25578
|
+
function escapeRegExp(value) {
|
|
25579
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25580
|
+
}
|
|
25581
|
+
function mentionPatterns(botId) {
|
|
25582
|
+
const patterns = [new RegExp(`@${escapeRegExp(AZURE_DEVOPS_BOT_NAME)}\\b`, "gi")];
|
|
25583
|
+
if (botId)
|
|
25584
|
+
patterns.push(new RegExp(`@<${escapeRegExp(botId)}>`, "gi"));
|
|
25585
|
+
return patterns;
|
|
25586
|
+
}
|
|
25587
|
+
function detectMention(text, botId) {
|
|
25588
|
+
if (!text)
|
|
25589
|
+
return false;
|
|
25590
|
+
return mentionPatterns(botId).some((re) => {
|
|
25591
|
+
re.lastIndex = 0;
|
|
25592
|
+
return re.test(text);
|
|
25593
|
+
});
|
|
25594
|
+
}
|
|
25595
|
+
function extractMentionContext(text, botId) {
|
|
25596
|
+
return mentionPatterns(botId).reduce((acc, re) => acc.replace(re, ""), text).trim();
|
|
25597
|
+
}
|
|
25598
|
+
function isBot(identity, botId) {
|
|
25599
|
+
return !!botId && identity.id.toLowerCase() === botId.toLowerCase();
|
|
25600
|
+
}
|
|
25601
|
+
function pullRequestWebUrl(pr) {
|
|
25602
|
+
const web = pr._links?.web?.href;
|
|
25603
|
+
if (web)
|
|
25604
|
+
return web.split("#")[0];
|
|
25605
|
+
return `${canonicalAzureDevOpsRepoUrl(pr.repository.remoteUrl)}/pullrequest/${pr.pullRequestId}`;
|
|
25606
|
+
}
|
|
25607
|
+
function branchName(refName) {
|
|
25608
|
+
return refName.replace(/^refs\/heads\//, "");
|
|
25609
|
+
}
|
|
25610
|
+
function orgUrlFor(event) {
|
|
25611
|
+
const containers = event.resourceContainers;
|
|
25612
|
+
return normalizeOrgUrl(containers?.account?.baseUrl ?? containers?.collection?.baseUrl) ?? getAzureDevOpsOrgUrl();
|
|
25613
|
+
}
|
|
25614
|
+
function threadIdOf(links) {
|
|
25615
|
+
const href = links?.threads?.href ?? links?.self?.href ?? "";
|
|
25616
|
+
const match = href.match(/\/threads\/(\d+)/);
|
|
25617
|
+
return match ? Number(match[1]) : null;
|
|
25618
|
+
}
|
|
25619
|
+
function isPullRequest(value) {
|
|
25620
|
+
const pr = value;
|
|
25621
|
+
return typeof pr?.pullRequestId === "number" && typeof pr.repository?.id === "string" && typeof pr.repository.remoteUrl === "string" && !!pr.repository.project && !!pr.createdBy;
|
|
25622
|
+
}
|
|
25623
|
+
function createdPullRequestOf(event) {
|
|
25624
|
+
return isPullRequest(event?.resource) ? event.resource : null;
|
|
25625
|
+
}
|
|
25626
|
+
function commentedPayloadOf(event) {
|
|
25627
|
+
const resource = event?.resource;
|
|
25628
|
+
const comment = resource?.comment;
|
|
25629
|
+
const pullRequest = resource?.pullRequest;
|
|
25630
|
+
if (!isPullRequest(pullRequest) || typeof comment?.id !== "number" || !comment.author) {
|
|
25631
|
+
return null;
|
|
25632
|
+
}
|
|
25633
|
+
return { comment, pullRequest };
|
|
25634
|
+
}
|
|
25635
|
+
function warnMalformed(event) {
|
|
25636
|
+
console.warn(`[AzureDevOps] Ignoring ${event?.eventType} event with resourceVersion ${event?.resourceVersion ?? "unknown"}: required resource fields are missing`);
|
|
25637
|
+
}
|
|
25638
|
+
async function findLeadAgent2() {
|
|
25639
|
+
const agents = await getAllAgents();
|
|
25640
|
+
return agents.find((a) => a.role === "lead" && a.status === "idle") ?? agents.find((a) => a.role === "lead") ?? null;
|
|
25641
|
+
}
|
|
25642
|
+
var UNMAPPED_NAMESPACE = "integration:unmapped:azure-devops";
|
|
25643
|
+
var UNMAPPED_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
25644
|
+
var AZURE_DEVOPS_WEBHOOK_ACTOR = { kind: "system", id: "webhook:azure-devops" };
|
|
25645
|
+
function externalIdOf(identity) {
|
|
25646
|
+
return identity.uniqueName?.trim() || identity.id;
|
|
25647
|
+
}
|
|
25648
|
+
async function resolveAzureDevOpsSender(identity, sampleEventType, sampleContext) {
|
|
25649
|
+
const externalId = externalIdOf(identity);
|
|
25650
|
+
const existing = await findUserByExternalId("azure-devops", externalId);
|
|
25651
|
+
if (existing)
|
|
25652
|
+
return existing.id;
|
|
25653
|
+
if (externalId.includes("@")) {
|
|
25654
|
+
const { user: linked } = await findOrCreateUserByEmail(externalId, { name: identity.displayName }, AZURE_DEVOPS_WEBHOOK_ACTOR);
|
|
25655
|
+
await linkIdentity(linked.id, "azure-devops", externalId, AZURE_DEVOPS_WEBHOOK_ACTOR);
|
|
25656
|
+
return linked.id;
|
|
25657
|
+
}
|
|
25658
|
+
await upsertKv({
|
|
25659
|
+
namespace: UNMAPPED_NAMESPACE,
|
|
25660
|
+
key: `${externalId}:meta`,
|
|
25661
|
+
value: {
|
|
25662
|
+
lastSeenAt: new Date().toISOString(),
|
|
25663
|
+
sampleEventType,
|
|
25664
|
+
sampleContext: sampleContext.slice(0, 100)
|
|
25665
|
+
},
|
|
25666
|
+
valueType: "json",
|
|
25667
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS
|
|
25668
|
+
});
|
|
25669
|
+
await incrKv(UNMAPPED_NAMESPACE, `${externalId}:count`, 1);
|
|
25670
|
+
return;
|
|
25671
|
+
}
|
|
25672
|
+
async function renderAzureDevOpsIdentity(identity) {
|
|
25673
|
+
return renderIdentity(await resolveIdentity("azure-devops", externalIdOf(identity)));
|
|
25674
|
+
}
|
|
25675
|
+
async function handlePullRequestCreated(event) {
|
|
25676
|
+
const pr = createdPullRequestOf(event);
|
|
25677
|
+
if (!pr) {
|
|
25678
|
+
warnMalformed(event);
|
|
25679
|
+
return { created: false };
|
|
25680
|
+
}
|
|
25681
|
+
const repo = canonicalAzureDevOpsRepoUrl(pr.repository.remoteUrl);
|
|
25682
|
+
console.log(`[AzureDevOps] PR #${pr.pullRequestId} created by ${pr.createdBy.displayName} in ${repo}`);
|
|
25683
|
+
const orgUrl2 = orgUrlFor(event);
|
|
25684
|
+
const botId = await resolveAzureDevOpsBotId(orgUrl2);
|
|
25685
|
+
if (isBot(pr.createdBy, botId)) {
|
|
25686
|
+
console.log(`[AzureDevOps] PR opened by the bot itself, skipping`);
|
|
25687
|
+
return { created: false };
|
|
25688
|
+
}
|
|
25689
|
+
if (!detectMention(pr.description, botId)) {
|
|
25690
|
+
console.log(`[AzureDevOps] PR opened without bot mention, skipping`);
|
|
25691
|
+
return { created: false };
|
|
25692
|
+
}
|
|
25693
|
+
const dedupKey = `azure-devops-pr-${pr.repository.id}-${pr.pullRequestId}-created`;
|
|
25694
|
+
if (isDuplicate2(dedupKey)) {
|
|
25695
|
+
console.log(`[AzureDevOps] Skipping duplicate PR event`);
|
|
25696
|
+
return { created: false };
|
|
25697
|
+
}
|
|
25698
|
+
const requestedByUserId = await resolveAzureDevOpsSender(pr.createdBy, "pull_request", `PR !${pr.pullRequestId}: ${pr.title}`);
|
|
25699
|
+
const context = pr.description ? extractMentionContext(pr.description, botId) : "";
|
|
25700
|
+
const prUrl = pullRequestWebUrl(pr);
|
|
25701
|
+
const result = resolveTemplate("azure-devops.pull_request.opened", {
|
|
25702
|
+
pr_id: pr.pullRequestId,
|
|
25703
|
+
pr_title: pr.title,
|
|
25704
|
+
repo,
|
|
25705
|
+
project: pr.repository.project.name,
|
|
25706
|
+
repository: pr.repository.name,
|
|
25707
|
+
username: await renderAzureDevOpsIdentity(pr.createdBy),
|
|
25708
|
+
source_branch: branchName(pr.sourceRefName),
|
|
25709
|
+
target_branch: branchName(pr.targetRefName),
|
|
25710
|
+
pr_url: prUrl,
|
|
25711
|
+
context_section: context ? `Context: ${context}
|
|
25712
|
+
|
|
25713
|
+
` : ""
|
|
25714
|
+
});
|
|
25715
|
+
if (result.skipped) {
|
|
25716
|
+
return { created: false };
|
|
25717
|
+
}
|
|
25718
|
+
const lead = await findLeadAgent2();
|
|
25719
|
+
const task = await createTaskWithSiblingAwareness(result.text, {
|
|
25720
|
+
agentId: lead?.id ?? null,
|
|
25721
|
+
routingReason: lead ? "skill" : undefined,
|
|
25722
|
+
routingSource: lead ? "engine_default" : undefined,
|
|
25723
|
+
source: "azure-devops",
|
|
25724
|
+
vcsProvider: "azure-devops",
|
|
25725
|
+
taskType: "azure-devops-pr",
|
|
25726
|
+
vcsRepo: repo,
|
|
25727
|
+
vcsEventType: "pull_request",
|
|
25728
|
+
vcsNumber: pr.pullRequestId,
|
|
25729
|
+
vcsAuthor: externalIdOf(pr.createdBy),
|
|
25730
|
+
requestedByUserId,
|
|
25731
|
+
vcsUrl: prUrl,
|
|
25732
|
+
contextKey: azureDevOpsContextKey({
|
|
25733
|
+
repositoryId: pr.repository.id,
|
|
25734
|
+
pullRequestId: pr.pullRequestId
|
|
25735
|
+
})
|
|
25736
|
+
}, { origin: "webhook" });
|
|
25737
|
+
return { created: true, taskId: task.id };
|
|
25738
|
+
}
|
|
25739
|
+
async function handlePullRequestCommented(event) {
|
|
25740
|
+
const payload = commentedPayloadOf(event);
|
|
25741
|
+
if (!payload) {
|
|
25742
|
+
warnMalformed(event);
|
|
25743
|
+
return { created: false };
|
|
25744
|
+
}
|
|
25745
|
+
const { comment, pullRequest: pr } = payload;
|
|
25746
|
+
const repo = canonicalAzureDevOpsRepoUrl(pr.repository.remoteUrl);
|
|
25747
|
+
if (comment.commentType === "system") {
|
|
25748
|
+
return { created: false };
|
|
25749
|
+
}
|
|
25750
|
+
if (comment.lastContentUpdatedDate && comment.lastContentUpdatedDate !== comment.publishedDate) {
|
|
25751
|
+
console.log(`[AzureDevOps] Ignoring edited comment ${comment.id} on PR #${pr.pullRequestId}`);
|
|
25752
|
+
return { created: false };
|
|
25753
|
+
}
|
|
25754
|
+
const orgUrl2 = orgUrlFor(event);
|
|
25755
|
+
const botId = await resolveAzureDevOpsBotId(orgUrl2);
|
|
25756
|
+
if (isBot(comment.author, botId)) {
|
|
25757
|
+
return { created: false };
|
|
25758
|
+
}
|
|
25759
|
+
if (!detectMention(comment.content, botId)) {
|
|
25760
|
+
return { created: false };
|
|
25761
|
+
}
|
|
25762
|
+
console.log(`[AzureDevOps] Comment by ${comment.author.displayName} on PR #${pr.pullRequestId} in ${repo}`);
|
|
25763
|
+
const threadId = threadIdOf(comment._links);
|
|
25764
|
+
const dedupKey = `azure-devops-comment-${pr.repository.id}-${pr.pullRequestId}-${threadId}-${comment.id}`;
|
|
25765
|
+
if (isDuplicate2(dedupKey)) {
|
|
25766
|
+
return { created: false };
|
|
25767
|
+
}
|
|
25768
|
+
const requestedByUserId = await resolveAzureDevOpsSender(comment.author, "pull_request_comment", comment.content);
|
|
25769
|
+
const existingTask = await findTaskByVcs(repo, pr.pullRequestId);
|
|
25770
|
+
const existingTaskNote = existingTask ? `
|
|
25771
|
+
|
|
25772
|
+
_Note: There's an active task (${existingTask.id}) for this PR #${pr.pullRequestId}._` : "";
|
|
25773
|
+
const prUrl = pullRequestWebUrl(pr);
|
|
25774
|
+
const result = resolveTemplate("azure-devops.comment.mentioned", {
|
|
25775
|
+
pr_id: pr.pullRequestId,
|
|
25776
|
+
pr_title: pr.title,
|
|
25777
|
+
username: await renderAzureDevOpsIdentity(comment.author),
|
|
25778
|
+
repo,
|
|
25779
|
+
project: pr.repository.project.name,
|
|
25780
|
+
repository: pr.repository.name,
|
|
25781
|
+
pr_url: prUrl,
|
|
25782
|
+
context: extractMentionContext(comment.content, botId),
|
|
25783
|
+
existing_task_note: existingTaskNote
|
|
25784
|
+
});
|
|
25785
|
+
if (result.skipped) {
|
|
25786
|
+
return { created: false };
|
|
25787
|
+
}
|
|
25788
|
+
const lead = await findLeadAgent2();
|
|
25789
|
+
const task = await createTaskWithSiblingAwareness(result.text, {
|
|
25790
|
+
agentId: lead?.id ?? null,
|
|
25791
|
+
routingReason: lead ? "skill" : undefined,
|
|
25792
|
+
routingSource: lead ? "engine_default" : undefined,
|
|
25793
|
+
source: "azure-devops",
|
|
25794
|
+
vcsProvider: "azure-devops",
|
|
25795
|
+
taskType: "azure-devops-comment",
|
|
25796
|
+
vcsRepo: repo,
|
|
25797
|
+
vcsEventType: "pull_request_comment",
|
|
25798
|
+
vcsNumber: pr.pullRequestId,
|
|
25799
|
+
vcsCommentId: comment.id,
|
|
25800
|
+
vcsAuthor: externalIdOf(comment.author),
|
|
25801
|
+
requestedByUserId,
|
|
25802
|
+
vcsUrl: prUrl,
|
|
25803
|
+
parentTaskId: existingTask?.id,
|
|
25804
|
+
contextKey: azureDevOpsContextKey({
|
|
25805
|
+
repositoryId: pr.repository.id,
|
|
25806
|
+
pullRequestId: pr.pullRequestId
|
|
25807
|
+
})
|
|
25808
|
+
}, { origin: "webhook" });
|
|
25809
|
+
if (orgUrl2 && threadId !== null) {
|
|
25810
|
+
const ref = {
|
|
25811
|
+
orgUrl: orgUrl2,
|
|
25812
|
+
projectId: pr.repository.project.id,
|
|
25813
|
+
repositoryId: pr.repository.id,
|
|
25814
|
+
pullRequestId: pr.pullRequestId
|
|
25815
|
+
};
|
|
25816
|
+
try {
|
|
25817
|
+
await likeAzureDevOpsComment(ref, threadId, comment.id);
|
|
25818
|
+
} catch {}
|
|
25819
|
+
}
|
|
25820
|
+
return { created: true, taskId: task.id };
|
|
25821
|
+
}
|
|
25233
25822
|
// src/http/core.ts
|
|
25234
25823
|
init_db();
|
|
25235
25824
|
|
|
@@ -25601,7 +26190,6 @@ function stopAuditGc() {
|
|
|
25601
26190
|
init_db();
|
|
25602
26191
|
init_resolver();
|
|
25603
26192
|
init_context_key();
|
|
25604
|
-
init_secret_scrubber();
|
|
25605
26193
|
|
|
25606
26194
|
// src/github/mentions.ts
|
|
25607
26195
|
var GITHUB_BOT_NAME = process.env.GITHUB_BOT_NAME || "agent-swarm-bot";
|
|
@@ -25620,12 +26208,12 @@ function computeMentionPattern(names) {
|
|
|
25620
26208
|
}
|
|
25621
26209
|
var BOT_NAMES = computeBotNames();
|
|
25622
26210
|
var MENTION_PATTERN = computeMentionPattern(BOT_NAMES);
|
|
25623
|
-
function
|
|
26211
|
+
function detectMention2(text) {
|
|
25624
26212
|
if (!text)
|
|
25625
26213
|
return false;
|
|
25626
26214
|
return MENTION_PATTERN.test(text);
|
|
25627
26215
|
}
|
|
25628
|
-
function
|
|
26216
|
+
function extractMentionContext2(text) {
|
|
25629
26217
|
if (!text)
|
|
25630
26218
|
return "";
|
|
25631
26219
|
return text.replace(MENTION_PATTERN, "").trim();
|
|
@@ -26068,7 +26656,7 @@ Related task: {{related_task_id}}
|
|
|
26068
26656
|
});
|
|
26069
26657
|
|
|
26070
26658
|
// src/github/handlers.ts
|
|
26071
|
-
var
|
|
26659
|
+
var processedEvents3 = new Map;
|
|
26072
26660
|
var EVENT_TTL2 = 60000;
|
|
26073
26661
|
function buildGithubContextKey(fullName, kind, number3) {
|
|
26074
26662
|
const [owner, repo] = fullName.split("/");
|
|
@@ -26112,34 +26700,34 @@ function getCommandSuggestions(taskType, targetType) {
|
|
|
26112
26700
|
return "";
|
|
26113
26701
|
}
|
|
26114
26702
|
}
|
|
26115
|
-
function
|
|
26703
|
+
function isDuplicate3(eventKey) {
|
|
26116
26704
|
const now = Date.now();
|
|
26117
|
-
for (const [key, timestamp] of
|
|
26705
|
+
for (const [key, timestamp] of processedEvents3) {
|
|
26118
26706
|
if (now - timestamp > EVENT_TTL2) {
|
|
26119
|
-
|
|
26707
|
+
processedEvents3.delete(key);
|
|
26120
26708
|
}
|
|
26121
26709
|
}
|
|
26122
|
-
if (
|
|
26710
|
+
if (processedEvents3.has(eventKey)) {
|
|
26123
26711
|
return true;
|
|
26124
26712
|
}
|
|
26125
|
-
|
|
26713
|
+
processedEvents3.set(eventKey, now);
|
|
26126
26714
|
return false;
|
|
26127
26715
|
}
|
|
26128
|
-
async function
|
|
26716
|
+
async function findLeadAgent3() {
|
|
26129
26717
|
const agents = await getAllAgents();
|
|
26130
26718
|
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
26131
26719
|
if (onlineLead)
|
|
26132
26720
|
return onlineLead;
|
|
26133
26721
|
return agents.find((a) => a.isLead) ?? null;
|
|
26134
26722
|
}
|
|
26135
|
-
var
|
|
26136
|
-
var
|
|
26723
|
+
var UNMAPPED_NAMESPACE2 = "integration:unmapped:github";
|
|
26724
|
+
var UNMAPPED_TTL_MS2 = 30 * 24 * 60 * 60 * 1000;
|
|
26137
26725
|
async function resolveGitHubSender(login, sampleEventType, sampleContext) {
|
|
26138
26726
|
const existing = await findUserByExternalId("github", login);
|
|
26139
26727
|
if (existing)
|
|
26140
26728
|
return existing.id;
|
|
26141
26729
|
await upsertKv({
|
|
26142
|
-
namespace:
|
|
26730
|
+
namespace: UNMAPPED_NAMESPACE2,
|
|
26143
26731
|
key: `${login}:meta`,
|
|
26144
26732
|
value: {
|
|
26145
26733
|
lastSeenAt: new Date().toISOString(),
|
|
@@ -26147,9 +26735,9 @@ async function resolveGitHubSender(login, sampleEventType, sampleContext) {
|
|
|
26147
26735
|
sampleContext: sampleContext.slice(0, 100)
|
|
26148
26736
|
},
|
|
26149
26737
|
valueType: "json",
|
|
26150
|
-
expiresAt: Date.now() +
|
|
26738
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS2
|
|
26151
26739
|
});
|
|
26152
|
-
await incrKv(
|
|
26740
|
+
await incrKv(UNMAPPED_NAMESPACE2, `${login}:count`, 1);
|
|
26153
26741
|
return;
|
|
26154
26742
|
}
|
|
26155
26743
|
async function handlePullRequest(event) {
|
|
@@ -26168,10 +26756,10 @@ async function handlePullRequest(event) {
|
|
|
26168
26756
|
return { created: false };
|
|
26169
26757
|
}
|
|
26170
26758
|
const eventKey2 = `pr-assigned:${repository.full_name}:${pr.number}`;
|
|
26171
|
-
if (
|
|
26759
|
+
if (isDuplicate3(eventKey2)) {
|
|
26172
26760
|
return { created: false };
|
|
26173
26761
|
}
|
|
26174
|
-
const lead2 = await
|
|
26762
|
+
const lead2 = await findLeadAgent3();
|
|
26175
26763
|
const result2 = resolveTemplate("github.pull_request.assigned", {
|
|
26176
26764
|
pr_number: pr.number,
|
|
26177
26765
|
pr_title: pr.title,
|
|
@@ -26207,9 +26795,7 @@ async function handlePullRequest(event) {
|
|
|
26207
26795
|
} else {
|
|
26208
26796
|
console.log(`[GitHub] Created unassigned task ${task2.id} for PR #${pr.number} (assigned, no lead available)`);
|
|
26209
26797
|
}
|
|
26210
|
-
|
|
26211
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26212
|
-
}
|
|
26798
|
+
addEyesReactionToTaskSource(task2).catch(() => {});
|
|
26213
26799
|
return { created: true, taskId: task2.id };
|
|
26214
26800
|
}
|
|
26215
26801
|
if (action === "unassigned") {
|
|
@@ -26237,7 +26823,7 @@ async function handlePullRequest(event) {
|
|
|
26237
26823
|
return { created: false };
|
|
26238
26824
|
}
|
|
26239
26825
|
const eventKey2 = `pr-review-requested:${repository.full_name}:${pr.number}`;
|
|
26240
|
-
if (
|
|
26826
|
+
if (isDuplicate3(eventKey2)) {
|
|
26241
26827
|
return { created: false };
|
|
26242
26828
|
}
|
|
26243
26829
|
const existingTask = await findTaskByVcs(repository.full_name, pr.number);
|
|
@@ -26245,7 +26831,7 @@ async function handlePullRequest(event) {
|
|
|
26245
26831
|
console.log(`[GitHub] Skipping review task for PR #${pr.number} — active task ${existingTask.id} already exists`);
|
|
26246
26832
|
return { created: false };
|
|
26247
26833
|
}
|
|
26248
|
-
const lead2 = await
|
|
26834
|
+
const lead2 = await findLeadAgent3();
|
|
26249
26835
|
const result2 = resolveTemplate("github.pull_request.review_requested", {
|
|
26250
26836
|
pr_number: pr.number,
|
|
26251
26837
|
pr_title: pr.title,
|
|
@@ -26281,9 +26867,7 @@ async function handlePullRequest(event) {
|
|
|
26281
26867
|
} else {
|
|
26282
26868
|
console.log(`[GitHub] Created unassigned task ${task2.id} for PR #${pr.number} (review requested, no lead available)`);
|
|
26283
26869
|
}
|
|
26284
|
-
|
|
26285
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26286
|
-
}
|
|
26870
|
+
addEyesReactionToTaskSource(task2).catch(() => {});
|
|
26287
26871
|
return { created: true, taskId: task2.id };
|
|
26288
26872
|
}
|
|
26289
26873
|
if (action === "review_request_removed") {
|
|
@@ -26312,10 +26896,10 @@ async function handlePullRequest(event) {
|
|
|
26312
26896
|
return { created: false };
|
|
26313
26897
|
}
|
|
26314
26898
|
const eventKey2 = `pr-labeled:${repository.full_name}:${pr.number}:${labelName}`;
|
|
26315
|
-
if (
|
|
26899
|
+
if (isDuplicate3(eventKey2)) {
|
|
26316
26900
|
return { created: false };
|
|
26317
26901
|
}
|
|
26318
|
-
const lead2 = await
|
|
26902
|
+
const lead2 = await findLeadAgent3();
|
|
26319
26903
|
const result2 = resolveTemplate("github.pull_request.labeled", {
|
|
26320
26904
|
pr_number: pr.number,
|
|
26321
26905
|
pr_title: pr.title,
|
|
@@ -26351,9 +26935,7 @@ async function handlePullRequest(event) {
|
|
|
26351
26935
|
} else {
|
|
26352
26936
|
console.log(`[GitHub] Created unassigned task ${task2.id} for PR #${pr.number} (labeled: ${labelName}, no lead available)`);
|
|
26353
26937
|
}
|
|
26354
|
-
|
|
26355
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26356
|
-
}
|
|
26938
|
+
addEyesReactionToTaskSource(task2).catch(() => {});
|
|
26357
26939
|
return { created: true, taskId: task2.id };
|
|
26358
26940
|
}
|
|
26359
26941
|
if (action === "closed") {
|
|
@@ -26367,16 +26949,16 @@ async function handlePullRequest(event) {
|
|
|
26367
26949
|
if (action !== "opened" && action !== "edited") {
|
|
26368
26950
|
return { created: false };
|
|
26369
26951
|
}
|
|
26370
|
-
const hasMention =
|
|
26952
|
+
const hasMention = detectMention2(pr.title) || detectMention2(pr.body);
|
|
26371
26953
|
if (!hasMention) {
|
|
26372
26954
|
return { created: false };
|
|
26373
26955
|
}
|
|
26374
26956
|
const eventKey = `pr:${repository.full_name}:${pr.number}:${action}`;
|
|
26375
|
-
if (
|
|
26957
|
+
if (isDuplicate3(eventKey)) {
|
|
26376
26958
|
return { created: false };
|
|
26377
26959
|
}
|
|
26378
|
-
const lead = await
|
|
26379
|
-
const context =
|
|
26960
|
+
const lead = await findLeadAgent3();
|
|
26961
|
+
const context = extractMentionContext2(pr.body) || pr.title;
|
|
26380
26962
|
const result = resolveTemplate("github.pull_request.mentioned", {
|
|
26381
26963
|
pr_number: pr.number,
|
|
26382
26964
|
pr_title: pr.title,
|
|
@@ -26411,9 +26993,7 @@ async function handlePullRequest(event) {
|
|
|
26411
26993
|
} else {
|
|
26412
26994
|
console.log(`[GitHub] Created unassigned task ${task.id} for PR #${pr.number} (no lead available)`);
|
|
26413
26995
|
}
|
|
26414
|
-
|
|
26415
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26416
|
-
}
|
|
26996
|
+
addEyesReactionToTaskSource(task).catch(() => {});
|
|
26417
26997
|
return { created: true, taskId: task.id };
|
|
26418
26998
|
}
|
|
26419
26999
|
async function handleIssue(event) {
|
|
@@ -26424,10 +27004,10 @@ async function handleIssue(event) {
|
|
|
26424
27004
|
return { created: false };
|
|
26425
27005
|
}
|
|
26426
27006
|
const eventKey2 = `issue-assigned:${repository.full_name}:${issue.number}`;
|
|
26427
|
-
if (
|
|
27007
|
+
if (isDuplicate3(eventKey2)) {
|
|
26428
27008
|
return { created: false };
|
|
26429
27009
|
}
|
|
26430
|
-
const lead2 = await
|
|
27010
|
+
const lead2 = await findLeadAgent3();
|
|
26431
27011
|
const result2 = resolveTemplate("github.issue.assigned", {
|
|
26432
27012
|
issue_number: issue.number,
|
|
26433
27013
|
issue_title: issue.title,
|
|
@@ -26461,9 +27041,7 @@ async function handleIssue(event) {
|
|
|
26461
27041
|
} else {
|
|
26462
27042
|
console.log(`[GitHub] Created unassigned task ${task2.id} for issue #${issue.number} (assigned, no lead available)`);
|
|
26463
27043
|
}
|
|
26464
|
-
|
|
26465
|
-
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26466
|
-
}
|
|
27044
|
+
addEyesReactionToTaskSource(task2).catch(() => {});
|
|
26467
27045
|
return { created: true, taskId: task2.id };
|
|
26468
27046
|
}
|
|
26469
27047
|
if (action === "unassigned") {
|
|
@@ -26492,10 +27070,10 @@ async function handleIssue(event) {
|
|
|
26492
27070
|
return { created: false };
|
|
26493
27071
|
}
|
|
26494
27072
|
const eventKey2 = `issue-labeled:${repository.full_name}:${issue.number}:${labelName}`;
|
|
26495
|
-
if (
|
|
27073
|
+
if (isDuplicate3(eventKey2)) {
|
|
26496
27074
|
return { created: false };
|
|
26497
27075
|
}
|
|
26498
|
-
const lead2 = await
|
|
27076
|
+
const lead2 = await findLeadAgent3();
|
|
26499
27077
|
const result2 = resolveTemplate("github.issue.labeled", {
|
|
26500
27078
|
issue_number: issue.number,
|
|
26501
27079
|
issue_title: issue.title,
|
|
@@ -26529,24 +27107,22 @@ async function handleIssue(event) {
|
|
|
26529
27107
|
} else {
|
|
26530
27108
|
console.log(`[GitHub] Created unassigned task ${task2.id} for issue #${issue.number} (labeled: ${labelName}, no lead available)`);
|
|
26531
27109
|
}
|
|
26532
|
-
|
|
26533
|
-
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26534
|
-
}
|
|
27110
|
+
addEyesReactionToTaskSource(task2).catch(() => {});
|
|
26535
27111
|
return { created: true, taskId: task2.id };
|
|
26536
27112
|
}
|
|
26537
27113
|
if (action !== "opened" && action !== "edited") {
|
|
26538
27114
|
return { created: false };
|
|
26539
27115
|
}
|
|
26540
|
-
const hasMention =
|
|
27116
|
+
const hasMention = detectMention2(issue.title) || detectMention2(issue.body);
|
|
26541
27117
|
if (!hasMention) {
|
|
26542
27118
|
return { created: false };
|
|
26543
27119
|
}
|
|
26544
27120
|
const eventKey = `issue:${repository.full_name}:${issue.number}:${action}`;
|
|
26545
|
-
if (
|
|
27121
|
+
if (isDuplicate3(eventKey)) {
|
|
26546
27122
|
return { created: false };
|
|
26547
27123
|
}
|
|
26548
|
-
const lead = await
|
|
26549
|
-
const context =
|
|
27124
|
+
const lead = await findLeadAgent3();
|
|
27125
|
+
const context = extractMentionContext2(issue.body) || issue.title;
|
|
26550
27126
|
const result = resolveTemplate("github.issue.mentioned", {
|
|
26551
27127
|
issue_number: issue.number,
|
|
26552
27128
|
issue_title: issue.title,
|
|
@@ -26579,9 +27155,7 @@ async function handleIssue(event) {
|
|
|
26579
27155
|
} else {
|
|
26580
27156
|
console.log(`[GitHub] Created unassigned task ${task.id} for issue #${issue.number} (no lead available)`);
|
|
26581
27157
|
}
|
|
26582
|
-
|
|
26583
|
-
addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26584
|
-
}
|
|
27158
|
+
addEyesReactionToTaskSource(task).catch(() => {});
|
|
26585
27159
|
return { created: true, taskId: task.id };
|
|
26586
27160
|
}
|
|
26587
27161
|
async function handleComment(event, eventType) {
|
|
@@ -26590,21 +27164,21 @@ async function handleComment(event, eventType) {
|
|
|
26590
27164
|
if (action !== "created") {
|
|
26591
27165
|
return { created: false };
|
|
26592
27166
|
}
|
|
26593
|
-
if (!
|
|
27167
|
+
if (!detectMention2(comment.body)) {
|
|
26594
27168
|
return { created: false };
|
|
26595
27169
|
}
|
|
26596
27170
|
const eventKey = `comment:${repository.full_name}:${comment.id}`;
|
|
26597
|
-
if (
|
|
27171
|
+
if (isDuplicate3(eventKey)) {
|
|
26598
27172
|
return { created: false };
|
|
26599
27173
|
}
|
|
26600
|
-
const lead = await
|
|
27174
|
+
const lead = await findLeadAgent3();
|
|
26601
27175
|
const target = pull_request || issue;
|
|
26602
27176
|
const targetType = pull_request ? "PR" : "Issue";
|
|
26603
27177
|
const targetNumber = target?.number ?? 0;
|
|
26604
27178
|
const targetTitle = target?.title ?? "Unknown";
|
|
26605
27179
|
const targetUrl = target?.html_url ?? comment.html_url;
|
|
26606
27180
|
const existingTask = targetNumber ? await findTaskByVcs(repository.full_name, targetNumber) : null;
|
|
26607
|
-
const context =
|
|
27181
|
+
const context = extractMentionContext2(comment.body);
|
|
26608
27182
|
const suggestions = getCommandSuggestions("github-comment", targetType);
|
|
26609
27183
|
const relatedTaskSection = existingTask ? `Related task: ${existingTask.id}
|
|
26610
27184
|
\uD83D\uDD00 Consider routing to the same agent working on the related task.
|
|
@@ -26646,9 +27220,7 @@ async function handleComment(event, eventType) {
|
|
|
26646
27220
|
} else {
|
|
26647
27221
|
console.log(`[GitHub] Created unassigned task ${task.id} for comment on #${targetNumber} (no lead available)`);
|
|
26648
27222
|
}
|
|
26649
|
-
|
|
26650
|
-
addReaction(repository.full_name, comment.id, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add comment reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26651
|
-
}
|
|
27223
|
+
addEyesReactionToTaskSource(task).catch(() => {});
|
|
26652
27224
|
return { created: true, taskId: task.id };
|
|
26653
27225
|
}
|
|
26654
27226
|
function parseNextPageLink(linkHeader) {
|
|
@@ -26667,12 +27239,12 @@ function buildReviewCommentsHeaders(token) {
|
|
|
26667
27239
|
"X-GitHub-Api-Version": "2022-11-28"
|
|
26668
27240
|
};
|
|
26669
27241
|
}
|
|
26670
|
-
async function fetchPaginatedReviewComments(initialUrl,
|
|
27242
|
+
async function fetchPaginatedReviewComments(initialUrl, headers2) {
|
|
26671
27243
|
const allComments = [];
|
|
26672
27244
|
let url = initialUrl;
|
|
26673
27245
|
try {
|
|
26674
27246
|
while (url) {
|
|
26675
|
-
const response = await fetch(url, { headers });
|
|
27247
|
+
const response = await fetch(url, { headers: headers2 });
|
|
26676
27248
|
if (!response.ok) {
|
|
26677
27249
|
console.error(`[GitHub] Failed to fetch review inline comments: ${response.status}`);
|
|
26678
27250
|
return { comments: allComments, degraded: true };
|
|
@@ -26689,24 +27261,24 @@ async function fetchPaginatedReviewComments(initialUrl, headers) {
|
|
|
26689
27261
|
return { comments: allComments, degraded: true };
|
|
26690
27262
|
}
|
|
26691
27263
|
}
|
|
26692
|
-
async function fetchReviewScopedComments(repo, prNumber, reviewId,
|
|
27264
|
+
async function fetchReviewScopedComments(repo, prNumber, reviewId, headers2) {
|
|
26693
27265
|
const url = `https://api.github.com/repos/${repo}/pulls/${prNumber}/reviews/${reviewId}/comments?per_page=100`;
|
|
26694
|
-
let result = await fetchPaginatedReviewComments(url,
|
|
27266
|
+
let result = await fetchPaginatedReviewComments(url, headers2);
|
|
26695
27267
|
if (result.degraded || result.comments.length > 0) {
|
|
26696
27268
|
return result;
|
|
26697
27269
|
}
|
|
26698
27270
|
for (const delayMs of REVIEW_COMMENTS_EMPTY_RETRY_DELAYS_MS) {
|
|
26699
27271
|
await reviewCommentsRetryDelay(delayMs);
|
|
26700
|
-
result = await fetchPaginatedReviewComments(url,
|
|
27272
|
+
result = await fetchPaginatedReviewComments(url, headers2);
|
|
26701
27273
|
if (result.degraded || result.comments.length > 0) {
|
|
26702
27274
|
return result;
|
|
26703
27275
|
}
|
|
26704
27276
|
}
|
|
26705
27277
|
return result;
|
|
26706
27278
|
}
|
|
26707
|
-
async function fetchPrLevelReviewComments(repo, prNumber, reviewId,
|
|
27279
|
+
async function fetchPrLevelReviewComments(repo, prNumber, reviewId, headers2) {
|
|
26708
27280
|
const url = `https://api.github.com/repos/${repo}/pulls/${prNumber}/comments?per_page=100`;
|
|
26709
|
-
const result = await fetchPaginatedReviewComments(url,
|
|
27281
|
+
const result = await fetchPaginatedReviewComments(url, headers2);
|
|
26710
27282
|
return {
|
|
26711
27283
|
comments: result.comments.filter((comment) => comment.pull_request_review_id === reviewId),
|
|
26712
27284
|
degraded: result.degraded
|
|
@@ -26726,12 +27298,12 @@ async function fetchReviewComments(repo, prNumber, reviewId, installationId) {
|
|
|
26726
27298
|
if (!token) {
|
|
26727
27299
|
return { comments: [], degraded: true };
|
|
26728
27300
|
}
|
|
26729
|
-
const
|
|
26730
|
-
const scopedResult = await fetchReviewScopedComments(repo, prNumber, reviewId,
|
|
27301
|
+
const headers2 = buildReviewCommentsHeaders(token);
|
|
27302
|
+
const scopedResult = await fetchReviewScopedComments(repo, prNumber, reviewId, headers2);
|
|
26731
27303
|
if (!scopedResult.degraded && scopedResult.comments.length > 0) {
|
|
26732
27304
|
return scopedResult;
|
|
26733
27305
|
}
|
|
26734
|
-
const fallbackResult = await fetchPrLevelReviewComments(repo, prNumber, reviewId,
|
|
27306
|
+
const fallbackResult = await fetchPrLevelReviewComments(repo, prNumber, reviewId, headers2);
|
|
26735
27307
|
const mergedComments = dedupeReviewComments([
|
|
26736
27308
|
...scopedResult.comments,
|
|
26737
27309
|
...fallbackResult.comments
|
|
@@ -26782,7 +27354,7 @@ async function handlePullRequestReview(event) {
|
|
|
26782
27354
|
return { created: false };
|
|
26783
27355
|
}
|
|
26784
27356
|
const eventKey = `pr-review:${repository.full_name}:${pr.number}:${review.id}`;
|
|
26785
|
-
if (
|
|
27357
|
+
if (isDuplicate3(eventKey)) {
|
|
26786
27358
|
return { created: false };
|
|
26787
27359
|
}
|
|
26788
27360
|
const { comments: inlineComments, degraded } = installation?.id ? await fetchReviewComments(repository.full_name, pr.number, review.id, installation.id) : { comments: [], degraded: true };
|
|
@@ -26794,7 +27366,7 @@ async function handlePullRequestReview(event) {
|
|
|
26794
27366
|
if (!isBotCreator && !existingTask) {
|
|
26795
27367
|
return { created: false };
|
|
26796
27368
|
}
|
|
26797
|
-
const lead = await
|
|
27369
|
+
const lead = await findLeadAgent3();
|
|
26798
27370
|
const { emoji, label } = getReviewStateInfo(review.state);
|
|
26799
27371
|
const reviewBodySection = review.body ? `
|
|
26800
27372
|
|
|
@@ -26846,9 +27418,7 @@ ${review.body}` : "";
|
|
|
26846
27418
|
} else {
|
|
26847
27419
|
console.log(`[GitHub] Created unassigned task ${task.id} for PR #${pr.number} review (${review.state}, no lead available)`);
|
|
26848
27420
|
}
|
|
26849
|
-
|
|
26850
|
-
addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
26851
|
-
}
|
|
27421
|
+
addEyesReactionToTaskSource(task).catch(() => {});
|
|
26852
27422
|
return { created: true, taskId: task.id };
|
|
26853
27423
|
}
|
|
26854
27424
|
async function handleCheckRun(event) {
|
|
@@ -26871,46 +27441,46 @@ async function handleWorkflowRun(event) {
|
|
|
26871
27441
|
}
|
|
26872
27442
|
// src/gitlab/auth.ts
|
|
26873
27443
|
init_env_flag();
|
|
26874
|
-
var
|
|
26875
|
-
var
|
|
26876
|
-
var
|
|
27444
|
+
var initialized4 = false;
|
|
27445
|
+
var webhookSecret4 = null;
|
|
27446
|
+
var apiToken2 = null;
|
|
26877
27447
|
var gitlabUrl = "https://gitlab.com";
|
|
26878
27448
|
function isGitLabEnabled() {
|
|
26879
27449
|
return !!process.env.GITLAB_WEBHOOK_SECRET && !isEnvFlagEnabled("GITLAB_DISABLE", false);
|
|
26880
27450
|
}
|
|
26881
27451
|
function initGitLab() {
|
|
26882
|
-
if (
|
|
27452
|
+
if (initialized4)
|
|
26883
27453
|
return;
|
|
26884
27454
|
if (!isGitLabEnabled()) {
|
|
26885
27455
|
console.log("[GitLab] Integration disabled (GITLAB_WEBHOOK_SECRET not set)");
|
|
26886
27456
|
return;
|
|
26887
27457
|
}
|
|
26888
|
-
|
|
26889
|
-
|
|
27458
|
+
webhookSecret4 = process.env.GITLAB_WEBHOOK_SECRET;
|
|
27459
|
+
apiToken2 = process.env.GITLAB_TOKEN ?? null;
|
|
26890
27460
|
gitlabUrl = process.env.GITLAB_URL ?? "https://gitlab.com";
|
|
26891
|
-
|
|
27461
|
+
initialized4 = true;
|
|
26892
27462
|
console.log(`[GitLab] Integration initialized (url: ${gitlabUrl})`);
|
|
26893
27463
|
}
|
|
26894
27464
|
function verifyGitLabWebhook(tokenHeader) {
|
|
26895
|
-
if (!
|
|
27465
|
+
if (!webhookSecret4)
|
|
26896
27466
|
return false;
|
|
26897
27467
|
if (!tokenHeader)
|
|
26898
27468
|
return false;
|
|
26899
|
-
if (tokenHeader.length !==
|
|
27469
|
+
if (tokenHeader.length !== webhookSecret4.length)
|
|
26900
27470
|
return false;
|
|
26901
|
-
return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(
|
|
27471
|
+
return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(webhookSecret4));
|
|
26902
27472
|
}
|
|
26903
27473
|
function getGitLabToken() {
|
|
26904
|
-
return
|
|
27474
|
+
return apiToken2;
|
|
26905
27475
|
}
|
|
26906
27476
|
function getGitLabUrl() {
|
|
26907
27477
|
return gitlabUrl;
|
|
26908
27478
|
}
|
|
26909
27479
|
var GITLAB_BOT_NAME = process.env.GITLAB_BOT_NAME ?? "agent-swarm-bot";
|
|
26910
27480
|
function resetGitLab() {
|
|
26911
|
-
|
|
26912
|
-
|
|
26913
|
-
|
|
27481
|
+
initialized4 = false;
|
|
27482
|
+
webhookSecret4 = null;
|
|
27483
|
+
apiToken2 = null;
|
|
26914
27484
|
gitlabUrl = "https://gitlab.com";
|
|
26915
27485
|
}
|
|
26916
27486
|
// src/gitlab/handlers.ts
|
|
@@ -26919,7 +27489,7 @@ init_resolver();
|
|
|
26919
27489
|
init_context_key();
|
|
26920
27490
|
|
|
26921
27491
|
// src/gitlab/reactions.ts
|
|
26922
|
-
function
|
|
27492
|
+
function headers2() {
|
|
26923
27493
|
const token = getGitLabToken();
|
|
26924
27494
|
if (!token)
|
|
26925
27495
|
throw new Error("[GitLab] No API token configured");
|
|
@@ -26940,7 +27510,7 @@ async function addGitLabReaction(project, entityType, iid, emojiName) {
|
|
|
26940
27510
|
try {
|
|
26941
27511
|
const resp = await fetch(url, {
|
|
26942
27512
|
method: "POST",
|
|
26943
|
-
headers:
|
|
27513
|
+
headers: headers2(),
|
|
26944
27514
|
body: JSON.stringify({ name: emojiName })
|
|
26945
27515
|
});
|
|
26946
27516
|
if (!resp.ok) {
|
|
@@ -26956,7 +27526,7 @@ async function addGitLabNoteReaction(project, entityType, iid, noteId, emojiName
|
|
|
26956
27526
|
try {
|
|
26957
27527
|
const resp = await fetch(url, {
|
|
26958
27528
|
method: "POST",
|
|
26959
|
-
headers:
|
|
27529
|
+
headers: headers2(),
|
|
26960
27530
|
body: JSON.stringify({ name: emojiName })
|
|
26961
27531
|
});
|
|
26962
27532
|
if (!resp.ok) {
|
|
@@ -27080,33 +27650,33 @@ The CI pipeline has failed. Please investigate and fix the issues.{{@template[co
|
|
|
27080
27650
|
});
|
|
27081
27651
|
|
|
27082
27652
|
// src/gitlab/handlers.ts
|
|
27083
|
-
var
|
|
27084
|
-
var
|
|
27085
|
-
function
|
|
27653
|
+
var processedEvents4 = new Map;
|
|
27654
|
+
var DEDUP_TTL_MS2 = 60000;
|
|
27655
|
+
function isDuplicate4(key) {
|
|
27086
27656
|
const now = Date.now();
|
|
27087
|
-
for (const [k, ts] of
|
|
27088
|
-
if (now - ts >
|
|
27089
|
-
|
|
27657
|
+
for (const [k, ts] of processedEvents4) {
|
|
27658
|
+
if (now - ts > DEDUP_TTL_MS2)
|
|
27659
|
+
processedEvents4.delete(k);
|
|
27090
27660
|
}
|
|
27091
|
-
if (
|
|
27661
|
+
if (processedEvents4.has(key))
|
|
27092
27662
|
return true;
|
|
27093
|
-
|
|
27663
|
+
processedEvents4.set(key, now);
|
|
27094
27664
|
return false;
|
|
27095
27665
|
}
|
|
27096
|
-
function
|
|
27666
|
+
function detectMention3(text) {
|
|
27097
27667
|
if (!text)
|
|
27098
27668
|
return false;
|
|
27099
27669
|
return new RegExp(`@${GITLAB_BOT_NAME}\\b`, "i").test(text);
|
|
27100
27670
|
}
|
|
27101
|
-
function
|
|
27671
|
+
function extractMentionContext3(text) {
|
|
27102
27672
|
return text.replace(new RegExp(`@${GITLAB_BOT_NAME}\\b`, "gi"), "").trim();
|
|
27103
27673
|
}
|
|
27104
|
-
async function
|
|
27674
|
+
async function findLeadAgent4() {
|
|
27105
27675
|
const agents = await getAllAgents();
|
|
27106
27676
|
return agents.find((a) => a.role === "lead" && a.status === "idle") ?? agents.find((a) => a.role === "lead") ?? null;
|
|
27107
27677
|
}
|
|
27108
|
-
var
|
|
27109
|
-
var
|
|
27678
|
+
var UNMAPPED_NAMESPACE3 = "integration:unmapped:gitlab";
|
|
27679
|
+
var UNMAPPED_TTL_MS3 = 30 * 24 * 60 * 60 * 1000;
|
|
27110
27680
|
var GITLAB_WEBHOOK_ACTOR = { kind: "system", id: "webhook:gitlab" };
|
|
27111
27681
|
async function resolveGitLabSender(user, sampleEventType, sampleContext) {
|
|
27112
27682
|
const existing = await findUserByExternalId("gitlab", user.username);
|
|
@@ -27119,7 +27689,7 @@ async function resolveGitLabSender(user, sampleEventType, sampleContext) {
|
|
|
27119
27689
|
return linked.id;
|
|
27120
27690
|
}
|
|
27121
27691
|
await upsertKv({
|
|
27122
|
-
namespace:
|
|
27692
|
+
namespace: UNMAPPED_NAMESPACE3,
|
|
27123
27693
|
key: `${user.username}:meta`,
|
|
27124
27694
|
value: {
|
|
27125
27695
|
lastSeenAt: new Date().toISOString(),
|
|
@@ -27127,9 +27697,9 @@ async function resolveGitLabSender(user, sampleEventType, sampleContext) {
|
|
|
27127
27697
|
sampleContext: sampleContext.slice(0, 100)
|
|
27128
27698
|
},
|
|
27129
27699
|
valueType: "json",
|
|
27130
|
-
expiresAt: Date.now() +
|
|
27700
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS3
|
|
27131
27701
|
});
|
|
27132
|
-
await incrKv(
|
|
27702
|
+
await incrKv(UNMAPPED_NAMESPACE3, `${user.username}:count`, 1);
|
|
27133
27703
|
return;
|
|
27134
27704
|
}
|
|
27135
27705
|
async function renderGitLabIdentity(username) {
|
|
@@ -27142,19 +27712,19 @@ async function handleMergeRequest(event) {
|
|
|
27142
27712
|
const requestedByUserId = await resolveGitLabSender(user, "merge_request", `MR !${mr.iid}: ${mr.title}`);
|
|
27143
27713
|
console.log(`[GitLab] MR #${mr.iid} ${action} by ${user.username} in ${repo}`);
|
|
27144
27714
|
const dedupKey = `gitlab-mr-${repo}-${mr.iid}-${action}-${user.username}`;
|
|
27145
|
-
if (
|
|
27715
|
+
if (isDuplicate4(dedupKey)) {
|
|
27146
27716
|
console.log(`[GitLab] Skipping duplicate MR event`);
|
|
27147
27717
|
return { created: false };
|
|
27148
27718
|
}
|
|
27149
|
-
const lead = await
|
|
27719
|
+
const lead = await findLeadAgent4();
|
|
27150
27720
|
switch (action) {
|
|
27151
27721
|
case "open": {
|
|
27152
|
-
const hasMention =
|
|
27722
|
+
const hasMention = detectMention3(mr.description);
|
|
27153
27723
|
if (!hasMention) {
|
|
27154
27724
|
console.log(`[GitLab] MR opened without bot mention, skipping`);
|
|
27155
27725
|
return { created: false };
|
|
27156
27726
|
}
|
|
27157
|
-
const context = mr.description ?
|
|
27727
|
+
const context = mr.description ? extractMentionContext3(mr.description) : "";
|
|
27158
27728
|
const contextSection = context ? `Context: ${context}
|
|
27159
27729
|
|
|
27160
27730
|
` : "";
|
|
@@ -27226,13 +27796,13 @@ async function handleIssue2(event) {
|
|
|
27226
27796
|
const requestedByUserId = await resolveGitLabSender(user, "issue", `Issue #${issue.iid}: ${issue.title}`);
|
|
27227
27797
|
console.log(`[GitLab] Issue #${issue.iid} ${action} by ${user.username} in ${repo}`);
|
|
27228
27798
|
const dedupKey = `gitlab-issue-${repo}-${issue.iid}-${action}-${user.username}`;
|
|
27229
|
-
if (
|
|
27799
|
+
if (isDuplicate4(dedupKey)) {
|
|
27230
27800
|
return { created: false };
|
|
27231
27801
|
}
|
|
27232
|
-
const lead = await
|
|
27802
|
+
const lead = await findLeadAgent4();
|
|
27233
27803
|
switch (action) {
|
|
27234
27804
|
case "open": {
|
|
27235
|
-
const hasMention =
|
|
27805
|
+
const hasMention = detectMention3(issue.description);
|
|
27236
27806
|
if (!hasMention) {
|
|
27237
27807
|
const isBotAssigned = event.assignees?.some((a) => a.username.toLowerCase() === GITLAB_BOT_NAME.toLowerCase());
|
|
27238
27808
|
if (!isBotAssigned) {
|
|
@@ -27240,7 +27810,7 @@ async function handleIssue2(event) {
|
|
|
27240
27810
|
return { created: false };
|
|
27241
27811
|
}
|
|
27242
27812
|
}
|
|
27243
|
-
const context = issue.description ?
|
|
27813
|
+
const context = issue.description ? extractMentionContext3(issue.description) : "";
|
|
27244
27814
|
const contextSection = context ? `Context: ${context}
|
|
27245
27815
|
|
|
27246
27816
|
` : "";
|
|
@@ -27296,16 +27866,16 @@ async function handleNote(event) {
|
|
|
27296
27866
|
const { user, project, object_attributes: note } = event;
|
|
27297
27867
|
const repo = project.path_with_namespace;
|
|
27298
27868
|
const requestedByUserId = await resolveGitLabSender(user, "note", note.note);
|
|
27299
|
-
if (!
|
|
27869
|
+
if (!detectMention3(note.note)) {
|
|
27300
27870
|
return { created: false };
|
|
27301
27871
|
}
|
|
27302
27872
|
console.log(`[GitLab] Note by ${user.username} in ${repo} (${note.noteable_type})`);
|
|
27303
27873
|
const dedupKey = `gitlab-note-${note.id}`;
|
|
27304
|
-
if (
|
|
27874
|
+
if (isDuplicate4(dedupKey)) {
|
|
27305
27875
|
return { created: false };
|
|
27306
27876
|
}
|
|
27307
|
-
const lead = await
|
|
27308
|
-
const context =
|
|
27877
|
+
const lead = await findLeadAgent4();
|
|
27878
|
+
const context = extractMentionContext3(note.note);
|
|
27309
27879
|
let targetNumber;
|
|
27310
27880
|
let targetUrl;
|
|
27311
27881
|
let eventType;
|
|
@@ -27379,14 +27949,14 @@ async function handlePipeline(event) {
|
|
|
27379
27949
|
}
|
|
27380
27950
|
const mrIid = event.merge_request.iid;
|
|
27381
27951
|
const dedupKey = `gitlab-pipeline-${pipeline2.id}`;
|
|
27382
|
-
if (
|
|
27952
|
+
if (isDuplicate4(dedupKey)) {
|
|
27383
27953
|
return { created: false };
|
|
27384
27954
|
}
|
|
27385
27955
|
const existingTask = await findTaskByVcs(repo, mrIid);
|
|
27386
27956
|
if (!existingTask) {
|
|
27387
27957
|
return { created: false };
|
|
27388
27958
|
}
|
|
27389
|
-
const lead = await
|
|
27959
|
+
const lead = await findLeadAgent4();
|
|
27390
27960
|
const pipelineResult = resolveTemplate("gitlab.pipeline.failed", {
|
|
27391
27961
|
pipeline_id: pipeline2.id,
|
|
27392
27962
|
mr_iid: mrIid,
|
|
@@ -27748,14 +28318,14 @@ async function jiraFetch(path, init) {
|
|
|
27748
28318
|
const send = async (token2) => {
|
|
27749
28319
|
const cloudId = await getJiraCloudId();
|
|
27750
28320
|
const url = `https://api.atlassian.com/ex/jira/${cloudId}${path}`;
|
|
27751
|
-
const
|
|
27752
|
-
|
|
27753
|
-
if (!
|
|
27754
|
-
|
|
27755
|
-
if (init?.body && !
|
|
27756
|
-
|
|
27757
|
-
}
|
|
27758
|
-
return fetch(url, { ...init, headers:
|
|
28321
|
+
const headers3 = new Headers(init?.headers);
|
|
28322
|
+
headers3.set("Authorization", `Bearer ${token2}`);
|
|
28323
|
+
if (!headers3.has("Accept"))
|
|
28324
|
+
headers3.set("Accept", "application/json");
|
|
28325
|
+
if (init?.body && !headers3.has("Content-Type")) {
|
|
28326
|
+
headers3.set("Content-Type", "application/json");
|
|
28327
|
+
}
|
|
28328
|
+
return fetch(url, { ...init, headers: headers3 });
|
|
27759
28329
|
};
|
|
27760
28330
|
let token = await getJiraAccessToken();
|
|
27761
28331
|
let response = await send(token);
|
|
@@ -28079,7 +28649,7 @@ async function resolveBotAccountId() {
|
|
|
28079
28649
|
function resetBotAccountIdCache() {
|
|
28080
28650
|
setCachedBotAccountId(null);
|
|
28081
28651
|
}
|
|
28082
|
-
async function
|
|
28652
|
+
async function findLeadAgent5() {
|
|
28083
28653
|
const agents = await getAllAgents();
|
|
28084
28654
|
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
28085
28655
|
if (onlineLead)
|
|
@@ -28283,7 +28853,7 @@ async function handleIssueDeleteEvent(event) {
|
|
|
28283
28853
|
}
|
|
28284
28854
|
}
|
|
28285
28855
|
async function createInitialJiraTask(input) {
|
|
28286
|
-
const lead = await
|
|
28856
|
+
const lead = await findLeadAgent5();
|
|
28287
28857
|
const descriptionSection = input.descriptionText ? `
|
|
28288
28858
|
Description:
|
|
28289
28859
|
${input.descriptionText}
|
|
@@ -28321,7 +28891,7 @@ ${input.descriptionText}
|
|
|
28321
28891
|
console.log(`[Jira Sync] Created ${action} task ${task.id} for ${input.issueKey} -> ${lead?.name ?? "unassigned"}`);
|
|
28322
28892
|
}
|
|
28323
28893
|
async function createCommentMentionTask(input) {
|
|
28324
|
-
const lead = await
|
|
28894
|
+
const lead = await findLeadAgent5();
|
|
28325
28895
|
const descriptionSection = input.descriptionText ? `
|
|
28326
28896
|
Description:
|
|
28327
28897
|
${input.descriptionText}
|
|
@@ -28381,7 +28951,7 @@ async function notifySlack(text) {
|
|
|
28381
28951
|
return;
|
|
28382
28952
|
}
|
|
28383
28953
|
try {
|
|
28384
|
-
const { getSlackApp: getSlackApp2 } = await import("./app-
|
|
28954
|
+
const { getSlackApp: getSlackApp2 } = await import("./app-0hdqa4k1.js");
|
|
28385
28955
|
const app = getSlackApp2();
|
|
28386
28956
|
if (!app) {
|
|
28387
28957
|
console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
|
|
@@ -28452,7 +29022,7 @@ async function deleteJiraWebhook(webhookId) {
|
|
|
28452
29022
|
console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
|
|
28453
29023
|
}
|
|
28454
29024
|
async function overwriteWebhookIds(next) {
|
|
28455
|
-
const { getDbClient: getDbClient2 } = await import("./db-
|
|
29025
|
+
const { getDbClient: getDbClient2 } = await import("./db-d2pvjpyt.js");
|
|
28456
29026
|
await getDbClient2().transaction(async (tx) => {
|
|
28457
29027
|
const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
|
|
28458
29028
|
if (!row) {
|
|
@@ -28559,7 +29129,7 @@ function stopJiraWebhookKeepalive() {
|
|
|
28559
29129
|
}
|
|
28560
29130
|
|
|
28561
29131
|
// src/jira/app.ts
|
|
28562
|
-
var
|
|
29132
|
+
var initialized5 = false;
|
|
28563
29133
|
function isJiraEnabled() {
|
|
28564
29134
|
const disabled = process.env.JIRA_DISABLE;
|
|
28565
29135
|
if (disabled === "true" || disabled === "1")
|
|
@@ -28573,12 +29143,12 @@ function resetJira() {
|
|
|
28573
29143
|
resetBotAccountIdCache();
|
|
28574
29144
|
teardownJiraOutboundSync();
|
|
28575
29145
|
stopJiraWebhookKeepalive();
|
|
28576
|
-
|
|
29146
|
+
initialized5 = false;
|
|
28577
29147
|
}
|
|
28578
29148
|
async function initJira() {
|
|
28579
|
-
if (
|
|
29149
|
+
if (initialized5)
|
|
28580
29150
|
return isJiraEnabled();
|
|
28581
|
-
|
|
29151
|
+
initialized5 = true;
|
|
28582
29152
|
if (!isJiraEnabled()) {
|
|
28583
29153
|
console.log("[Jira] Integration disabled or JIRA_CLIENT_ID not set");
|
|
28584
29154
|
return false;
|
|
@@ -28799,14 +29369,14 @@ var InvalidInputLinearError = class extends LinearError {
|
|
|
28799
29369
|
var RatelimitedLinearError = class extends LinearError {
|
|
28800
29370
|
constructor(error, errors) {
|
|
28801
29371
|
super(error, errors, LinearErrorType.Ratelimited);
|
|
28802
|
-
const
|
|
28803
|
-
this.retryAfter = this.parseNumber(
|
|
28804
|
-
this.requestsLimit = this.parseNumber(
|
|
28805
|
-
this.requestsRemaining = this.parseNumber(
|
|
28806
|
-
this.requestsResetAt = this.parseNumber(
|
|
28807
|
-
this.complexityLimit = this.parseNumber(
|
|
28808
|
-
this.complexityRemaining = this.parseNumber(
|
|
28809
|
-
this.complexityResetAt = this.parseNumber(
|
|
29372
|
+
const headers3 = error?.response?.headers;
|
|
29373
|
+
this.retryAfter = this.parseNumber(headers3?.get("retry-after"));
|
|
29374
|
+
this.requestsLimit = this.parseNumber(headers3?.get("x-ratelimit-requests-limit"));
|
|
29375
|
+
this.requestsRemaining = this.parseNumber(headers3?.get("x-ratelimit-requests-remaining"));
|
|
29376
|
+
this.requestsResetAt = this.parseNumber(headers3?.get("x-ratelimit-requests-reset"));
|
|
29377
|
+
this.complexityLimit = this.parseNumber(headers3?.get("x-ratelimit-complexity-limit"));
|
|
29378
|
+
this.complexityRemaining = this.parseNumber(headers3?.get("x-ratelimit-complexity-remaining"));
|
|
29379
|
+
this.complexityResetAt = this.parseNumber(headers3?.get("x-ratelimit-complexity-reset"));
|
|
28810
29380
|
}
|
|
28811
29381
|
retryAfter;
|
|
28812
29382
|
requestsLimit;
|
|
@@ -29829,7 +30399,7 @@ var LinearGraphQLClient = class {
|
|
|
29829
30399
|
this.options = options || {};
|
|
29830
30400
|
}
|
|
29831
30401
|
async rawRequest(query, variables, requestHeaders) {
|
|
29832
|
-
const { headers:
|
|
30402
|
+
const { headers: headers3, ...others } = this.options;
|
|
29833
30403
|
const body = JSON.stringify({
|
|
29834
30404
|
query,
|
|
29835
30405
|
variables
|
|
@@ -29839,7 +30409,7 @@ var LinearGraphQLClient = class {
|
|
|
29839
30409
|
method: "POST",
|
|
29840
30410
|
headers: {
|
|
29841
30411
|
...typeof body === "string" ? { "Content-Type": "application/json" } : {},
|
|
29842
|
-
...resolveHeaders(
|
|
30412
|
+
...resolveHeaders(headers3),
|
|
29843
30413
|
...resolveHeaders(requestHeaders)
|
|
29844
30414
|
},
|
|
29845
30415
|
body,
|
|
@@ -29863,7 +30433,7 @@ var LinearGraphQLClient = class {
|
|
|
29863
30433
|
}));
|
|
29864
30434
|
}
|
|
29865
30435
|
async request(document2, variables, requestHeaders) {
|
|
29866
|
-
const { headers:
|
|
30436
|
+
const { headers: headers3, ...others } = this.options;
|
|
29867
30437
|
const query = typeof document2 === "string" ? document2 : (0, import_printer.print)(document2);
|
|
29868
30438
|
const body = JSON.stringify({
|
|
29869
30439
|
query,
|
|
@@ -29873,7 +30443,7 @@ var LinearGraphQLClient = class {
|
|
|
29873
30443
|
method: "POST",
|
|
29874
30444
|
headers: {
|
|
29875
30445
|
...typeof body === "string" ? { "Content-Type": "application/json" } : {},
|
|
29876
|
-
...resolveHeaders(
|
|
30446
|
+
...resolveHeaders(headers3),
|
|
29877
30447
|
...resolveHeaders(requestHeaders)
|
|
29878
30448
|
},
|
|
29879
30449
|
body,
|
|
@@ -29892,14 +30462,14 @@ var LinearGraphQLClient = class {
|
|
|
29892
30462
|
variables
|
|
29893
30463
|
});
|
|
29894
30464
|
}
|
|
29895
|
-
setHeaders(
|
|
29896
|
-
this.options.headers =
|
|
30465
|
+
setHeaders(headers3) {
|
|
30466
|
+
this.options.headers = headers3;
|
|
29897
30467
|
return this;
|
|
29898
30468
|
}
|
|
29899
30469
|
setHeader(key, value) {
|
|
29900
|
-
const { headers:
|
|
29901
|
-
if (
|
|
29902
|
-
|
|
30470
|
+
const { headers: headers3 } = this.options;
|
|
30471
|
+
if (headers3)
|
|
30472
|
+
headers3[key] = value;
|
|
29903
30473
|
else
|
|
29904
30474
|
this.options.headers = { [key]: value };
|
|
29905
30475
|
return this;
|
|
@@ -29912,22 +30482,22 @@ function getResult(response) {
|
|
|
29912
30482
|
else
|
|
29913
30483
|
return response.text();
|
|
29914
30484
|
}
|
|
29915
|
-
function resolveHeaders(
|
|
30485
|
+
function resolveHeaders(headers3) {
|
|
29916
30486
|
let oHeaders = {};
|
|
29917
|
-
if (
|
|
29918
|
-
if (typeof Headers !== "undefined" &&
|
|
29919
|
-
oHeaders = headersToObject(
|
|
29920
|
-
else if (Array.isArray(
|
|
29921
|
-
|
|
30487
|
+
if (headers3)
|
|
30488
|
+
if (typeof Headers !== "undefined" && headers3 instanceof Headers)
|
|
30489
|
+
oHeaders = headersToObject(headers3);
|
|
30490
|
+
else if (Array.isArray(headers3))
|
|
30491
|
+
headers3.forEach(([name, value]) => {
|
|
29922
30492
|
oHeaders[name] = value;
|
|
29923
30493
|
});
|
|
29924
30494
|
else
|
|
29925
|
-
oHeaders =
|
|
30495
|
+
oHeaders = headers3;
|
|
29926
30496
|
return oHeaders;
|
|
29927
30497
|
}
|
|
29928
|
-
function headersToObject(
|
|
30498
|
+
function headersToObject(headers3) {
|
|
29929
30499
|
const o = {};
|
|
29930
|
-
|
|
30500
|
+
headers3.forEach((v, k) => {
|
|
29931
30501
|
o[k] = v;
|
|
29932
30502
|
});
|
|
29933
30503
|
return o;
|
|
@@ -93790,8 +94360,8 @@ var IssueVcsBranchSearchQuery = class extends Request2 {
|
|
|
93790
94360
|
constructor(request) {
|
|
93791
94361
|
super(request);
|
|
93792
94362
|
}
|
|
93793
|
-
async fetch(
|
|
93794
|
-
const data = (await this._request(IssueVcsBranchSearchDocument.toString(), { branchName })).issueVcsBranchSearch;
|
|
94363
|
+
async fetch(branchName2) {
|
|
94364
|
+
const data = (await this._request(IssueVcsBranchSearchDocument.toString(), { branchName: branchName2 })).issueVcsBranchSearch;
|
|
93795
94365
|
return data ? new Issue(this._request, data) : undefined;
|
|
93796
94366
|
}
|
|
93797
94367
|
};
|
|
@@ -99124,8 +99694,8 @@ var LinearSdk = class extends Request2 {
|
|
|
99124
99694
|
issueTitleSuggestionFromCustomerRequest(request) {
|
|
99125
99695
|
return new IssueTitleSuggestionFromCustomerRequestQuery(this._request).fetch(request);
|
|
99126
99696
|
}
|
|
99127
|
-
issueVcsBranchSearch(
|
|
99128
|
-
return new IssueVcsBranchSearchQuery(this._request).fetch(
|
|
99697
|
+
issueVcsBranchSearch(branchName2) {
|
|
99698
|
+
return new IssueVcsBranchSearchQuery(this._request).fetch(branchName2);
|
|
99129
99699
|
}
|
|
99130
99700
|
issues(variables) {
|
|
99131
99701
|
return new IssuesQuery(this._request).fetch(variables);
|
|
@@ -100142,13 +100712,13 @@ var LinearSdk = class extends Request2 {
|
|
|
100142
100712
|
return new UpdateWorkflowStateMutation(this._request).fetch(id, input);
|
|
100143
100713
|
}
|
|
100144
100714
|
};
|
|
100145
|
-
function parseClientOptions({ apiKey, accessToken, apiUrl, headers:
|
|
100715
|
+
function parseClientOptions({ apiKey, accessToken, apiUrl, headers: headers3, ...opts }) {
|
|
100146
100716
|
if (!accessToken && !apiKey)
|
|
100147
100717
|
throw new Error("No accessToken or apiKey provided to the LinearClient - create one here: https://linear.app/settings/account/security");
|
|
100148
100718
|
return {
|
|
100149
100719
|
headers: {
|
|
100150
100720
|
Authorization: accessToken ? accessToken.startsWith("Bearer ") ? accessToken : `Bearer ${accessToken}` : apiKey ?? "",
|
|
100151
|
-
...
|
|
100721
|
+
...headers3,
|
|
100152
100722
|
"User-Agent": serializeUserAgent({ [process.env.npm_package_name ?? "@linear/sdk"]: process.env.npm_package_version ?? "unknown" })
|
|
100153
100723
|
},
|
|
100154
100724
|
apiUrl: apiUrl ?? "https://api.linear.app/graphql",
|
|
@@ -100464,15 +101034,15 @@ async function _fetchIssueGatingInfo(issueId) {
|
|
|
100464
101034
|
const labelNames = (json.data?.issue?.labels?.nodes ?? []).map((n) => n?.name ?? "").filter((n) => n.length > 0);
|
|
100465
101035
|
return { stateType, labelNames };
|
|
100466
101036
|
}
|
|
100467
|
-
async function
|
|
101037
|
+
async function findLeadAgent6() {
|
|
100468
101038
|
const agents = await getAllAgents();
|
|
100469
101039
|
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
100470
101040
|
if (onlineLead)
|
|
100471
101041
|
return onlineLead;
|
|
100472
101042
|
return agents.find((a) => a.isLead) ?? null;
|
|
100473
101043
|
}
|
|
100474
|
-
var
|
|
100475
|
-
var
|
|
101044
|
+
var UNMAPPED_NAMESPACE4 = "integration:unmapped:linear";
|
|
101045
|
+
var UNMAPPED_TTL_MS4 = 30 * 24 * 60 * 60 * 1000;
|
|
100476
101046
|
var LINEAR_WEBHOOK_ACTOR = { kind: "system", id: "webhook:linear" };
|
|
100477
101047
|
var APP_USER_ID_NAMESPACE = "integration:linear:bot-app-user-id";
|
|
100478
101048
|
async function getStoredAppUserId(workspaceId) {
|
|
@@ -100503,7 +101073,7 @@ async function resolveLinearActor(linearUserId, email, name, workspaceId, sample
|
|
|
100503
101073
|
return linked.id;
|
|
100504
101074
|
}
|
|
100505
101075
|
await upsertKv({
|
|
100506
|
-
namespace:
|
|
101076
|
+
namespace: UNMAPPED_NAMESPACE4,
|
|
100507
101077
|
key: `${linearUserId}:meta`,
|
|
100508
101078
|
value: {
|
|
100509
101079
|
lastSeenAt: new Date().toISOString(),
|
|
@@ -100511,9 +101081,9 @@ async function resolveLinearActor(linearUserId, email, name, workspaceId, sample
|
|
|
100511
101081
|
sampleContext: sampleContext ? sampleContext.slice(0, 100) : null
|
|
100512
101082
|
},
|
|
100513
101083
|
valueType: "json",
|
|
100514
|
-
expiresAt: Date.now() +
|
|
101084
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS4
|
|
100515
101085
|
});
|
|
100516
|
-
await incrKv(
|
|
101086
|
+
await incrKv(UNMAPPED_NAMESPACE4, `${linearUserId}:count`, 1);
|
|
100517
101087
|
return;
|
|
100518
101088
|
}
|
|
100519
101089
|
async function handleAgentSessionEvent(event) {
|
|
@@ -100584,7 +101154,7 @@ async function handleAgentSessionEvent(event) {
|
|
|
100584
101154
|
}
|
|
100585
101155
|
return;
|
|
100586
101156
|
}
|
|
100587
|
-
const lead = await
|
|
101157
|
+
const lead = await findLeadAgent6();
|
|
100588
101158
|
const sessionSection = sessionUrl ? `
|
|
100589
101159
|
Session: ${sessionUrl}` : "";
|
|
100590
101160
|
const descriptionSection = issueDescription ? `
|
|
@@ -100785,7 +101355,7 @@ async function handleAgentSessionPrompted(event) {
|
|
|
100785
101355
|
return;
|
|
100786
101356
|
}
|
|
100787
101357
|
}
|
|
100788
|
-
const lead = await
|
|
101358
|
+
const lead = await findLeadAgent6();
|
|
100789
101359
|
const activity = event.agentActivity;
|
|
100790
101360
|
const promptUser = activity?.user;
|
|
100791
101361
|
const promptedActorLinearId = promptUser ? String(promptUser.id ?? "") : "";
|
|
@@ -101067,7 +101637,7 @@ function shouldSkipForLoopPrevention2(sync) {
|
|
|
101067
101637
|
}
|
|
101068
101638
|
|
|
101069
101639
|
// src/linear/app.ts
|
|
101070
|
-
var
|
|
101640
|
+
var initialized6 = false;
|
|
101071
101641
|
var unsubscribeRefresh = null;
|
|
101072
101642
|
function isLinearEnabled() {
|
|
101073
101643
|
const disabled = process.env.LINEAR_DISABLE;
|
|
@@ -101084,12 +101654,12 @@ function resetLinear() {
|
|
|
101084
101654
|
unsubscribeRefresh();
|
|
101085
101655
|
unsubscribeRefresh = null;
|
|
101086
101656
|
}
|
|
101087
|
-
|
|
101657
|
+
initialized6 = false;
|
|
101088
101658
|
}
|
|
101089
101659
|
async function initLinear() {
|
|
101090
|
-
if (
|
|
101660
|
+
if (initialized6)
|
|
101091
101661
|
return isLinearEnabled();
|
|
101092
|
-
|
|
101662
|
+
initialized6 = true;
|
|
101093
101663
|
if (!isLinearEnabled()) {
|
|
101094
101664
|
console.log("[Linear] Integration disabled or LINEAR_CLIENT_ID not set");
|
|
101095
101665
|
return false;
|
|
@@ -102184,7 +102754,7 @@ async function reloadGlobalConfigsAndIntegrations() {
|
|
|
102184
102754
|
return runWithoutRequestAuth(() => reloadGlobalConfigsAndIntegrationsInner());
|
|
102185
102755
|
}
|
|
102186
102756
|
async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
102187
|
-
const { getEmbeddingProvider: getEmbeddingProvider2, resetEmbeddingProvider } = await import("./index-
|
|
102757
|
+
const { getEmbeddingProvider: getEmbeddingProvider2, resetEmbeddingProvider } = await import("./index-k4nj18qs.js");
|
|
102188
102758
|
const wasEmbeddingsConfigured = getEmbeddingProvider2().isConfigured();
|
|
102189
102759
|
const updated = await loadGlobalConfigsIntoEnv(true);
|
|
102190
102760
|
await stopSlackApp();
|
|
@@ -102197,10 +102767,10 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
|
102197
102767
|
integrations.push("embeddings");
|
|
102198
102768
|
}
|
|
102199
102769
|
if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
|
|
102200
|
-
import("./boot-reembed-
|
|
102770
|
+
import("./boot-reembed-gt5gjkt4.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
|
|
102201
102771
|
console.error("[config-reload] memory backfill failed (non-fatal):", err);
|
|
102202
102772
|
});
|
|
102203
|
-
import("./boot-reembed-
|
|
102773
|
+
import("./boot-reembed-xy9t7avg.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
|
|
102204
102774
|
console.error("[config-reload] script backfill failed (non-fatal):", err);
|
|
102205
102775
|
});
|
|
102206
102776
|
}
|
|
@@ -102214,6 +102784,11 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
|
102214
102784
|
initGitLab();
|
|
102215
102785
|
if (isGitLabEnabled())
|
|
102216
102786
|
integrations.push("gitlab");
|
|
102787
|
+
resetAzureDevOps();
|
|
102788
|
+
resetAzureDevOpsBotIdCache();
|
|
102789
|
+
initAzureDevOps();
|
|
102790
|
+
if (isAzureDevOpsEnabled())
|
|
102791
|
+
integrations.push("azure-devops");
|
|
102217
102792
|
resetLinear();
|
|
102218
102793
|
if (await initLinear())
|
|
102219
102794
|
integrations.push("linear");
|
|
@@ -103013,7 +103588,7 @@ function setPreloadedTools(server, names) {
|
|
|
103013
103588
|
async function applyPreToolCall(name, args, requestInfo, inputSchema) {
|
|
103014
103589
|
if (requestInfo.callOrigin !== "mcp")
|
|
103015
103590
|
return { args };
|
|
103016
|
-
const dispatcher = await import("./dispatcher-
|
|
103591
|
+
const dispatcher = await import("./dispatcher-8wbwyzjg.js");
|
|
103017
103592
|
const result = await dispatcher.dispatchPre("pre.tool.call", { tool: name, args, requestInfo }, inputSchema ? {
|
|
103018
103593
|
validateModify: async (data) => {
|
|
103019
103594
|
const schema = normalizeObjectSchema(inputSchema) ?? inputSchema;
|
|
@@ -105065,6 +105640,7 @@ var registerContextDiffTool = (server) => {
|
|
|
105065
105640
|
fromVersion: number().optional(),
|
|
105066
105641
|
toVersion: number().optional(),
|
|
105067
105642
|
diff: string().optional(),
|
|
105643
|
+
predecessorPruned: boolean().optional(),
|
|
105068
105644
|
changeSource: string().optional(),
|
|
105069
105645
|
createdAt: string().optional()
|
|
105070
105646
|
})
|
|
@@ -105112,6 +105688,20 @@ var registerContextDiffTool = (server) => {
|
|
|
105112
105688
|
} else if (version.previousVersionId) {
|
|
105113
105689
|
compareVersion = await getContextVersion(version.previousVersionId);
|
|
105114
105690
|
}
|
|
105691
|
+
if (!compareToVersionId && !compareVersion && version.version > 1) {
|
|
105692
|
+
const message = `No predecessor for ${version.field} v${version.version}: v${version.version - 1} was removed by context version retention. Pass compareToVersionId with a surviving version from context-history.`;
|
|
105693
|
+
return toolOk(message, {
|
|
105694
|
+
details: message,
|
|
105695
|
+
data: {
|
|
105696
|
+
yourAgentId: requestInfo.agentId,
|
|
105697
|
+
field: version.field,
|
|
105698
|
+
toVersion: version.version,
|
|
105699
|
+
predecessorPruned: true,
|
|
105700
|
+
changeSource: version.changeSource,
|
|
105701
|
+
createdAt: version.createdAt
|
|
105702
|
+
}
|
|
105703
|
+
});
|
|
105704
|
+
}
|
|
105115
105705
|
const oldContent = compareVersion?.content ?? "";
|
|
105116
105706
|
const diff = await computeDiff(oldContent, version.content);
|
|
105117
105707
|
const fromVersion = compareVersion?.version ?? 0;
|
|
@@ -109426,8 +110016,8 @@ async function applyRating(events, ctx = {}) {
|
|
|
109426
110016
|
const UPDATE_MEMORY_SQL = "UPDATE agent_memory SET alpha = alpha + ?, beta = beta + ? WHERE id = ?";
|
|
109427
110017
|
const CHECK_EXISTS_SQL = "SELECT id FROM agent_memory WHERE id = ?";
|
|
109428
110018
|
const INSERT_RATING_SQL = `INSERT INTO memory_rating
|
|
109429
|
-
(id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey)
|
|
109430
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
110019
|
+
(id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey, model)
|
|
110020
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
109431
110021
|
const UPSERT_EDGE_SQL = `INSERT INTO agent_memory_edge (from_id, to_id, type, alpha, beta, createdAt)
|
|
109432
110022
|
VALUES (?, ?, 'references-source', ?, ?, ?)
|
|
109433
110023
|
ON CONFLICT(from_id, to_id, type) DO UPDATE SET
|
|
@@ -109456,7 +110046,8 @@ async function applyRating(events, ctx = {}) {
|
|
|
109456
110046
|
event.weight,
|
|
109457
110047
|
event.reasoning ?? null,
|
|
109458
110048
|
new Date().toISOString(),
|
|
109459
|
-
ctx.contextKey ?? null
|
|
110049
|
+
ctx.contextKey ?? null,
|
|
110050
|
+
event.source === "llm" ? event.model ?? null : null
|
|
109460
110051
|
]);
|
|
109461
110052
|
} catch (err) {
|
|
109462
110053
|
if (isUniqueConstraintError(err)) {
|
|
@@ -110660,20 +111251,20 @@ async function proxySwarmApi(args) {
|
|
|
110660
111251
|
if (!args.requestInfo.agentId)
|
|
110661
111252
|
return toolErr(args.transportError);
|
|
110662
111253
|
const apiKey = getApiKey();
|
|
110663
|
-
const
|
|
111254
|
+
const headers3 = {
|
|
110664
111255
|
Authorization: `Bearer ${apiKey}`,
|
|
110665
111256
|
"X-Agent-ID": args.requestInfo.agentId,
|
|
110666
111257
|
"Content-Type": "application/json"
|
|
110667
111258
|
};
|
|
110668
111259
|
if (args.requestInfo.sourceTaskId) {
|
|
110669
|
-
|
|
111260
|
+
headers3["X-Source-Task-Id"] = args.requestInfo.sourceTaskId;
|
|
110670
111261
|
}
|
|
110671
111262
|
if (args.requestInfo.runtimeInstanceId) {
|
|
110672
|
-
|
|
111263
|
+
headers3["X-Runtime-Instance-ID"] = args.requestInfo.runtimeInstanceId;
|
|
110673
111264
|
}
|
|
110674
111265
|
const res = await fetch(`${apiBaseUrl()}${args.path}`, {
|
|
110675
111266
|
method: args.method,
|
|
110676
|
-
headers:
|
|
111267
|
+
headers: headers3,
|
|
110677
111268
|
body: args.body === undefined ? undefined : JSON.stringify(args.body)
|
|
110678
111269
|
});
|
|
110679
111270
|
const text = await res.text();
|
|
@@ -110908,7 +111499,15 @@ var registerExtensionEnableTool = (server) => {
|
|
|
110908
111499
|
|
|
110909
111500
|
// src/tools/extension-install.ts
|
|
110910
111501
|
init_zod();
|
|
110911
|
-
|
|
111502
|
+
init_types();
|
|
111503
|
+
var EXTENSION_INSTALL_DESCRIPTION = "Install an extension from the catalog by `template` name (extension-catalog, GET /api/extensions/catalog), or from an inline bundle: `manifest` plus a `files` map keyed by bundle path. `template` and `manifest`/`files` are mutually exclusive. Inline bundles are accepted only when the deployment sets EXTENSION_ALLOW_INLINE_INSTALL=true, and only from lead, operator and dashboard-user callers. Workers are denied (403) and stay catalog-only; with the flag off the call fails with inline_install_disabled. Before writing an inline bundle, fetch the hook contract: GET /api/extensions/type-defs returns swarm-extension.d.ts. Install creates the extension, its ext:<name> agent and every asset it declares (scripts, and disabled schedules, workflows and skills). Any authenticated agent may install from the catalog; the installing agent is recorded as createdByAgentId. Workers may install subsequent versions only for their own extensions; those versions remain inactive. A new extension remains disabled until a lead, operator, or dashboard user enables it with extension-enable.";
|
|
111504
|
+
var extensionInstallInputSchema = object({
|
|
111505
|
+
template: string().min(1).optional().describe("Name of a predefined extension from extension-catalog. Mutually exclusive with manifest and files."),
|
|
111506
|
+
manifest: ExtensionManifestSchema.optional().describe("Inline bundle manifest. Requires files. Needs EXTENSION_ALLOW_INLINE_INSTALL and a lead, operator, or dashboard-user caller."),
|
|
111507
|
+
files: record(string(), string()).optional().describe("Inline bundle files keyed by relative path. Requires manifest."),
|
|
111508
|
+
priority: number().int().optional().describe("Handler priority. Lower values run first."),
|
|
111509
|
+
config: record(string(), unknown()).optional().describe("Extension configuration.")
|
|
111510
|
+
}).strict().superRefine(checkExtensionInstallSource);
|
|
110912
111511
|
function extensionInstallResult(data, fallbackName) {
|
|
110913
111512
|
const body = data;
|
|
110914
111513
|
const extension = coerceExtensionSummary(body.extension);
|
|
@@ -110929,18 +111528,14 @@ var registerExtensionInstallTool = (server) => {
|
|
|
110929
111528
|
title: "Extension Install",
|
|
110930
111529
|
description: EXTENSION_INSTALL_DESCRIPTION,
|
|
110931
111530
|
annotations: { openWorldHint: false },
|
|
110932
|
-
inputSchema:
|
|
110933
|
-
template: string().min(1).describe("Name of a predefined extension from extension-catalog."),
|
|
110934
|
-
priority: number().int().optional().describe("Handler priority. Lower values run first."),
|
|
110935
|
-
config: record(string(), unknown()).optional().describe("Extension configuration.")
|
|
110936
|
-
}).strict(),
|
|
111531
|
+
inputSchema: extensionInstallInputSchema,
|
|
110937
111532
|
outputSchema: extensionToolOutputSchema
|
|
110938
111533
|
}, async (args, requestInfo) => proxyExtensionsApi({
|
|
110939
111534
|
method: "POST",
|
|
110940
111535
|
path: "/api/extensions/install",
|
|
110941
111536
|
body: args,
|
|
110942
111537
|
requestInfo,
|
|
110943
|
-
success: (data) => extensionInstallResult(data, args.template)
|
|
111538
|
+
success: (data) => extensionInstallResult(data, args.template ?? args.manifest?.name ?? "extension")
|
|
110944
111539
|
}));
|
|
110945
111540
|
};
|
|
110946
111541
|
|
|
@@ -112591,6 +113186,52 @@ var registerMemoryDeleteTool = (server) => {
|
|
|
112591
113186
|
init_zod();
|
|
112592
113187
|
init_db();
|
|
112593
113188
|
|
|
113189
|
+
// src/be/memory/key-guard.ts
|
|
113190
|
+
init_key_paths();
|
|
113191
|
+
|
|
113192
|
+
class MemoryKeyError extends Error {
|
|
113193
|
+
reason;
|
|
113194
|
+
constructor(message, reason) {
|
|
113195
|
+
super(message);
|
|
113196
|
+
this.reason = reason;
|
|
113197
|
+
this.name = "MemoryKeyError";
|
|
113198
|
+
}
|
|
113199
|
+
}
|
|
113200
|
+
var NO_AUTHORITY = {
|
|
113201
|
+
principal: { kind: "agent", agentId: "", isLead: false },
|
|
113202
|
+
source: "http"
|
|
113203
|
+
};
|
|
113204
|
+
function shapeError(key, origin) {
|
|
113205
|
+
if (key.length <= MEMORY_KEY_MAX_LENGTH && MEMORY_KEY_PATTERN.test(key))
|
|
113206
|
+
return null;
|
|
113207
|
+
const subject = origin === "sourcePath" ? `sourcePath "${key}" starts with ${LONGTERM_ROOT}, so it is used as the key, but it is not a valid key.` : `Key "${key}" is not a valid key.`;
|
|
113208
|
+
return `${subject} ${MEMORY_KEY_PATTERN_MESSAGE}`;
|
|
113209
|
+
}
|
|
113210
|
+
function assertKeyWritable(key, origin, writer) {
|
|
113211
|
+
if (origin === "sourcePath" && !isLongtermKey(key))
|
|
113212
|
+
return;
|
|
113213
|
+
const shape = shapeError(key, origin);
|
|
113214
|
+
if (shape)
|
|
113215
|
+
throw new MemoryKeyError(shape, "invalid");
|
|
113216
|
+
const pathError = longtermKeyError(key);
|
|
113217
|
+
if (pathError)
|
|
113218
|
+
throw new MemoryKeyError(pathError, "invalid");
|
|
113219
|
+
if (!isConsolidatedKey(key))
|
|
113220
|
+
return;
|
|
113221
|
+
const { principal, source } = writer ?? NO_AUTHORITY;
|
|
113222
|
+
const decision = can({
|
|
113223
|
+
principal,
|
|
113224
|
+
verb: "memory.write.consolidated",
|
|
113225
|
+
resource: { kind: "none" },
|
|
113226
|
+
source
|
|
113227
|
+
});
|
|
113228
|
+
if (!decision.allow)
|
|
113229
|
+
throw new MemoryKeyError(consolidatedKeyMessage(key), "forbidden");
|
|
113230
|
+
}
|
|
113231
|
+
|
|
113232
|
+
// src/tools/memory-edit.ts
|
|
113233
|
+
init_key_paths();
|
|
113234
|
+
|
|
112594
113235
|
// src/be/memory/link-resolver.ts
|
|
112595
113236
|
init_db();
|
|
112596
113237
|
var WIKILINK_RE = /\[\[([^\]]+)\]\]/g;
|
|
@@ -112805,7 +113446,7 @@ var agentMemoryOutputSchema = looseObject({
|
|
|
112805
113446
|
var registerMemoryEditTool = (server) => {
|
|
112806
113447
|
createToolRegistrar(server)("memory-edit", {
|
|
112807
113448
|
title: "Edit a memory",
|
|
112808
|
-
description: "Edit a single memory in place while preserving its ID, usefulness posterior, and audit history. Two modes: 'replace' overwrites the entire content (requires `content`); 'exact' performs a surgical find-and-replace of `oldString` with `newString` within the existing content (fails if `oldString` is missing or ambiguous). Use 'replace' for full rewrites, 'exact' for targeted edits. Agents can edit their own memories; lead agents can edit any scope.",
|
|
113449
|
+
description: "Edit a single memory in place while preserving its ID, usefulness posterior, and audit history. Two modes: 'replace' overwrites the entire content (requires `content`); 'exact' performs a surgical find-and-replace of `oldString` with `newString` within the existing content (fails if `oldString` is missing or ambiguous). Use 'replace' for full rewrites, 'exact' for targeted edits. Pass `newKey` alone to move the memory to another logical path (every chunk, same ID, posterior, access counts and author). A move into /longterm also clears the expiry. Agents can edit their own memories; lead agents can edit any scope.",
|
|
112809
113450
|
annotations: { destructiveHint: true },
|
|
112810
113451
|
inputSchema: object({
|
|
112811
113452
|
memoryId: uuid().optional().describe("The memory ID to edit."),
|
|
@@ -112816,7 +113457,8 @@ var registerMemoryEditTool = (server) => {
|
|
|
112816
113457
|
oldString: string().min(1).optional().describe("Substring to find in existing content. Required for 'exact' mode. Must appear exactly once."),
|
|
112817
113458
|
newString: string().optional().describe("Replacement for oldString. Required for 'exact' mode. Can be empty to delete."),
|
|
112818
113459
|
intent: string().min(1).describe("Why you are editing this memory."),
|
|
112819
|
-
expectedVersion: number().int().min(1).optional()
|
|
113460
|
+
expectedVersion: number().int().min(1).optional(),
|
|
113461
|
+
newKey: string().max(MEMORY_KEY_MAX_LENGTH).regex(MEMORY_KEY_PATTERN, MEMORY_KEY_PATTERN_MESSAGE).optional().describe("Move the memory to this logical path, for example '/longterm/facts/swarm-runtime/slug'. Alone it is a pure move: omit content/oldString/newString. Fails when the key is already used in this scope by the same owner. Moving into /longterm marks the memory as curated on every chunk: it stops expiring and is protected from cleanup, and moving it out later does not bring the expiry back. A key under /longterm must start with /longterm/company-story, /longterm/entities/people, /longterm/entities/customers, /longterm/facts, /longterm/decisions, /longterm/workstreams or /longterm/timeline. Paths under /longterm/company-story, /longterm/entities and /longterm/timeline are lead-only.")
|
|
112820
113462
|
}),
|
|
112821
113463
|
outputSchema: swarmToolOutputSchema({
|
|
112822
113464
|
yourAgentId: string().optional(),
|
|
@@ -112825,7 +113467,18 @@ var registerMemoryEditTool = (server) => {
|
|
|
112825
113467
|
previousVersion: number().int().optional(),
|
|
112826
113468
|
version: number().int().optional()
|
|
112827
113469
|
})
|
|
112828
|
-
}, async ({
|
|
113470
|
+
}, async ({
|
|
113471
|
+
memoryId,
|
|
113472
|
+
key,
|
|
113473
|
+
scope,
|
|
113474
|
+
mode,
|
|
113475
|
+
content,
|
|
113476
|
+
oldString,
|
|
113477
|
+
newString,
|
|
113478
|
+
intent,
|
|
113479
|
+
expectedVersion,
|
|
113480
|
+
newKey
|
|
113481
|
+
}, requestInfo, _meta) => {
|
|
112829
113482
|
if (!requestInfo.agentId) {
|
|
112830
113483
|
return toolErr("Agent ID required. Are you registered in the swarm?");
|
|
112831
113484
|
}
|
|
@@ -112835,6 +113488,17 @@ var registerMemoryEditTool = (server) => {
|
|
|
112835
113488
|
});
|
|
112836
113489
|
}
|
|
112837
113490
|
try {
|
|
113491
|
+
if (newKey) {
|
|
113492
|
+
const agent = await getAgentById(requestInfo.agentId);
|
|
113493
|
+
assertKeyWritable(newKey, "key", {
|
|
113494
|
+
principal: {
|
|
113495
|
+
kind: "agent",
|
|
113496
|
+
agentId: requestInfo.agentId,
|
|
113497
|
+
isLead: agent?.isLead ?? false
|
|
113498
|
+
},
|
|
113499
|
+
source: "mcp"
|
|
113500
|
+
});
|
|
113501
|
+
}
|
|
112838
113502
|
const store = getMemoryStore();
|
|
112839
113503
|
if (memoryId) {
|
|
112840
113504
|
const memory = await store.peek(memoryId);
|
|
@@ -112871,9 +113535,11 @@ var registerMemoryEditTool = (server) => {
|
|
|
112871
113535
|
newString,
|
|
112872
113536
|
intent,
|
|
112873
113537
|
expectedVersion,
|
|
112874
|
-
changedByAgentId: requestInfo.agentId
|
|
113538
|
+
changedByAgentId: requestInfo.agentId,
|
|
113539
|
+
newKey
|
|
112875
113540
|
});
|
|
112876
|
-
|
|
113541
|
+
const contentEdited = content !== undefined || oldString !== undefined || newString !== undefined;
|
|
113542
|
+
if (result.changed && (newKey === undefined || contentEdited)) {
|
|
112877
113543
|
const provider = getEmbeddingProvider();
|
|
112878
113544
|
const embedding = await provider.embed(result.memory.content);
|
|
112879
113545
|
if (embedding)
|
|
@@ -112894,6 +113560,9 @@ var registerMemoryEditTool = (server) => {
|
|
|
112894
113560
|
}
|
|
112895
113561
|
});
|
|
112896
113562
|
} catch (err) {
|
|
113563
|
+
if (err instanceof MemoryKeyError) {
|
|
113564
|
+
return toolErr(err.message, { data: { yourAgentId: requestInfo.agentId } });
|
|
113565
|
+
}
|
|
112897
113566
|
return toolErr(`Memory edit failed: ${err.message}`, {
|
|
112898
113567
|
data: { yourAgentId: requestInfo.agentId }
|
|
112899
113568
|
});
|
|
@@ -113231,7 +113900,7 @@ function addNeighborScopeConditions(conditions, params, agentId, scope, isLead)
|
|
|
113231
113900
|
async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
|
|
113232
113901
|
if (!isGraphExpansionEnabled())
|
|
113233
113902
|
return candidates;
|
|
113234
|
-
const { cap = 5, damping = 0.7, scope = "all", source, isLead = false } = options;
|
|
113903
|
+
const { cap = 5, damping = 0.7, scope = "all", source, keyPrefix, isLead = false } = options;
|
|
113235
113904
|
if (candidates.length === 0 || cap <= 0)
|
|
113236
113905
|
return candidates;
|
|
113237
113906
|
const parentById = new Map(candidates.map((c) => [c.id, c]));
|
|
@@ -113247,6 +113916,10 @@ async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
|
|
|
113247
113916
|
conditions.push("m.source = ?");
|
|
113248
113917
|
params.push(source);
|
|
113249
113918
|
}
|
|
113919
|
+
if (keyPrefix) {
|
|
113920
|
+
conditions.push("substr(m.key, 1, length(?)) = ?");
|
|
113921
|
+
params.push(keyPrefix, keyPrefix);
|
|
113922
|
+
}
|
|
113250
113923
|
let rows;
|
|
113251
113924
|
try {
|
|
113252
113925
|
rows = await getDbClient().query(`SELECT m.*, ml.from_memory_id AS fromMemoryId, ml.strength AS linkStrength
|
|
@@ -113303,6 +113976,7 @@ async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
|
|
|
113303
113976
|
}
|
|
113304
113977
|
|
|
113305
113978
|
// src/tools/memory-search.ts
|
|
113979
|
+
init_key_paths();
|
|
113306
113980
|
init_reranker();
|
|
113307
113981
|
init_types();
|
|
113308
113982
|
var NUDGE_ELIGIBLE_SOURCES2 = new Set(["manual", "file_index"]);
|
|
@@ -113345,10 +114019,11 @@ var registerMemorySearchTool = (server) => {
|
|
|
113345
114019
|
intent: string().min(1).optional().describe("Optional reason for searching for this memory. E.g. 'looking for auth pattern to fix login bug'."),
|
|
113346
114020
|
scope: _enum(["all", "agent", "swarm"]).default("all").describe("Search scope: 'all' (own + swarm), 'agent' (own only), 'swarm' (shared only)."),
|
|
113347
114021
|
limit: number().int().min(1).max(50).default(10).describe("Max results to return."),
|
|
113348
|
-
source: AgentMemorySourceSchema.optional().describe("Filter by memory source type.")
|
|
114022
|
+
source: AgentMemorySourceSchema.optional().describe("Filter by memory source type."),
|
|
114023
|
+
keyPrefix: string().min(1).max(MEMORY_KEY_MAX_LENGTH).optional().describe("Only return memories whose key starts with this text, for example '/longterm/facts/' or '/longterm/entities/people/'. Matched literally, case-sensitive. Include the trailing '/' to stay inside one folder.")
|
|
113349
114024
|
}),
|
|
113350
114025
|
outputSchema: memorySearchOutputSchema
|
|
113351
|
-
}, async ({ query, intent, scope, limit, source }, requestInfo, _meta) => {
|
|
114026
|
+
}, async ({ query, intent, scope, limit, source, keyPrefix }, requestInfo, _meta) => {
|
|
113352
114027
|
if (!requestInfo.agentId) {
|
|
113353
114028
|
return toolErr("Agent ID required. Are you registered in the swarm?");
|
|
113354
114029
|
}
|
|
@@ -113363,11 +114038,13 @@ var registerMemorySearchTool = (server) => {
|
|
|
113363
114038
|
limit: candidateLimit,
|
|
113364
114039
|
source,
|
|
113365
114040
|
isLead,
|
|
113366
|
-
queryText: query
|
|
114041
|
+
queryText: query,
|
|
114042
|
+
keyPrefix
|
|
113367
114043
|
});
|
|
113368
114044
|
const expanded = await expandCandidatesWithGraph(candidates, requestInfo.agentId, {
|
|
113369
114045
|
scope,
|
|
113370
114046
|
source,
|
|
114047
|
+
keyPrefix,
|
|
113371
114048
|
isLead
|
|
113372
114049
|
});
|
|
113373
114050
|
if (expanded.length > 0) {
|
|
@@ -113414,7 +114091,8 @@ var registerMemorySearchTool = (server) => {
|
|
|
113414
114091
|
scope,
|
|
113415
114092
|
limit,
|
|
113416
114093
|
isLead,
|
|
113417
|
-
source
|
|
114094
|
+
source,
|
|
114095
|
+
keyPrefix
|
|
113418
114096
|
});
|
|
113419
114097
|
const consumedIds = dedupeMemoryDocumentIds(recent);
|
|
113420
114098
|
try {
|
|
@@ -113442,6 +114120,7 @@ var registerMemorySearchTool = (server) => {
|
|
|
113442
114120
|
|
|
113443
114121
|
// src/tools/memory-store.ts
|
|
113444
114122
|
init_zod();
|
|
114123
|
+
init_db();
|
|
113445
114124
|
|
|
113446
114125
|
// src/be/chunking.ts
|
|
113447
114126
|
var MAX_CHUNK_SIZE = 2000;
|
|
@@ -113594,6 +114273,9 @@ function addOverlap(chunks, _originalText) {
|
|
|
113594
114273
|
init_secret_scrubber();
|
|
113595
114274
|
async function indexMemoryContent(params) {
|
|
113596
114275
|
const { agentId, content, name, scope, source, sourceTaskId, sourcePath, tags } = params;
|
|
114276
|
+
const rowKey2 = params.key ?? (sourcePath || null);
|
|
114277
|
+
if (rowKey2)
|
|
114278
|
+
assertKeyWritable(rowKey2, params.key != null ? "key" : "sourcePath", params.writer);
|
|
113597
114279
|
const contentChunks = chunkContent(content);
|
|
113598
114280
|
if (contentChunks.length === 0) {
|
|
113599
114281
|
contentChunks.push({
|
|
@@ -113647,7 +114329,7 @@ async function indexMemoryContent(params) {
|
|
|
113647
114329
|
tags: tags || [],
|
|
113648
114330
|
contextKey: params.contextKey ?? null,
|
|
113649
114331
|
intent: params.intent ?? "index memory content",
|
|
113650
|
-
key:
|
|
114332
|
+
key: rowKey2
|
|
113651
114333
|
})));
|
|
113652
114334
|
if (agentId) {
|
|
113653
114335
|
for (const memory of memories) {
|
|
@@ -113674,6 +114356,7 @@ async function indexMemoryContent(params) {
|
|
|
113674
114356
|
}
|
|
113675
114357
|
|
|
113676
114358
|
// src/tools/memory-store.ts
|
|
114359
|
+
init_key_paths();
|
|
113677
114360
|
init_types();
|
|
113678
114361
|
var registerMemoryStoreTool = (server) => {
|
|
113679
114362
|
createToolRegistrar(server)("memory-store", {
|
|
@@ -113682,11 +114365,12 @@ var registerMemoryStoreTool = (server) => {
|
|
|
113682
114365
|
annotations: { destructiveHint: false },
|
|
113683
114366
|
inputSchema: object({
|
|
113684
114367
|
content: string().min(1).describe("The memory body. Markdown is fine. State the fact, the context it applies to, and the evidence."),
|
|
113685
|
-
name: string().min(1).max(200).optional().describe("Short title used in search results and the UI. Defaults to the first non-empty content line (up to 200 characters)."),
|
|
114368
|
+
name: string().min(1).max(200).optional().describe("Short title used in search results and the UI. Defaults to the first non-empty content line (up to 200 characters). A name that starts with /longterm/ is also used as the key when no key is given."),
|
|
113686
114369
|
scope: AgentMemoryScopeSchema.default("agent").describe("'agent' (default): only you can recall it. 'swarm': every agent can recall it."),
|
|
113687
114370
|
tags: union([array(string()), string()]).optional().describe("Free-form tags as an array or a comma-separated string, for example a repo name or a topic."),
|
|
113688
114371
|
taskId: uuid().optional().describe("The task this learning came from, when there is one."),
|
|
113689
|
-
intent: string().min(1).optional().describe("Why this is worth remembering. Kept in the audit trail.")
|
|
114372
|
+
intent: string().min(1).optional().describe("Why this is worth remembering. Kept in the audit trail."),
|
|
114373
|
+
key: string().max(MEMORY_KEY_MAX_LENGTH).regex(MEMORY_KEY_PATTERN, MEMORY_KEY_PATTERN_MESSAGE).optional().describe("Optional logical path for this memory, for example '/longterm/facts/swarm-runtime/sqlite-busy-retry'. Lowercase segments joined by '/', starting with '/'. Search it with memory-search keyPrefix and move it with memory-edit newKey. Fails when you already have a memory with this key in this scope. A key under /longterm marks the memory as curated: it never expires and is protected from cleanup. It must start with /longterm/company-story, /longterm/entities/people, /longterm/entities/customers, /longterm/facts, /longterm/decisions, /longterm/workstreams or /longterm/timeline. Paths under /longterm/company-story, /longterm/entities and /longterm/timeline are lead-only. Defaults to an auto key, which makes the memory inbox material.")
|
|
113690
114374
|
}),
|
|
113691
114375
|
outputSchema: swarmToolOutputSchema({
|
|
113692
114376
|
yourAgentId: string().optional(),
|
|
@@ -113694,13 +114378,18 @@ var registerMemoryStoreTool = (server) => {
|
|
|
113694
114378
|
chunks: number().int().optional(),
|
|
113695
114379
|
queued: boolean().optional()
|
|
113696
114380
|
})
|
|
113697
|
-
}, async ({ content, name: requestedName, scope, tags, taskId, intent }, requestInfo, _meta) => {
|
|
114381
|
+
}, async ({ content, name: requestedName, scope, tags, taskId, intent, key }, requestInfo, _meta) => {
|
|
113698
114382
|
const name = requestedName ?? content.split(/\r?\n/).find((line) => line.trim())?.trim().slice(0, 200) ?? "Untitled memory";
|
|
113699
114383
|
const normalizedTags = typeof tags === "string" ? tags.split(",").map((tag) => tag.trim()).filter(Boolean) : tags;
|
|
113700
114384
|
if (!requestInfo.agentId) {
|
|
113701
114385
|
return toolErr("Agent ID required. Are you registered in the swarm?");
|
|
113702
114386
|
}
|
|
114387
|
+
const storeKey = resolveStoreKey(key, requestedName);
|
|
114388
|
+
if (storeKey && !key && !MEMORY_KEY_PATTERN.test(storeKey)) {
|
|
114389
|
+
return toolErr(`Name "${storeKey}" starts with /longterm/, so it is used as the key, but it is not a valid key. ${MEMORY_KEY_PATTERN_MESSAGE}`, { data: { yourAgentId: requestInfo.agentId } });
|
|
114390
|
+
}
|
|
113703
114391
|
try {
|
|
114392
|
+
const agent = storeKey ? await getAgentById(requestInfo.agentId) : undefined;
|
|
113704
114393
|
const result = await indexMemoryContent({
|
|
113705
114394
|
agentId: requestInfo.agentId,
|
|
113706
114395
|
content,
|
|
@@ -113709,7 +114398,16 @@ var registerMemoryStoreTool = (server) => {
|
|
|
113709
114398
|
source: "manual",
|
|
113710
114399
|
sourceTaskId: taskId ?? null,
|
|
113711
114400
|
tags: normalizedTags,
|
|
113712
|
-
intent
|
|
114401
|
+
intent,
|
|
114402
|
+
key: storeKey,
|
|
114403
|
+
writer: {
|
|
114404
|
+
principal: {
|
|
114405
|
+
kind: "agent",
|
|
114406
|
+
agentId: requestInfo.agentId,
|
|
114407
|
+
isLead: agent?.isLead ?? false
|
|
114408
|
+
},
|
|
114409
|
+
source: "mcp"
|
|
114410
|
+
}
|
|
113713
114411
|
});
|
|
113714
114412
|
return toolOk(`Memory "${name}" stored as ${result.chunks} chunk(s) in ${scope} scope. Embedding runs in the background.`, {
|
|
113715
114413
|
data: {
|
|
@@ -113720,7 +114418,14 @@ var registerMemoryStoreTool = (server) => {
|
|
|
113720
114418
|
}
|
|
113721
114419
|
});
|
|
113722
114420
|
} catch (err) {
|
|
113723
|
-
|
|
114421
|
+
if (err instanceof MemoryKeyError) {
|
|
114422
|
+
return toolErr(err.message, { data: { yourAgentId: requestInfo.agentId } });
|
|
114423
|
+
}
|
|
114424
|
+
const message = err.message;
|
|
114425
|
+
if (storeKey && /UNIQUE constraint failed/i.test(message)) {
|
|
114426
|
+
return toolErr(`Memory store failed: key "${storeKey}" is already used in ${scope} scope. Edit that memory with memory-edit, or pick another key.`, { data: { yourAgentId: requestInfo.agentId } });
|
|
114427
|
+
}
|
|
114428
|
+
return toolErr(`Memory store failed: ${message}`, {
|
|
113724
114429
|
data: { yourAgentId: requestInfo.agentId }
|
|
113725
114430
|
});
|
|
113726
114431
|
}
|
|
@@ -121843,7 +122548,7 @@ var createScheduleInputSchema = object({
|
|
|
121843
122548
|
targetAgentId: string().optional().describe("Agent to assign tasks to (omit for task pool)"),
|
|
121844
122549
|
timezone: string().default("UTC").optional().describe("Timezone for cron schedules"),
|
|
121845
122550
|
enabled: boolean().default(true).optional().describe("Whether the schedule is enabled (default: true)"),
|
|
121846
|
-
model: string().trim().min(1).optional().describe("Concrete model override for tasks created by this schedule. Interpreted by each assignee's harness/provider and does not switch providers. Prefer modelTier for portable intent."),
|
|
122551
|
+
model: string().trim().min(1).optional().describe("Concrete model override for tasks created by this schedule. Interpreted by each assignee's harness/provider and does not switch providers. Prefer modelTier for portable intent. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
|
|
121847
122552
|
modelTier: ModelTierSchema.optional().describe("Portable model tier for tasks created by this schedule: 'smol', 'regular', 'smart', or 'ultra'. Resolved by each assignee's harness/provider at run time."),
|
|
121848
122553
|
allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet.")
|
|
121849
122554
|
});
|
|
@@ -122427,7 +123132,7 @@ var patchScheduleInputSchema = object({
|
|
|
122427
123132
|
targetAgentId: string().nullable().optional().describe("New target agent ID"),
|
|
122428
123133
|
timezone: string().optional().describe("New timezone"),
|
|
122429
123134
|
enabled: boolean().optional().describe("Enable or disable the schedule"),
|
|
122430
|
-
model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear."),
|
|
123135
|
+
model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
|
|
122431
123136
|
modelTier: ModelTierSchema.nullable().optional().describe("Portable model tier for tasks created by this schedule. Set to null to clear."),
|
|
122432
123137
|
allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet.")
|
|
122433
123138
|
});
|
|
@@ -122586,12 +123291,13 @@ var registerPatchScheduleTool = (server) => {
|
|
|
122586
123291
|
updateData.timezone = timezone;
|
|
122587
123292
|
if (enabled2 !== undefined)
|
|
122588
123293
|
updateData.enabled = enabled2;
|
|
123294
|
+
const agentChanged = targetAgentId !== undefined && targetAgentId !== schedule.targetAgentId;
|
|
122589
123295
|
if (model !== undefined || modelTier !== undefined) {
|
|
122590
123296
|
const normalizedModel = splitLegacyModelAlias({ model, modelTier });
|
|
122591
|
-
if (normalizedModel.model !== schedule.model) {
|
|
123297
|
+
if (normalizedModel.model !== schedule.model || agentChanged) {
|
|
122592
123298
|
const modelError = await explicitModelErrorForAgent({
|
|
122593
123299
|
model: normalizedModel.model,
|
|
122594
|
-
allowCustomModel,
|
|
123300
|
+
allowCustomModel: allowCustomModel || normalizedModel.model === schedule.model,
|
|
122595
123301
|
agentId: targetAgentId ?? schedule.targetAgentId
|
|
122596
123302
|
});
|
|
122597
123303
|
if (modelError)
|
|
@@ -122602,6 +123308,14 @@ var registerPatchScheduleTool = (server) => {
|
|
|
122602
123308
|
if (modelTier !== undefined || normalizedModel.modelTier) {
|
|
122603
123309
|
updateData.modelTier = normalizedModel.modelTier ?? null;
|
|
122604
123310
|
}
|
|
123311
|
+
} else if (agentChanged && schedule.model) {
|
|
123312
|
+
const modelError = await explicitModelErrorForAgent({
|
|
123313
|
+
model: schedule.model,
|
|
123314
|
+
allowCustomModel: true,
|
|
123315
|
+
agentId: targetAgentId ?? schedule.targetAgentId
|
|
123316
|
+
});
|
|
123317
|
+
if (modelError)
|
|
123318
|
+
return toolErr(modelError);
|
|
122605
123319
|
}
|
|
122606
123320
|
if (schedule.scheduleType === "one_time") {
|
|
122607
123321
|
if (enabled2 === false) {
|
|
@@ -122728,7 +123442,7 @@ var updateScheduleInputSchema = object({
|
|
|
122728
123442
|
targetAgentId: string().nullable().optional().describe("New target agent ID"),
|
|
122729
123443
|
timezone: string().optional().describe("New timezone"),
|
|
122730
123444
|
enabled: boolean().optional().describe("Enable or disable the schedule"),
|
|
122731
|
-
model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear."),
|
|
123445
|
+
model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
|
|
122732
123446
|
modelTier: ModelTierSchema.nullable().optional().describe("Portable model tier for tasks created by this schedule. Set to null to clear."),
|
|
122733
123447
|
allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet.")
|
|
122734
123448
|
});
|
|
@@ -122887,12 +123601,13 @@ var registerUpdateScheduleTool = (server) => {
|
|
|
122887
123601
|
updateData.timezone = timezone;
|
|
122888
123602
|
if (enabled2 !== undefined)
|
|
122889
123603
|
updateData.enabled = enabled2;
|
|
123604
|
+
const agentChanged = targetAgentId !== undefined && targetAgentId !== schedule.targetAgentId;
|
|
122890
123605
|
if (model !== undefined || modelTier !== undefined) {
|
|
122891
123606
|
const normalizedModel = splitLegacyModelAlias({ model, modelTier });
|
|
122892
|
-
if (normalizedModel.model !== schedule.model) {
|
|
123607
|
+
if (normalizedModel.model !== schedule.model || agentChanged) {
|
|
122893
123608
|
const modelError = await explicitModelErrorForAgent({
|
|
122894
123609
|
model: normalizedModel.model,
|
|
122895
|
-
allowCustomModel,
|
|
123610
|
+
allowCustomModel: allowCustomModel || normalizedModel.model === schedule.model,
|
|
122896
123611
|
agentId: targetAgentId ?? schedule.targetAgentId
|
|
122897
123612
|
});
|
|
122898
123613
|
if (modelError)
|
|
@@ -122903,6 +123618,14 @@ var registerUpdateScheduleTool = (server) => {
|
|
|
122903
123618
|
if (modelTier !== undefined || normalizedModel.modelTier) {
|
|
122904
123619
|
updateData.modelTier = normalizedModel.modelTier ?? null;
|
|
122905
123620
|
}
|
|
123621
|
+
} else if (agentChanged && schedule.model) {
|
|
123622
|
+
const modelError = await explicitModelErrorForAgent({
|
|
123623
|
+
model: schedule.model,
|
|
123624
|
+
allowCustomModel: true,
|
|
123625
|
+
agentId: targetAgentId ?? schedule.targetAgentId
|
|
123626
|
+
});
|
|
123627
|
+
if (modelError)
|
|
123628
|
+
return toolErr(modelError);
|
|
122906
123629
|
}
|
|
122907
123630
|
if (schedule.scheduleType === "one_time") {
|
|
122908
123631
|
if (enabled2 === false) {
|
|
@@ -123773,7 +124496,7 @@ var sendTaskInputSchema = object({
|
|
|
123773
124496
|
parentTaskId: uuid().optional().describe("Parent task ID for session continuity. Child task will resume the parent's Claude session. Auto-routes to the same worker unless agentId is explicitly provided."),
|
|
123774
124497
|
dir: string().min(1).startsWith("/").optional().describe("Working directory (absolute path) for the agent to start in. If the directory doesn't exist, falls back to the default working directory."),
|
|
123775
124498
|
vcsRepo: string().optional().describe("VCS repo identifier (e.g., 'desplega-ai/agent-swarm' for GitHub or 'group/project' for GitLab). Links the task to a registered repo for workspace context."),
|
|
123776
|
-
model: string().trim().min(1).optional().describe("Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent."),
|
|
124499
|
+
model: string().trim().min(1).optional().describe("Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
|
|
123777
124500
|
modelTier: ModelTierSchema.optional().describe("Portable model tier for this task: 'smol', 'regular', 'smart', or 'ultra'. Resolved at claim/run time using the assignee's harness/provider. Legacy model shortnames map as haiku→smol, sonnet→regular, opus→smart, fable→ultra."),
|
|
123778
124501
|
allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet (a fresh launch, a private deployment)."),
|
|
123779
124502
|
effort: ReasoningEffortSchema.optional().describe("Reasoning effort for this task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. If omitted, the assignee's REASONING_EFFORT_OVERRIDE/default applies."),
|
|
@@ -123887,13 +124610,6 @@ async function sendTaskHandler(ctx, {
|
|
|
123887
124610
|
}
|
|
123888
124611
|
const effectiveVcsRepo = vcsRepo;
|
|
123889
124612
|
const normalizedModel = splitLegacyModelAlias({ model, modelTier });
|
|
123890
|
-
const modelError = await explicitModelErrorForAgent({
|
|
123891
|
-
model: normalizedModel.model,
|
|
123892
|
-
allowCustomModel,
|
|
123893
|
-
agentId
|
|
123894
|
-
});
|
|
123895
|
-
if (modelError)
|
|
123896
|
-
return toolErr(modelError, { data: { yourAgentId: creatorAgentId } });
|
|
123897
124613
|
const effectiveParentTaskId = parentTaskId ?? sourceTaskId;
|
|
123898
124614
|
const effectiveParentTask = effectiveParentTaskId ? await getTaskById(effectiveParentTaskId) : null;
|
|
123899
124615
|
if (effectiveParentTask?.routingAffinityInvalid) {
|
|
@@ -123931,6 +124647,13 @@ async function sendTaskHandler(ctx, {
|
|
|
123931
124647
|
effectiveAgentId = effectiveParentTask.agentId;
|
|
123932
124648
|
}
|
|
123933
124649
|
}
|
|
124650
|
+
const modelError = await explicitModelErrorForAgent({
|
|
124651
|
+
model: normalizedModel.model,
|
|
124652
|
+
allowCustomModel,
|
|
124653
|
+
agentId: effectiveAgentId
|
|
124654
|
+
});
|
|
124655
|
+
if (modelError)
|
|
124656
|
+
return toolErr(modelError, { data: { yourAgentId: creatorAgentId } });
|
|
123934
124657
|
const effectiveRoutingReason = agentId !== undefined ? routingReason : effectiveAgentId ? "continuity" : undefined;
|
|
123935
124658
|
const effectiveRoutingNote = effectiveRoutingReason ? routingNote : undefined;
|
|
123936
124659
|
const effectiveRoutingSource = agentId !== undefined ? "declared" : effectiveAgentId ? "engine_default" : undefined;
|
|
@@ -123968,7 +124691,8 @@ async function sendTaskHandler(ctx, {
|
|
|
123968
124691
|
description: task,
|
|
123969
124692
|
options: requestedTaskOptions,
|
|
123970
124693
|
origin: "mcp",
|
|
123971
|
-
requestInfo: ctx.kind === "owner" ? ctx.requestInfo : undefined
|
|
124694
|
+
requestInfo: ctx.kind === "owner" ? ctx.requestInfo : undefined,
|
|
124695
|
+
allowCustomModel
|
|
123972
124696
|
});
|
|
123973
124697
|
if (preCreate.kind === "blocked") {
|
|
123974
124698
|
return toolErr(preCreate.reason, {
|
|
@@ -126167,9 +126891,9 @@ var registerSlackReadTool = (server) => {
|
|
|
126167
126891
|
const extractedText = extractSlackMessageText(m);
|
|
126168
126892
|
if (!extractedText && (!m.files || m.files.length === 0))
|
|
126169
126893
|
continue;
|
|
126170
|
-
const
|
|
126894
|
+
const isBot2 = m.user === botUserId || m.bot_id !== undefined || m.subtype === "bot_message";
|
|
126171
126895
|
let username;
|
|
126172
|
-
if (
|
|
126896
|
+
if (isBot2) {
|
|
126173
126897
|
username = m.username || "Agent";
|
|
126174
126898
|
} else if (m.user) {
|
|
126175
126899
|
username = await getUserDisplayName(m.user);
|
|
@@ -126207,7 +126931,7 @@ var registerSlackReadTool = (server) => {
|
|
|
126207
126931
|
messages.push({
|
|
126208
126932
|
user: m.user,
|
|
126209
126933
|
username,
|
|
126210
|
-
isBot,
|
|
126934
|
+
isBot: isBot2,
|
|
126211
126935
|
text: extractedText,
|
|
126212
126936
|
ts: m.ts,
|
|
126213
126937
|
files
|
|
@@ -126867,6 +127591,20 @@ init_types();
|
|
|
126867
127591
|
init_secret_scrubber();
|
|
126868
127592
|
var BLOCKED_WAITING_PATTERN = /\b(waiting (for|on)|blocked (on|until|by)|still waiting|awaiting)\b/i;
|
|
126869
127593
|
var BLOCKED_WAITING_MIN_ELAPSED_MS = 3 * 60 * 1000;
|
|
127594
|
+
async function foreignTaskWriteError(caller, task, sourceTaskId) {
|
|
127595
|
+
const decision = can({
|
|
127596
|
+
principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead === true },
|
|
127597
|
+
verb: "task.progress.write",
|
|
127598
|
+
resource: { kind: "task", taskId: task.id, agentId: task.agentId },
|
|
127599
|
+
source: "mcp"
|
|
127600
|
+
});
|
|
127601
|
+
if (decision.allow)
|
|
127602
|
+
return;
|
|
127603
|
+
const sourceTask = sourceTaskId ? await getTaskById(sourceTaskId) : null;
|
|
127604
|
+
const ownTask = sourceTask?.agentId === caller.id ? sourceTask : await getAgentCurrentTask(caller.id);
|
|
127605
|
+
const retry = ownTask ? ` Your own task is "${ownTask.id}"; call store-progress with that taskId.` : " You have no in-progress task.";
|
|
127606
|
+
return `Task "${task.id}" is assigned to another agent; only its assignee may store progress on it. Nothing was written.${retry}`;
|
|
127607
|
+
}
|
|
126870
127608
|
var storeProgressOutputSchema = swarmToolOutputSchema({
|
|
126871
127609
|
task: looseObject({
|
|
126872
127610
|
id: string(),
|
|
@@ -126940,12 +127678,17 @@ var registerStoreProgressTool = (server) => {
|
|
|
126940
127678
|
const agentFsScopes = new Map;
|
|
126941
127679
|
const agentFsAttachments = attachments?.filter((a) => a.kind === "agent-fs") ?? [];
|
|
126942
127680
|
if (agentFsAttachments.length > 0) {
|
|
126943
|
-
|
|
127681
|
+
const caller = await getAgentById(requestInfo.agentId);
|
|
127682
|
+
if (!caller) {
|
|
126944
127683
|
return toolErr(`Agent with ID "${requestInfo.agentId}" not found in the swarm, register before storing task progress.`);
|
|
126945
127684
|
}
|
|
126946
|
-
|
|
127685
|
+
const target = await getTaskById(taskId);
|
|
127686
|
+
if (!target) {
|
|
126947
127687
|
return toolErr(`Task with ID "${taskId}" not found.`);
|
|
126948
127688
|
}
|
|
127689
|
+
const foreignError = await foreignTaskWriteError(caller, target, requestInfo.sourceTaskId);
|
|
127690
|
+
if (foreignError)
|
|
127691
|
+
return toolErr(foreignError);
|
|
126949
127692
|
const configs = await getResolvedConfig(requestInfo.agentId ?? undefined);
|
|
126950
127693
|
const configValue = (key) => configs.find((c) => c.key === key)?.value?.trim();
|
|
126951
127694
|
const defaultOrgId = configValue("AGENT_FS_DEFAULT_ORG_ID");
|
|
@@ -127006,6 +127749,10 @@ var registerStoreProgressTool = (server) => {
|
|
|
127006
127749
|
message: `Task with ID "${taskId}" not found.`
|
|
127007
127750
|
};
|
|
127008
127751
|
}
|
|
127752
|
+
const foreignError = await foreignTaskWriteError(agent, existingTask, requestInfo.sourceTaskId);
|
|
127753
|
+
if (foreignError) {
|
|
127754
|
+
return { success: false, message: foreignError };
|
|
127755
|
+
}
|
|
127009
127756
|
let updatedTask = existingTask;
|
|
127010
127757
|
const isTerminal2 = isTerminalTaskStatus(existingTask.status);
|
|
127011
127758
|
const goingTerminal = status !== undefined && isTerminalTaskStatus(status);
|
|
@@ -127063,8 +127810,8 @@ var registerStoreProgressTool = (server) => {
|
|
|
127063
127810
|
return terminalResultGuard;
|
|
127064
127811
|
}
|
|
127065
127812
|
if (progress && !isTerminal2) {
|
|
127066
|
-
const
|
|
127067
|
-
if (!
|
|
127813
|
+
const isDuplicate5 = existingTask.progress === progress && existingTask.lastUpdatedAt && Date.now() - new Date(existingTask.lastUpdatedAt).getTime() < 5 * 60 * 1000;
|
|
127814
|
+
if (!isDuplicate5) {
|
|
127068
127815
|
const result2 = await updateTaskProgress(taskId, progress);
|
|
127069
127816
|
if (result2)
|
|
127070
127817
|
updatedTask = result2;
|
|
@@ -127780,7 +128527,7 @@ var taskActionInputSchema = object({
|
|
|
127780
128527
|
taskId: uuid().optional().describe("Task ID (required for claim/release/accept/reject)."),
|
|
127781
128528
|
reason: string().optional().describe("Reason for rejection (optional for 'reject')."),
|
|
127782
128529
|
dir: string().min(1).startsWith("/").optional().describe("Working directory (absolute path) for the agent to start in. Only used with 'create' action."),
|
|
127783
|
-
model: string().trim().min(1).optional().describe("Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action."),
|
|
128530
|
+
model: string().trim().min(1).optional().describe("Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
|
|
127784
128531
|
modelTier: ModelTierSchema.optional().describe("Portable model tier for the created task: 'smol', 'regular', 'smart', or 'ultra'. Resolved when a worker claims/runs the task. Only used with 'create' action."),
|
|
127785
128532
|
allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only used with 'create' action."),
|
|
127786
128533
|
effort: ReasoningEffortSchema.optional().describe("Reasoning effort for the created task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. Only used with 'create' action."),
|
|
@@ -127928,7 +128675,8 @@ async function taskActionHandler(ctx, input) {
|
|
|
127928
128675
|
routingAffinity: leadOnly || requiredCapabilities?.length ? { leadOnly, capabilities: requiredCapabilities ?? [] } : undefined
|
|
127929
128676
|
},
|
|
127930
128677
|
origin: "mcp",
|
|
127931
|
-
requestInfo: ctx.requestInfo
|
|
128678
|
+
requestInfo: ctx.requestInfo,
|
|
128679
|
+
allowCustomModel: input.allowCustomModel
|
|
127932
128680
|
});
|
|
127933
128681
|
if (preCreate.kind === "blocked") {
|
|
127934
128682
|
return taskActionResult({ success: false, message: preCreate.reason }, agentId);
|
|
@@ -128849,6 +129597,43 @@ var registerCancelWorkflowRunTool = (server) => {
|
|
|
128849
129597
|
init_zod();
|
|
128850
129598
|
init_db();
|
|
128851
129599
|
init_types();
|
|
129600
|
+
|
|
129601
|
+
// src/workflows/model-validation.ts
|
|
129602
|
+
init_types();
|
|
129603
|
+
function asConfig(value) {
|
|
129604
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
129605
|
+
}
|
|
129606
|
+
function isStatic(value) {
|
|
129607
|
+
return typeof value === "string" && value.trim() !== "" && !value.includes("{{");
|
|
129608
|
+
}
|
|
129609
|
+
async function workflowModelErrors(def) {
|
|
129610
|
+
const errors = [];
|
|
129611
|
+
for (const node of def.nodes) {
|
|
129612
|
+
const targets = [];
|
|
129613
|
+
if (node.type === "agent-task")
|
|
129614
|
+
targets.push({ config: node.config, path: "config" });
|
|
129615
|
+
if (node.type === "foreach") {
|
|
129616
|
+
const body = asConfig(asConfig(node.config.body)?.config);
|
|
129617
|
+
if (body)
|
|
129618
|
+
targets.push({ config: body, path: "config.body.config" });
|
|
129619
|
+
}
|
|
129620
|
+
for (const { config, path: path3 } of targets) {
|
|
129621
|
+
if (!isStatic(config.model) || !isStatic(config.agentId))
|
|
129622
|
+
continue;
|
|
129623
|
+
const modelTier = typeof config.modelTier === "string" ? config.modelTier : undefined;
|
|
129624
|
+
const error = await explicitModelErrorForAgent({
|
|
129625
|
+
model: splitLegacyModelAlias({ model: config.model, modelTier }).model,
|
|
129626
|
+
allowCustomModel: config.allowCustomModel === true,
|
|
129627
|
+
agentId: config.agentId
|
|
129628
|
+
});
|
|
129629
|
+
if (error)
|
|
129630
|
+
errors.push(`Node "${node.id}" ${path3}.model: ${error}`);
|
|
129631
|
+
}
|
|
129632
|
+
}
|
|
129633
|
+
return errors;
|
|
129634
|
+
}
|
|
129635
|
+
|
|
129636
|
+
// src/tools/workflows/create-workflow.ts
|
|
128852
129637
|
var registerCreateWorkflowTool = (server) => {
|
|
128853
129638
|
createToolRegistrar(server)("create-workflow", {
|
|
128854
129639
|
title: "Create Workflow",
|
|
@@ -128860,14 +129645,14 @@ var registerCreateWorkflowTool = (server) => {
|
|
|
128860
129645
|
` + `- Agent-task config: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }.
|
|
128861
129646
|
` + "- FOREACH NODE: type 'foreach' fans out one agent-task per item. Config: " + "{ over: <array or exact {{input}} token>, itemKey: <property name>, body: { type: 'agent-task', config: {...} } }. " + "The body config is interpolated once per item with {{item.*}} and {{index}}. Child steps use synthetic IDs " + "'<foreachNodeId>#<itemKey>'; the parent waits for every child and exposes one aggregate result to successors. " + `concurrency is not supported in v1; use definition-level onNodeFailure: 'continue' to aggregate failed children.
|
|
128862
129647
|
` + "- TRIGGER SCHEMA: Optional 'triggerSchema' is a JSON-Schema object that validates incoming trigger payloads. " + "Supported keywords: type, required, properties, enum, const, items (recursive into arrays). " + `Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored.
|
|
128863
|
-
` + "- WEBHOOK VERIFICATION: Webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "
|
|
129648
|
+
` + "- WEBHOOK VERIFICATION: Webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "{ format: 'token-equality', header }, or { format: 'standard-webhooks', toleranceSeconds? } " + "(standardwebhooks.com: webhook-id/webhook-timestamp/webhook-signature headers, hmacSecret is the whsec_ signing secret). Example: { type: 'webhook', hmacSecret: 'secret.SUPERAGENT_WEBHOOK_SECRET', " + `verification: { format: 'timestamped-hmac-sha256', header: 'X-Superagent-Signature', toleranceSeconds: 300 } }.
|
|
128864
129649
|
` + "- WAIT NODE: type 'wait' pauses a workflow for a duration or until a named workflowEventBus event arrives. " + "See runbooks/workflows.md#wait-nodes for config shapes, ordering caveats, and built-in event names.",
|
|
128865
129650
|
inputSchema: exports_external.object({
|
|
128866
129651
|
name: exports_external.string().describe("Unique name for the workflow"),
|
|
128867
129652
|
key: AssetKeySchema.optional().describe("Logical namespace. Defaults to a shared/workflow:<id>/ resource key."),
|
|
128868
129653
|
description: exports_external.string().optional().describe("Description of what this workflow does"),
|
|
128869
129654
|
definition: WorkflowDefinitionSchema.describe("The workflow definition with nodes (each node has id, type, config, and optional next/retry/validation)"),
|
|
128870
|
-
triggers: exports_external.array(TriggerConfigSchema).optional().describe("Optional trigger configurations (webhook, schedule, event). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality."),
|
|
129655
|
+
triggers: exports_external.array(TriggerConfigSchema).optional().describe("Optional trigger configurations (webhook, schedule, event). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality, standard-webhooks."),
|
|
128871
129656
|
cooldown: CooldownConfigSchema.optional().describe("Optional cooldown configuration to prevent re-triggering too frequently"),
|
|
128872
129657
|
input: exports_external.record(exports_external.string(), InputValueSchema).optional().describe("Optional input values resolved at execution time (env vars like VAR_NAME, secrets secret.NAME, or literals)"),
|
|
128873
129658
|
dir: exports_external.string().min(1).startsWith("/").optional().describe("Default working directory for all agent-task nodes (absolute path, e.g. /tmp/workspace)"),
|
|
@@ -128899,6 +129684,10 @@ var registerCreateWorkflowTool = (server) => {
|
|
|
128899
129684
|
if (!validation.valid) {
|
|
128900
129685
|
return toolErr(`Invalid definition: ${validation.errors.join("; ")}`);
|
|
128901
129686
|
}
|
|
129687
|
+
const modelErrors = await workflowModelErrors(definition);
|
|
129688
|
+
if (modelErrors.length > 0) {
|
|
129689
|
+
return toolErr(`Invalid definition: ${modelErrors.join("; ")}`);
|
|
129690
|
+
}
|
|
128902
129691
|
const createdBy = await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId) ?? undefined;
|
|
128903
129692
|
const assetKey = key ? await authorizeAssetKeyWrite(key, createdBy) : undefined;
|
|
128904
129693
|
const workflow = await createWorkflow({
|
|
@@ -129178,6 +129967,10 @@ async function patchWorkflowDefinition(options) {
|
|
|
129178
129967
|
if (!validation.valid) {
|
|
129179
129968
|
return { ok: false, reason: "invalid", errors: validation.errors };
|
|
129180
129969
|
}
|
|
129970
|
+
const modelErrors = await workflowModelErrors(patchResult.definition);
|
|
129971
|
+
if (modelErrors.length > 0) {
|
|
129972
|
+
return { ok: false, reason: "invalid", errors: modelErrors };
|
|
129973
|
+
}
|
|
129181
129974
|
let version = null;
|
|
129182
129975
|
if (snapshotOptional) {
|
|
129183
129976
|
try {
|
|
@@ -129438,14 +130231,14 @@ var registerUpdateWorkflowTool = (server) => {
|
|
|
129438
130231
|
createToolRegistrar(server)("update-workflow", {
|
|
129439
130232
|
title: "Update Workflow",
|
|
129440
130233
|
annotations: { destructiveHint: false },
|
|
129441
|
-
description: "Update an existing workflow's name, description, definition, triggers, cooldown, input, triggerSchema, or enabled state. " + "Creates a version snapshot before applying changes. " + "TRIGGER SCHEMA: pass 'triggerSchema' as a JSON-Schema object to set/replace, or 'null' to clear. " + "Supported JSON-Schema keywords: type, required, properties, enum, const, items (recursive into arrays). " + "Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored. " + "WEBHOOK VERIFICATION: webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "
|
|
130234
|
+
description: "Update an existing workflow's name, description, definition, triggers, cooldown, input, triggerSchema, or enabled state. " + "Creates a version snapshot before applying changes. " + "TRIGGER SCHEMA: pass 'triggerSchema' as a JSON-Schema object to set/replace, or 'null' to clear. " + "Supported JSON-Schema keywords: type, required, properties, enum, const, items (recursive into arrays). " + "Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored. " + "WEBHOOK VERIFICATION: webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "{ format: 'token-equality', header }, or { format: 'standard-webhooks', toleranceSeconds? } " + "(standardwebhooks.com: webhook-id/webhook-timestamp/webhook-signature headers, hmacSecret is the whsec_ signing secret).",
|
|
129442
130235
|
inputSchema: exports_external.object({
|
|
129443
130236
|
id: exports_external.string().uuid().describe("Workflow ID to update"),
|
|
129444
130237
|
key: AssetKeySchema.optional().describe("Move to a logical namespace."),
|
|
129445
130238
|
name: exports_external.string().optional().describe("New name for the workflow"),
|
|
129446
130239
|
description: exports_external.string().optional().describe("New description"),
|
|
129447
130240
|
definition: WorkflowDefinitionSchema.optional().describe("New workflow definition"),
|
|
129448
|
-
triggers: exports_external.array(TriggerConfigSchema).optional().describe("New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality."),
|
|
130241
|
+
triggers: exports_external.array(TriggerConfigSchema).optional().describe("New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality, standard-webhooks."),
|
|
129449
130242
|
cooldown: CooldownConfigSchema.optional().nullable().describe("New cooldown configuration (null to remove)"),
|
|
129450
130243
|
input: exports_external.record(exports_external.string(), InputValueSchema).optional().nullable().describe("New input values (null to remove)"),
|
|
129451
130244
|
dir: exports_external.string().min(1).startsWith("/").optional().nullable().describe("Default working directory for all agent-task nodes (null to remove)"),
|
|
@@ -129484,6 +130277,10 @@ var registerUpdateWorkflowTool = (server) => {
|
|
|
129484
130277
|
if (!validation.valid) {
|
|
129485
130278
|
return toolErr(`Invalid definition: ${validation.errors.join("; ")}`);
|
|
129486
130279
|
}
|
|
130280
|
+
const modelErrors = await workflowModelErrors(definition);
|
|
130281
|
+
if (modelErrors.length > 0) {
|
|
130282
|
+
return toolErr(`Invalid definition: ${modelErrors.join("; ")}`);
|
|
130283
|
+
}
|
|
129487
130284
|
}
|
|
129488
130285
|
const updatedBy = await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId) ?? undefined;
|
|
129489
130286
|
const assetKey = key === undefined ? undefined : await authorizeAssetKeyWrite(key, updatedBy);
|
|
@@ -130205,7 +131002,7 @@ async function readScriptSdkJsonResponse(response, operation, limitBytes = SCRIP
|
|
|
130205
131002
|
}
|
|
130206
131003
|
|
|
130207
131004
|
// src/scripts-runtime/swarm-sdk.ts
|
|
130208
|
-
function
|
|
131005
|
+
function headers3(config) {
|
|
130209
131006
|
return {
|
|
130210
131007
|
Authorization: `Bearer ${Redacted.value(config.apiKey)}`,
|
|
130211
131008
|
"X-Agent-ID": Redacted.value(config.agentId),
|
|
@@ -130638,7 +131435,7 @@ async function callBridgeApi(name, args2, config, options = {}) {
|
|
|
130638
131435
|
const mcpToolName = mcpToolNameForSdkMethod(name);
|
|
130639
131436
|
const res2 = await fetch(`${baseUrl}/api/mcp-bridge`, {
|
|
130640
131437
|
method: "POST",
|
|
130641
|
-
headers:
|
|
131438
|
+
headers: headers3(config),
|
|
130642
131439
|
body: JSON.stringify({ tool: mcpToolName, args: args2 ?? {} })
|
|
130643
131440
|
});
|
|
130644
131441
|
const data2 = await readScriptSdkJsonResponse(res2, `ctx.swarm.${name}`);
|
|
@@ -130650,7 +131447,7 @@ async function callBridgeApi(name, args2, config, options = {}) {
|
|
|
130650
131447
|
}
|
|
130651
131448
|
const res = await fetch(`${baseUrl}${request.path}`, {
|
|
130652
131449
|
method: request.method,
|
|
130653
|
-
headers:
|
|
131450
|
+
headers: headers3(config),
|
|
130654
131451
|
body: request.body === undefined ? undefined : JSON.stringify(request.body)
|
|
130655
131452
|
});
|
|
130656
131453
|
const data = await readScriptSdkJsonResponse(res, `ctx.swarm.${name}`);
|
|
@@ -131777,6 +132574,7 @@ async function applyPreTaskCreate(args2) {
|
|
|
131777
132574
|
const creatingExtensionId = extensionIdForAgent(args2.requestInfo?.agentId);
|
|
131778
132575
|
const creatingExtension = creatingExtensionId ? listRegistered().find((loaded) => loaded.record.id === creatingExtensionId) : undefined;
|
|
131779
132576
|
const origin = creatingExtension ? `extension:${creatingExtension.record.name}` : args2.origin;
|
|
132577
|
+
let modelEditor;
|
|
131780
132578
|
const result = await dispatchPre("pre.task.create", {
|
|
131781
132579
|
description: args2.description,
|
|
131782
132580
|
options: args2.options,
|
|
@@ -131803,6 +132601,9 @@ async function applyPreTaskCreate(args2) {
|
|
|
131803
132601
|
}
|
|
131804
132602
|
const { description: _description, ...optionChanges2 } = filtered;
|
|
131805
132603
|
CreateTaskOptionsSchema.parse({ ...currentOptions, ...optionChanges2 });
|
|
132604
|
+
if ("model" in optionChanges2 || "agentId" in optionChanges2) {
|
|
132605
|
+
modelEditor = { id: extension.id, name: extension.name };
|
|
132606
|
+
}
|
|
131806
132607
|
return filtered;
|
|
131807
132608
|
}
|
|
131808
132609
|
});
|
|
@@ -131817,10 +132618,25 @@ async function applyPreTaskCreate(args2) {
|
|
|
131817
132618
|
return { kind: "proceed", description: args2.description, options: args2.options };
|
|
131818
132619
|
}
|
|
131819
132620
|
const { description, ...optionChanges } = result.data;
|
|
132621
|
+
const options = CreateTaskOptionsSchema.parse({ ...args2.options, ...optionChanges });
|
|
132622
|
+
if (modelEditor) {
|
|
132623
|
+
const modelError = await explicitModelErrorForAgent({
|
|
132624
|
+
model: options.model,
|
|
132625
|
+
allowCustomModel: args2.allowCustomModel || options.model === args2.options.model,
|
|
132626
|
+
agentId: options.agentId
|
|
132627
|
+
});
|
|
132628
|
+
if (modelError) {
|
|
132629
|
+
return {
|
|
132630
|
+
kind: "blocked",
|
|
132631
|
+
reason: `pre.task.create rewrite from extension "${modelEditor.name}" is invalid: ${modelError}`,
|
|
132632
|
+
extension: modelEditor
|
|
132633
|
+
};
|
|
132634
|
+
}
|
|
132635
|
+
}
|
|
131820
132636
|
return {
|
|
131821
132637
|
kind: "proceed",
|
|
131822
132638
|
description: description ?? args2.description,
|
|
131823
|
-
options
|
|
132639
|
+
options
|
|
131824
132640
|
};
|
|
131825
132641
|
}
|
|
131826
132642
|
|
|
@@ -131920,13 +132736,13 @@ class AgentTaskExecutor extends BaseExecutor {
|
|
|
131920
132736
|
followUpConfig: config.followUpConfig,
|
|
131921
132737
|
contextKey: workflowContextKey({ workflowRunId: meta2.runId })
|
|
131922
132738
|
},
|
|
131923
|
-
origin: "workflow"
|
|
132739
|
+
origin: "workflow",
|
|
132740
|
+
allowCustomModel: config.allowCustomModel
|
|
131924
132741
|
});
|
|
131925
132742
|
if (preCreate.kind === "blocked") {
|
|
131926
132743
|
throw new TaskCreationBlockedError(preCreate.reason, preCreate.extension);
|
|
131927
132744
|
}
|
|
131928
|
-
const
|
|
131929
|
-
const task = await db.createTaskExtended(taskDescription, taskOptions);
|
|
132745
|
+
const task = await db.createTaskExtended(preCreate.description, preCreate.options);
|
|
131930
132746
|
return {
|
|
131931
132747
|
status: "success",
|
|
131932
132748
|
async: true,
|
|
@@ -132187,7 +133003,7 @@ class NotifyExecutor extends BaseExecutor {
|
|
|
132187
133003
|
}
|
|
132188
133004
|
}
|
|
132189
133005
|
case "slack": {
|
|
132190
|
-
const { getSlackApp: getSlackApp2 } = await import("./app-
|
|
133006
|
+
const { getSlackApp: getSlackApp2 } = await import("./app-0hdqa4k1.js");
|
|
132191
133007
|
const app = getSlackApp2();
|
|
132192
133008
|
if (!app) {
|
|
132193
133009
|
return {
|
|
@@ -132992,4 +133808,4 @@ async function initWorkflows() {
|
|
|
132992
133808
|
logOpenWebhookTriggers();
|
|
132993
133809
|
}
|
|
132994
133810
|
|
|
132995
|
-
export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, findUserById, findUserByExternalId, getUserIdentities, listUserEvents, listUserTokens, recordIdentityEvent, findOrCreateUserByEmail, linkIdentity, unlinkIdentity, mintToken, revokeToken, resolveUserByToken, mintSessionToken, revokeSessionToken, fingerprintApiKey, resolveIdentity, renderIdentity, createAdditiveBuffer, referencedBundlePaths, skillDirs, TaskCreationBlockedError, recordUnmappedIdentity, MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload, buildEffectiveText, bufferedFileFailures, fetchSlackFiles, createSlackTaskWithFiles, notifySlackFileFailures, hasOtherUserMention, broadcastMatches, routeMessage, extractTaskFromMessage, extractSlackMessageText, automationIntegrationFixUrl, preflightAutomation, getAutomationSetupStates, listEnabledAutomationPreflightInputs, validateJsonSchema, workflowSaveWarnings, TriggerSchemaError, startWorkflowExecution, setupWorkflowResumeListener, retryFailedRun, cancelWorkflowRun, resumeWaitState, initWaitBusSubscriptions, subscribeWaitToBus, recoverIncompleteRuns, startRetryPoller, stopRetryPoller, validateTemplateVariables, instantiateTemplate, handleWebhookTrigger, logOpenWebhookTriggers, handleEventTrigger, handleScheduleTrigger, verifyHmacSignature, WebhookError, snapshotWorkflow, snapshotAndUpdateWorkflow, startWaitPoller, stopWaitPoller,
|
|
133811
|
+
export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, findUserById, findUserByExternalId, getUserIdentities, listUserEvents, listUserTokens, recordIdentityEvent, findOrCreateUserByEmail, linkIdentity, unlinkIdentity, mintToken, revokeToken, resolveUserByToken, mintSessionToken, revokeSessionToken, fingerprintApiKey, resolveIdentity, renderIdentity, createAdditiveBuffer, listHarnessModelSupport, recordHarnessModelSupport, agentRanModel, getAgentHarnessCliVersion, setAgentHarnessCliVersion, sanitizeModelTierOverrides, parseModelTierOverridesHeader, setAgentModelTierOverrides, previewModelTiers, recordClaimModelResolution, harnessModelErrorFor, poolTaskRunsOnHarness, explicitModelError, explicitModelErrorForAgent, referencedBundlePaths, skillDirs, TaskCreationBlockedError, recordUnmappedIdentity, MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload, buildEffectiveText, bufferedFileFailures, fetchSlackFiles, createSlackTaskWithFiles, notifySlackFileFailures, hasOtherUserMention, broadcastMatches, routeMessage, extractTaskFromMessage, extractSlackMessageText, automationIntegrationFixUrl, preflightAutomation, getAutomationSetupStates, listEnabledAutomationPreflightInputs, validateJsonSchema, workflowSaveWarnings, TriggerSchemaError, startWorkflowExecution, setupWorkflowResumeListener, retryFailedRun, cancelWorkflowRun, resumeWaitState, initWaitBusSubscriptions, subscribeWaitToBus, recoverIncompleteRuns, startRetryPoller, stopRetryPoller, validateTemplateVariables, instantiateTemplate, handleWebhookTrigger, logOpenWebhookTriggers, handleEventTrigger, handleScheduleTrigger, verifyHmacSignature, WebhookError, snapshotWorkflow, snapshotAndUpdateWorkflow, startWaitPoller, stopWaitPoller, RawLlmConfigSchema, RawLlmOutputSchema, executeRawLlm, getExecutorRegistry, initWorkflows, dispatchScheduleTarget, calculateNextRun, startScheduler, stopScheduler, runScheduleNow, parseSkillContent, ExtensionAssetConflictError, ExtensionOwnershipError, getExtensionFiles, getExtensionById, getExtensionByName, listExtensions, listExtensionVersions, updateExtensionMeta, listExtensionRuns, SDK_ALLOWLIST, mcpToolNameForSdkMethod, mcpOverflowAuthError, toolErr, createToolRegistrar, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, allowedCredentialRedirect, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, handleMcpBridge, Redacted, SCRIPT_SDK_RESPONSE_LIMIT_BYTES, readScriptSdkJsonResponse, ExtensionConfigError, ExtensionLifecycleError, setExtensionLoopbackBaseUrl, enableExtension, disableExtension, activateVersion, ExtensionAssetsInvalidError, installExtensionWithAssets, uninstallExtension, reloadExtension, loadEnabledExtensions, stopExtensionRuntime, ExtensionAbortedError, isRegistered, isExtensionAgentId, getExtensionBridgeToken, resolveBridgeCallOrigin, extensionIdForAgent, runContext, registerLoaded, unregister, listRegistered, dispatchPre, dispatchPost, stripSiblingBlock, createTaskWithSiblingAwareness, isInboxAllowed, isSenderAllowed, handleMessageReceived, isAzureDevOpsEnabled, initAzureDevOps, verifyAzureDevOpsWebhook, isAzureDevOpsUrl, canonicalAzureDevOpsRepoUrl, parseAzureDevOpsRepoUrl, createdPullRequestOf, commentedPayloadOf, handlePullRequestCreated, handlePullRequestCommented, AGENT_MAX_TASKS_CONFIG_KEY, reconcileAgentMaxTasksPolicy, resetAgentMaxTasksMirror, upsertSwarmConfigWithPolicyMirror, runtimeStaleThresholdMinutes, upsertRuntimeInstance, getRuntimeInstanceById, touchRuntimeInstance, countActiveRuntimeInstancesForAgent, listRuntimeInstancesForAgent, setRuntimeCredentialReady, reconcileAgentStatusFromRuntimes, agentsWithLiveRuntime, expireStaleRuntimeInstances, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, repointTrackerSyncBySwarmId, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, cancelApprovalRequest, cancelApprovalRequestAndRun, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, REBOOT_RETRY_PIN_TAG, getPinCandidateAgent, resolveLeadOnlyRecoveryAssignment, getResumeGeneration, getNextResumeGeneration, createWorkerTaskFollowUp, createResumeFollowUp, createRerouteDecisionTask, createPoolStarvationDecisionTask, guardTerminalTaskResultWrite, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, MemoryKeyError, refreshLinks, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, indexMemoryContent, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, workflowModelErrors, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer };
|