@desplega.ai/agent-swarm 2.4.4 → 2.5.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 +4 -2
- package/dist/{acp-adapter-thq04adh.js → acp-adapter-11gp67nr.js} +8 -6
- package/dist/{actions-j6ywh6x5.js → actions-8p2kze8j.js} +24 -22
- package/dist/{amp-adapter-k8b5xmj8.js → amp-adapter-z4qvhacj.js} +2 -2
- package/dist/{anthropic-messages-g6pqmqk4.js → anthropic-messages-txs190dd.js} +17 -20
- package/dist/{app-rb7vc02s.js → app-0qp0a2gk.js} +3 -3
- package/dist/{assistant-ftta1zjf.js → assistant-jedd3ktm.js} +27 -25
- package/dist/{azure-openai-responses-9dbmj346.js → azure-openai-responses-9kfwhmn7.js} +18 -13
- package/dist/{boot-reembed-xns7h5h9.js → boot-reembed-4xwq5tg0.js} +1 -1
- package/dist/{boot-reembed-srp6v6af.js → boot-reembed-n4wq5dd2.js} +1 -1
- package/dist/{boot-scrub-sweep-3qqrh2mz.js → boot-scrub-sweep-69h90xcq.js} +4 -4
- package/dist/{boot-seeds-9ks8hce7.js → boot-seeds-3vn0m9sg.js} +4 -4
- package/dist/{claude-adapter-k5ksyres.js → claude-adapter-221mvad5.js} +8 -6
- package/dist/{claude-managed-adapter-h2y889ge.js → claude-managed-adapter-gt6pa35d.js} +2 -2
- package/dist/{claude-managed-setup-n5a5eqks.js → claude-managed-setup-c3hp36ph.js} +4 -4
- package/dist/{claude-sdk-session-2j3j4kwn.js → claude-sdk-session-8thjsk5e.js} +9729 -9628
- package/dist/{cli-b9fcxxev.js → cli-007cnhm1.js} +50 -4
- package/dist/{cli-j4rqdf2n.js → cli-03vpq45j.js} +2 -2
- package/dist/{cli-amyhm3gj.js → cli-0y6f0ckq.js} +1 -1
- package/dist/{cli-4dg55wsk.js → cli-0z3vjrpm.js} +1 -1
- package/dist/{cli-pccfmtb5.js → cli-179xcyky.js} +11 -11
- package/dist/{cli-3r8samv3.js → cli-1f0gp9vz.js} +3 -2
- package/dist/{cli-hj3debgw.js → cli-1pr672hz.js} +3 -3
- package/dist/{cli-0bqteszy.js → cli-2nf3b08t.js} +328 -25
- package/dist/{cli-t7cyef5g.js → cli-36j4jnk3.js} +4 -4
- package/dist/{cli-er83cjbn.js → cli-3qv8naq8.js} +527 -231
- package/dist/cli-3zwye9sn.js +1193 -0
- package/dist/{cli-60cgh1rv.js → cli-459fk97x.js} +7 -7
- package/dist/{cli-xj0re5tm.js → cli-4w24f7z3.js} +1 -1
- package/dist/{cli-v3yr2gbg.js → cli-5kzk3472.js} +2198 -968
- package/dist/{cli-h7gc0b4r.js → cli-5m84zd2k.js} +55 -18
- package/dist/{cli-w6nadkh4.js → cli-5rvg1ddk.js} +5 -5
- package/dist/{cli-dvkmp9bt.js → cli-6ctwrf1z.js} +20 -10
- package/dist/{cli-9qtjfd60.js → cli-6rg2jn2y.js} +3 -2
- package/dist/{cli-2v045xyf.js → cli-7bwtc6yx.js} +3 -3
- package/dist/{cli-3cgngyd8.js → cli-7g40g8hq.js} +35 -17
- package/dist/{cli-q6r7t299.js → cli-92mqenkc.js} +2379 -154
- package/dist/{cli-cynvc9fj.js → cli-9ce2xw98.js} +8 -8
- package/dist/{cli-gqvh8d8a.js → cli-bgdtv62r.js} +36 -22
- package/dist/{cli-wxbn3yfx.js → cli-cz5nmdxt.js} +2 -2
- package/dist/{cli-wt645v7q.js → cli-dabehxhp.js} +1 -1
- package/dist/{cli-vfha21c9.js → cli-e5bxnjps.js} +2 -2
- package/dist/{cli-p20r8w42.js → cli-fcc5qe3f.js} +763 -268
- package/dist/{cli-1ephgwnq.js → cli-fes51ya2.js} +3 -3
- package/dist/{cli-1d70crsy.js → cli-ftmq4nvk.js} +2 -2
- package/dist/{cli-qkhc5aqy.js → cli-fy1jyyym.js} +13 -13
- package/dist/{cli-s95dknxh.js → cli-g1cw7xtt.js} +1 -1
- package/dist/{cli-qje9k2nh.js → cli-g9ypd5en.js} +12 -2
- package/dist/{cli-74c1wpm0.js → cli-gpv60278.js} +1 -1
- package/dist/{cli-pemywhfq.js → cli-ha9rmwgq.js} +2 -1
- package/dist/{cli-bnz0r3kc.js → cli-j1eghqfm.js} +5 -5
- package/dist/{cli-2zqpkvtt.js → cli-jpxsrxcb.js} +1 -1
- package/dist/{cli-ejs3m1sx.js → cli-kxpfx2xr.js} +1 -1
- package/dist/{cli-37yb7307.js → cli-mbfj11fq.js} +1 -1
- package/dist/{cli-pnp2j5zg.js → cli-mmhj8vd7.js} +2 -2
- package/dist/{cli-xf234ws8.js → cli-n4c8e3s5.js} +2 -0
- package/dist/{cli-a0kcty51.js → cli-n6kmqngw.js} +2 -2
- package/dist/{cli-te6b5wvg.js → cli-nnvjb17s.js} +3 -3
- package/dist/{cli-1dmcq2eh.js → cli-nzfnt2gs.js} +1 -1
- package/dist/{cli-625tb7aq.js → cli-p859hcc8.js} +2 -2
- package/dist/{cli-smvcw9z5.js → cli-pasyvjmm.js} +1 -1
- package/dist/cli-pkaqk57w.js +128 -0
- package/dist/{cli-8nyhf7za.js → cli-qqzmjxkf.js} +129 -105
- package/dist/{cli-zrwpctp4.js → cli-r25qpaxt.js} +161 -63
- package/dist/{cli-nc35pxb7.js → cli-rh5smt8t.js} +19 -4
- package/dist/{cli-qwkcwjdn.js → cli-rycdaj0a.js} +1 -1
- package/dist/{cli-esxerzg7.js → cli-s4sntwt4.js} +2 -2
- package/dist/{cli-b8k7epj1.js → cli-segs7hx9.js} +8 -8
- package/dist/{cli-36ckw0wx.js → cli-stxdrqs2.js} +2 -2
- package/dist/{cli-vdm20wej.js → cli-sy8f9705.js} +4 -4
- package/dist/{cli-1m17dc9d.js → cli-ta8bd7th.js} +2 -2
- package/dist/{cli-2y91wnbh.js → cli-we0ra057.js} +222 -10
- package/dist/{cli-55qmbp6z.js → cli-x21dqn18.js} +5 -5
- package/dist/{cli-dqb4n629.js → cli-x6vf4sad.js} +11 -11
- package/dist/{cli-d2mb5s8a.js → cli-x77gen2p.js} +680 -440
- package/dist/{cli-vq97g1jq.js → cli-xawhpgc9.js} +95 -195
- package/dist/{cli-82d3nkc3.js → cli-xd4eqtr2.js} +2 -2
- package/dist/{cli-9fhkkpj5.js → cli-xt768r5m.js} +2 -2
- package/dist/{cli-zrk6jxv8.js → cli-y4x8ww6s.js} +2 -2
- package/dist/{cli-xc27fwzg.js → cli-y9jvxfhk.js} +3 -3
- package/dist/{cli-44159k28.js → cli-z63a269p.js} +2 -2
- package/dist/{cli-sm8rses9.js → cli-zfdp01hn.js} +8 -5
- package/dist/cli.js +31 -29
- package/dist/{cloudflare-workers-ai-system-one-ch2wxfcp.js → cloudflare-workers-ai-system-one-43v9qkjk.js} +7 -2
- package/dist/{codex-adapter-968xwfy7.js → codex-adapter-tcg1q3jk.js} +6 -4
- package/dist/{codex-login-m819c41r.js → codex-login-rn7c5gxt.js} +1 -1
- package/dist/{codex-session-runner-ht4z99fa.js → codex-session-runner-xfx4wd9x.js} +7 -5
- package/dist/{commands-pcymaeg9.js → commands-ew83nj70.js} +2 -2
- package/dist/{controller-fpjyk46r.js → controller-gnq1k1mf.js} +4 -4
- package/dist/{controllers-connect-mwzx1fh6.js → controllers-connect-tw1dan9r.js} +26 -24
- package/dist/{cursor-adapter-cp4s2e2f.js → cursor-adapter-yq5xgfcg.js} +1 -1
- package/dist/{db-xsjg9jqq.js → db-7gbc53fd.js} +14 -2
- package/dist/{db-sgd12bt9.js → db-t86xrnes.js} +3 -3
- package/dist/{devin-adapter-zgqadvnm.js → devin-adapter-4ycy4vrf.js} +1 -1
- package/dist/{dispatcher-x0jfw2c9.js → dispatcher-64bdyhps.js} +23 -21
- package/dist/{docker-fkgtr75t.js → docker-nfy2gc8t.js} +2 -2
- package/dist/{dsh-adapter-jrq7ma7h.js → dsh-adapter-tvhc4k2d.js} +1 -1
- package/dist/{e2b-16d6ch39.js → e2b-9gkdhm3c.js} +2 -2
- package/dist/{e2b-zn0b4w5w.js → e2b-cjtf8k1z.js} +2 -2
- package/dist/{easter-egg-3d-5cgynaja.js → easter-egg-3d-e4qv8dxj.js} +1 -1
- package/dist/{event-bus-9vpk8gmq.js → event-bus-3z78ep5n.js} +1 -1
- package/dist/{execute-t4e6m3rw.js → execute-0xpz8950.js} +85 -23
- package/dist/{external-channel-8njj4h3b.js → external-channel-e9nw24zv.js} +2 -2
- package/dist/{google-generative-ai-bmq8gkf3.js → google-generative-ai-mk9vcpe1.js} +15 -15
- package/dist/{google-vertex-b1rvp52s.js → google-vertex-q580kz8k.js} +20 -20
- package/dist/{grok-adapter-kkr97v2f.js → grok-adapter-v82srhrx.js} +9 -7
- package/dist/handlers-c9ajzhbn.js +41 -0
- package/dist/{heartbeat-wd03zhn0.js → heartbeat-2vqs1319.js} +26 -24
- package/dist/{hook-xzj2ts2p.js → hook-01nk13wx.js} +7 -5
- package/dist/{hook-f0vghj42.js → hook-jzpheegg.js} +9 -7
- package/dist/{http-4hwxv62p.js → http-fc1k6ec8.js} +859 -252
- package/dist/index-07ef7nkm.js +42 -0
- package/dist/{index-g6tbb6ve.js → index-31ceyf42.js} +1 -1
- package/dist/index-7yts8n9s.js +43 -0
- package/dist/{index-c4ykd0f1.js → index-dr94zbnh.js} +13348 -11611
- package/dist/index-q3t40ryv.js +46 -0
- package/dist/{index-ww2vznkp.js → index-sepja052.js} +1 -1
- package/dist/{index-97q4xn03.js → index-zdycv3ja.js} +135 -79
- package/dist/{index-g216q6jr.js → index-zsyx51ap.js} +1 -4
- package/dist/{keepalive-hrh7xnr9.js → keepalive-5nh2rhmr.js} +4 -4
- package/dist/lead-aayq64jn.js +79 -0
- package/dist/{llama-cpp-classify-vv43gswy.js → llama-cpp-classify-ee7vmd7q.js} +4 -1
- package/dist/{maintenance-e8wnwnqx.js → maintenance-hjhzdt3k.js} +1 -1
- package/dist/{mistral-conversations-1medfwv7.js → mistral-conversations-sd0xf1tn.js} +13 -13
- package/dist/{node-3v3f08f7.js → node-jzjj7r9x.js} +10 -9
- package/dist/{oauth-refresh-sweep-zm0yj4sj.js → oauth-refresh-sweep-y3n1knmd.js} +3 -3
- package/dist/{onboard-dtwcq603.js → onboard-1zq3m7db.js} +2 -2
- package/dist/{openai-codex-responses-de9pvs4d.js → openai-codex-responses-79s8xnbh.js} +29 -23
- package/dist/{openai-completions-mtqge3nf.js → openai-completions-tdbyts0x.js} +21 -20
- package/dist/{openai-decisions-ygk4kkxd.js → openai-decisions-bqhnjyfz.js} +2 -1
- package/dist/{openai-responses-dkyng71g.js → openai-responses-dm3t5vqp.js} +26 -17
- package/dist/{opencode-adapter-x4tqzhkh.js → opencode-adapter-e56086m1.js} +7 -5
- package/dist/{openrouter-images-wvv7camj.js → openrouter-images-ssttr1y4.js} +6 -3
- package/dist/{otel-impl-w3fbhpn0.js → otel-impl-h9yyza47.js} +2 -2
- package/dist/{pi-messages-nhh1pkz2.js → pi-messages-3nf8bq1a.js} +6 -4
- package/dist/{pi-mono-adapter-mcfkn9vf.js → pi-mono-adapter-tzps8f38.js} +9 -37
- package/dist/{pricing-refresh-j38dehfs.js → pricing-refresh-nevhat8h.js} +3 -3
- package/dist/{rbac-roles-ae8yttq4.js → rbac-roles-4y6ngvzq.js} +1 -1
- package/dist/{rbac-roles-ejxx9b35.js → rbac-roles-exbg8xb6.js} +2 -2
- package/dist/{registry-rxw10xzg.js → registry-ajhexe44.js} +1 -1
- package/dist/{render-v2-n16n0phe.js → render-v2-cfsh13z3.js} +3 -3
- package/dist/{resume-z0fgjc38.js → resume-5s2t0dbs.js} +10 -8
- package/dist/{runtime-xe3aqy4x.js → runtime-bt5pkpm1.js} +1 -1
- package/dist/{session-access-cv3mq6mc.js → session-access-dnbyp3cn.js} +6 -4
- package/dist/{setup-mafhj3yt.js → setup-1wj1y77j.js} +1 -1
- package/dist/{typesafe-system-one-2hgpayzy.js → typesafe-system-one-bre38hvs.js} +4 -2
- package/dist/{virtual-modules-4r3zkc20.js → virtual-modules-mnfbh5mr.js} +8 -2
- package/dist/{work-objects-8b86mgjp.js → work-objects-7mg6216g.js} +26 -24
- package/dist/worker-nwb789mg.js +79 -0
- package/dist/{x-y45mthwn.js → x-pbpezr0s.js} +2 -2
- package/openapi.json +793 -6
- package/package.json +11 -11
- package/src/apps/catalog.generated.json +206 -4
- package/src/apps/page-validator.ts +13 -1
- package/src/assets/key.ts +17 -0
- package/src/azure-devops/handlers.ts +1 -1
- package/src/be/chunking.ts +42 -9
- package/src/be/db/approvals.ts +18 -0
- package/src/be/db/session-moves.ts +164 -0
- package/src/be/db/session-tree.ts +384 -0
- package/src/be/db/tasks/draft-text.ts +15 -0
- package/src/be/db/tasks/read.ts +54 -5
- package/src/be/db/workflow-runs.ts +96 -0
- package/src/be/db.ts +85 -237
- package/src/be/memory/index-content.ts +36 -17
- package/src/be/memory/providers/openai-embedding.ts +115 -61
- package/src/be/memory/providers/sqlite-store.ts +69 -23
- package/src/be/memory/reranker.ts +31 -1
- package/src/be/memory/search-candidates.ts +47 -0
- package/src/be/memory/types.ts +14 -0
- package/src/be/onboarding.ts +3 -0
- package/src/be/scripts/typecheck.ts +2 -0
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +106 -54
- package/src/be/seed-scripts/index.ts +2 -2
- package/src/be/skill-sync.ts +43 -2
- package/src/be/swarm-config-guard.ts +25 -1
- package/src/be/task-attachment-store.ts +30 -0
- package/src/bitbucket/api.ts +81 -0
- package/src/bitbucket/auth.ts +64 -0
- package/src/bitbucket/handlers.ts +434 -0
- package/src/bitbucket/index.ts +28 -0
- package/src/bitbucket/templates.ts +134 -0
- package/src/bitbucket/types.ts +65 -0
- package/src/commands/runner.ts +55 -3
- package/src/e2b/env.ts +1 -0
- package/src/extensions/catalog.generated.json +4 -4
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +9 -2
- package/src/extensions/post-bridge.ts +1 -0
- package/src/fs/provider.ts +13 -1
- package/src/github/handlers.ts +6 -6
- package/src/gitlab/handlers.ts +5 -5
- package/src/heartbeat/heartbeat.ts +31 -11
- package/src/http/assets.ts +14 -2
- package/src/http/core.ts +12 -0
- package/src/http/fs.ts +54 -34
- package/src/http/index.ts +4 -0
- package/src/http/mcp-body.ts +37 -0
- package/src/http/mcp-user.ts +3 -5
- package/src/http/mcp.ts +6 -7
- package/src/http/memory.ts +26 -15
- package/src/http/onboarding.ts +1 -0
- package/src/http/page-proxy.ts +61 -5
- package/src/http/pages-public.ts +27 -44
- package/src/http/pages.ts +4 -4
- package/src/http/script-runs.ts +2 -0
- package/src/http/sessions.ts +366 -12
- package/src/http/skills.ts +48 -1
- package/src/http/tasks.ts +1 -1
- package/src/http/users.ts +13 -1
- package/src/http/webhooks.ts +141 -0
- package/src/integrations/chat-sdk/adapters.ts +24 -4
- package/src/integrations/chat-sdk/attachments.ts +90 -12
- package/src/integrations/chat-sdk/facts.ts +138 -0
- package/src/integrations/chat-sdk/inbound.ts +156 -8
- package/src/integrations/chat-sdk/limits.ts +24 -0
- package/src/integrations/chat-sdk/outbound-files.ts +186 -0
- package/src/integrations/chat-sdk/outbound.ts +272 -5
- package/src/integrations/chat-sdk/relay.ts +4 -1
- package/src/integrations/chat-sdk/router.ts +28 -2
- package/src/integrations/chat-sdk/steering.ts +9 -0
- package/src/integrations/chat-sdk/templates.ts +14 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +4 -0
- package/src/mcp-limits.ts +20 -0
- package/src/pages/browser-sdk.ts +8 -3
- package/src/pages/feedback-overlay.ts +1 -1
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +106 -119
- package/src/providers/codex-agents-md.ts +35 -229
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +5 -53
- package/src/realtime/transport.ts +1 -2
- package/src/script-workflows/workflow-ctx.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +2 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +14 -4
- package/src/scripts-runtime/types/swarm-sdk.d.ts +2 -0
- package/src/server-user.ts +2 -0
- package/src/server.ts +2 -0
- package/src/slack/assistant.ts +2 -2
- package/src/slack/files.ts +2 -0
- package/src/slack/handlers.test.ts +158 -0
- package/src/slack/handlers.ts +23 -32
- package/src/slack/inbound-files.ts +39 -6
- package/src/slack/thread-buffer.ts +2 -1
- package/src/tasks/context-key.ts +61 -1
- package/src/tasks/task-terminal-effects.ts +21 -17
- package/src/tests/apps-card-grid.test.ts +197 -0
- package/src/tests/apps-catalog-additions.test.ts +120 -0
- package/src/tests/apps-tree.test.ts +129 -0
- package/src/tests/bitbucket-auth.test.ts +156 -0
- package/src/tests/bitbucket-handlers.test.ts +425 -0
- package/src/tests/bitbucket-webhook.test.ts +220 -0
- package/src/tests/chat-sdk-attachments-reply.test.ts +52 -0
- package/src/tests/chat-sdk-config.test.ts +11 -0
- package/src/tests/chat-sdk-facts.test.ts +23 -0
- package/src/tests/chat-sdk-inbound.test.ts +597 -4
- package/src/tests/chat-sdk-outbound-files.test.ts +652 -0
- package/src/tests/chat-sdk-telegram-markdown.test.ts +92 -0
- package/src/tests/codex-adapter.test.ts +167 -242
- package/src/tests/config-api-only-keys.test.ts +9 -0
- package/src/tests/context-key.test.ts +50 -0
- package/src/tests/core-auth.test.ts +5 -0
- package/src/tests/cors-allowlist.test.ts +1 -1
- package/src/tests/db-task-read-contract.test.ts +7 -0
- package/src/tests/db-task-write-contract.test.ts +6 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/extensions-example-slack-reply-gate.test.ts +262 -91
- package/src/tests/fixtures/bitbucket/pullrequest-comment-created-inline.json +174 -0
- package/src/tests/fixtures/bitbucket/pullrequest-comment-created.json +170 -0
- package/src/tests/fixtures/bitbucket/pullrequest-created-mention.json +132 -0
- package/src/tests/fixtures/bitbucket/pullrequest-created-reviewer.json +140 -0
- package/src/tests/fixtures/bitbucket/pullrequest-fulfilled.json +134 -0
- package/src/tests/fixtures/bitbucket/pullrequest-rejected.json +133 -0
- package/src/tests/generate-mcp-docs.test.ts +101 -0
- package/src/tests/gitlab-handlers.test.ts +3 -3
- package/src/tests/gitlab-vcs-db.test.ts +4 -4
- package/src/tests/heartbeat-checklist.test.ts +33 -0
- package/src/tests/heartbeat-jev-gate-credentials.test.ts +44 -0
- package/src/tests/heartbeat-jev-gate.test.ts +242 -1
- package/src/tests/integration-disable-flags.test.ts +36 -0
- package/src/tests/kv-page-proxy.test.ts +91 -5
- package/src/tests/launch-password-rejection.test.ts +2 -2
- package/src/tests/mcp-input-caps.test.ts +294 -0
- package/src/tests/mcp-tools.test.ts +1 -1
- package/src/tests/memory-chunked-search-starvation.test.ts +200 -0
- package/src/tests/memory-embedding-input-cap.test.ts +114 -0
- package/src/tests/memory.test.ts +14 -0
- package/src/tests/onboarding.test.ts +12 -0
- package/src/tests/page-guest-session.test.ts +19 -8
- package/src/tests/page-proxy-authed.test.ts +1 -1
- package/src/tests/page-proxy.test.ts +17 -10
- package/src/tests/page-session.test.ts +102 -1
- package/src/tests/pages-authed-mode.test.ts +82 -12
- package/src/tests/pages-password-mode.test.ts +5 -5
- package/src/tests/pi-codemode.test.ts +8 -2
- package/src/tests/preload-env.test.ts +57 -0
- package/src/tests/preload.ts +21 -0
- package/src/tests/prompt-template-remaining.test.ts +38 -0
- package/src/tests/realtime-transport.test.ts +13 -7
- package/src/tests/run-root-coverage.test.ts +39 -0
- package/src/tests/runner-bitbucket-vcs.test.ts +191 -0
- package/src/tests/runner-skills-refresh.test.ts +58 -0
- package/src/tests/script-runs-http.test.ts +84 -0
- package/src/tests/scripts-http.test.ts +10 -1
- package/src/tests/secret-scrubber.test.ts +15 -0
- package/src/tests/sessions-move.test.ts +576 -0
- package/src/tests/sessions-tree.test.ts +493 -0
- package/src/tests/skill-files-http.test.ts +50 -0
- package/src/tests/skills-bundle.test.ts +99 -0
- package/src/tests/swarm-config-export-to-env.test.ts +23 -3
- package/src/tests/task-audio-transcription.test.ts +299 -0
- package/src/tests/task-completion-memory-chunking.test.ts +434 -0
- package/src/tests/task-terminal-secret-scrub.test.ts +6 -1
- package/src/tests/transcription.test.ts +299 -0
- package/src/tests/vcs-bitbucket.test.ts +91 -0
- package/src/tests/vcs-provider-isolation.test.ts +123 -0
- package/src/tests/vcs-provider.test.ts +16 -1
- package/src/tests/vcs-tracking.test.ts +3 -3
- package/src/tests/workflow-foreach-bodies.test.ts +637 -0
- package/src/tests/workflow-foreach-concurrency.test.ts +342 -0
- package/src/tests/workflow-foreach-retry.test.ts +537 -0
- package/src/tests/workflow-foreach.test.ts +44 -23
- package/src/tests/workflow-step-claims.test.ts +6 -6
- package/src/tests/workflow-system-one-decision-providers.test.ts +98 -1
- package/src/tests/workflow-system-one-decision.test.ts +2 -1
- package/src/tests/workflow-tla-races.test.ts +2 -2
- package/src/tools/chat-access.ts +10 -0
- package/src/tools/chat-post.ts +31 -11
- package/src/tools/chat-reply.ts +32 -10
- package/src/tools/memory-search.ts +3 -1
- package/src/tools/script-delete.ts +1 -1
- package/src/tools/system-one-decide.ts +17 -4
- package/src/tools/workflows/create-workflow.ts +5 -3
- package/src/types.ts +9 -2
- package/src/utils/config-env-export.ts +4 -1
- package/src/utils/page-session.ts +133 -20
- package/src/utils/secret-scrubber.ts +4 -0
- package/src/utils/skills-refresh.ts +83 -43
- package/src/utils/transcription.ts +246 -0
- package/src/vcs/bitbucket.ts +58 -0
- package/src/vcs/index.ts +2 -0
- package/src/vcs/types.ts +2 -2
- package/src/workflows/approval-resolution.ts +4 -1
- package/src/workflows/checkpoint.ts +9 -1
- package/src/workflows/constants.ts +3 -0
- package/src/workflows/definition.ts +48 -17
- package/src/workflows/engine.ts +25 -15
- package/src/workflows/executors/foreach.ts +45 -99
- package/src/workflows/executors/system-one-decision.ts +28 -7
- package/src/workflows/executors/system-one-providers.ts +39 -4
- package/src/workflows/foreach-body.ts +146 -0
- package/src/workflows/foreach-driver.ts +552 -0
- package/src/workflows/foreach-join.ts +206 -7
- package/src/workflows/node-timeout.ts +21 -0
- package/src/workflows/recovery.ts +68 -3
- package/src/workflows/resume.ts +221 -43
- package/src/workflows/retry-poller.ts +39 -24
- package/src/workflows/step-input.ts +59 -0
- package/src/workflows/task-step-routing.ts +114 -56
- package/templates/extensions/slack-reply-gate/README.md +24 -22
- package/templates/extensions/slack-reply-gate/hooks.ts +146 -95
- package/templates/extensions/slack-reply-gate/manifest.json +2 -2
- package/templates/skills/apps/SKILL.md +28 -6
- package/templates/skills/apps/content.md +28 -6
- package/templates/skills/chat-sdk/content.md +6 -2
- package/templates/skills/code-quality/content.md +2 -1
- package/templates/skills/heartbeat-runbook/content.md +5 -5
- package/templates/skills/pages/content.md +6 -4
- package/templates/skills/slack-interaction/content.md +5 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -2
- package/templates/skills/swarm-scripts/content.md +2 -2
- package/templates/skills/work-on-task/SKILL.md +1 -1
- package/templates/skills/work-on-task/content.md +1 -1
- package/dist/cli-51y09c6p.js +0 -2657
- package/dist/cli-yw91rnmw.js +0 -13
- package/dist/handlers-0pvee9nw.js +0 -39
- package/dist/index-gdh8jrdm.js +0 -43
- package/dist/index-hg0x2cdv.js +0 -40
- package/dist/index-thm0y6a8.js +0 -41
- package/dist/lead-ee8vazz2.js +0 -77
- package/dist/worker-16s75hm5.js +0 -77
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
gitlabContextKey,
|
|
10
10
|
azureDevOpsContextKey,
|
|
11
11
|
azureDevOpsWorkItemContextKey,
|
|
12
|
+
bitbucketContextKey,
|
|
12
13
|
linearContextKey,
|
|
13
14
|
buildJiraContextKey,
|
|
14
15
|
scheduleContextKey,
|
|
@@ -72,6 +73,7 @@ import {
|
|
|
72
73
|
hasNonTerminalRerouteDecisionChild2,
|
|
73
74
|
getAgentCurrentTask2,
|
|
74
75
|
findTaskByVcs2,
|
|
76
|
+
findActiveTasksByVcs2,
|
|
75
77
|
readableSessionCondition,
|
|
76
78
|
getAllTasks2,
|
|
77
79
|
getPendingChatRelayTasks2,
|
|
@@ -155,6 +157,8 @@ import {
|
|
|
155
157
|
computeScore,
|
|
156
158
|
rerank,
|
|
157
159
|
init_reranker,
|
|
160
|
+
searchMemoryCandidates,
|
|
161
|
+
init_search_candidates,
|
|
158
162
|
rowToCandidate,
|
|
159
163
|
init_sqlite_store,
|
|
160
164
|
getEmbeddingProvider2,
|
|
@@ -332,19 +336,19 @@ import {
|
|
|
332
336
|
recordInlineScriptRun2,
|
|
333
337
|
exports_db,
|
|
334
338
|
init_db3
|
|
335
|
-
} from "./cli-
|
|
339
|
+
} from "./cli-fcc5qe3f.js";
|
|
336
340
|
import {
|
|
337
341
|
getUserGrant2,
|
|
338
342
|
init_rbac_roles
|
|
339
|
-
} from "./cli-
|
|
343
|
+
} from "./cli-0z3vjrpm.js";
|
|
340
344
|
import {
|
|
341
345
|
ensurePricingSeeded2,
|
|
342
346
|
ensureRbacSeeded2,
|
|
343
347
|
ensureModelProfilesSeeded2
|
|
344
|
-
} from "./cli-
|
|
348
|
+
} from "./cli-36j4jnk3.js";
|
|
345
349
|
import {
|
|
346
350
|
loadModelsDevCache
|
|
347
|
-
} from "./cli-
|
|
351
|
+
} from "./cli-0y6f0ckq.js";
|
|
348
352
|
import {
|
|
349
353
|
buildCatalogEntries,
|
|
350
354
|
listModelCatalog,
|
|
@@ -354,12 +358,12 @@ import {
|
|
|
354
358
|
loadModelsCatalog,
|
|
355
359
|
requestModelCatalogRefresh2,
|
|
356
360
|
startPricingRefreshLoop2
|
|
357
|
-
} from "./cli-
|
|
361
|
+
} from "./cli-y9jvxfhk.js";
|
|
358
362
|
import {
|
|
359
363
|
ampPinProviderError,
|
|
360
364
|
ampPinCatalogError,
|
|
361
365
|
ampModelError
|
|
362
|
-
} from "./cli-
|
|
366
|
+
} from "./cli-jpxsrxcb.js";
|
|
363
367
|
import {
|
|
364
368
|
notifyAutomationPreflightFailure,
|
|
365
369
|
isNeedsSetupFailure,
|
|
@@ -368,50 +372,50 @@ import {
|
|
|
368
372
|
getAutomationSetupStates,
|
|
369
373
|
schedulePreflightInput,
|
|
370
374
|
recordSchedulePreflightFailure,
|
|
375
|
+
BaseExecutor,
|
|
376
|
+
postApprovalCancellationUpdates,
|
|
377
|
+
createApprovalFollowUpTask,
|
|
378
|
+
HumanInTheLoopExecutor,
|
|
379
|
+
resolveWorkflowLlmConfig,
|
|
380
|
+
SYSTEM_ONE_PROVIDER_IDS,
|
|
381
|
+
SystemOneExtractionExecutor,
|
|
382
|
+
SYSTEM_ONE_DECISION_NODE_TYPE,
|
|
383
|
+
SystemOneDecisionConfigSchema,
|
|
384
|
+
SystemOneDecisionExecutor,
|
|
371
385
|
checkpointStep,
|
|
372
386
|
checkpointStepFailure,
|
|
373
387
|
checkpointStepWaiting,
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
buildForeachAggregate,
|
|
388
|
+
FAILED_TASK_OUTPUT_PREFIX,
|
|
389
|
+
FOREACH_ITEMS_WAIT_FOR,
|
|
377
390
|
loadCompletedStepRouting,
|
|
378
391
|
resolveInputValue,
|
|
379
392
|
getSecretInputKeys,
|
|
380
393
|
validateJsonSchema,
|
|
381
394
|
findJsonSchemaShapeErrors,
|
|
382
|
-
getMaxWorkflowStepsPerRun,
|
|
383
395
|
workflowSaveWarnings,
|
|
384
396
|
withSaveWarnings,
|
|
385
397
|
runStepValidation,
|
|
386
|
-
shapeApprovalResolution,
|
|
387
|
-
FAILED_TASK_OUTPUT_PREFIX,
|
|
388
|
-
SubWorkflowExecutor,
|
|
389
|
-
WaitExecutor,
|
|
390
|
-
failStepAndRunIfWaiting,
|
|
391
|
-
checkpointPortStepAndResolveSuccessors,
|
|
392
|
-
scheduleTaskStepRetry,
|
|
393
|
-
completeTaskStepAndResolveSuccessors,
|
|
394
|
-
setupWorkflowResumeListener2,
|
|
395
|
-
finalizeOrWait2,
|
|
396
|
-
retryFailedRun2,
|
|
397
|
-
cancelWorkflowRunRows2,
|
|
398
|
-
cancelWorkflowRun2,
|
|
399
|
-
resumeWaitState2,
|
|
400
|
-
recoverResolvedWaitState2,
|
|
401
|
-
resumeFromChildRun2,
|
|
402
|
-
initWaitBusSubscriptions2,
|
|
403
398
|
TriggerSchemaError,
|
|
404
399
|
startWorkflowExecution2,
|
|
405
400
|
failRunOnUnreadableReplay,
|
|
406
401
|
isWorkflowRunActive,
|
|
407
402
|
holdWorkflowRun,
|
|
408
403
|
walkGraph,
|
|
409
|
-
rehydrateCompletedStepOutputs,
|
|
410
404
|
findReadyNodes,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
405
|
+
scriptBodyInterpolationError,
|
|
406
|
+
ForeachExecutor,
|
|
407
|
+
rebuildNodeExecutionInput,
|
|
408
|
+
isForeachChildOwned,
|
|
409
|
+
parkAndDriveForeach,
|
|
410
|
+
runForeachDrive,
|
|
411
|
+
stepFailureMode,
|
|
412
|
+
generateEdges,
|
|
413
|
+
resolveValidationPort,
|
|
414
|
+
getSuccessors,
|
|
415
|
+
definitionNodeIds,
|
|
416
|
+
validateDefinition,
|
|
417
|
+
applyDefinitionPatch
|
|
418
|
+
} from "./cli-92mqenkc.js";
|
|
415
419
|
import {
|
|
416
420
|
require_dist2,
|
|
417
421
|
publicEndpointSsrfOptions,
|
|
@@ -471,14 +475,14 @@ import {
|
|
|
471
475
|
deleteApp,
|
|
472
476
|
typecheckScript,
|
|
473
477
|
parseSkillContent
|
|
474
|
-
} from "./cli-
|
|
478
|
+
} from "./cli-we0ra057.js";
|
|
475
479
|
import {
|
|
476
480
|
buildAuthorizationUrl,
|
|
477
481
|
onAuthorizationRefreshed,
|
|
478
482
|
ensureAuthorizationTokenOrThrow,
|
|
479
483
|
ensureToken,
|
|
480
484
|
ensureTokenOrThrow
|
|
481
|
-
} from "./cli-
|
|
485
|
+
} from "./cli-s4sntwt4.js";
|
|
482
486
|
import {
|
|
483
487
|
detachedProcessGroup,
|
|
484
488
|
registerProcessGroup,
|
|
@@ -508,36 +512,36 @@ import {
|
|
|
508
512
|
getSlackApp2,
|
|
509
513
|
startSlackApp2,
|
|
510
514
|
stopSlackApp2
|
|
511
|
-
} from "./cli-
|
|
515
|
+
} from "./cli-fy1jyyym.js";
|
|
512
516
|
import {
|
|
513
517
|
slackCode,
|
|
514
518
|
slackMissingScopeMessage,
|
|
515
519
|
withAutoJoin,
|
|
516
520
|
externalChannelToolError2,
|
|
517
521
|
getChannelBlockReason2
|
|
518
|
-
} from "./cli-
|
|
519
|
-
import {
|
|
520
|
-
BaseExecutor,
|
|
521
|
-
postApprovalCancellationUpdates,
|
|
522
|
-
createApprovalFollowUpTask,
|
|
523
|
-
HumanInTheLoopExecutor,
|
|
524
|
-
resolveWorkflowLlmConfig,
|
|
525
|
-
SYSTEM_ONE_PROVIDER_IDS,
|
|
526
|
-
SystemOneExtractionExecutor,
|
|
527
|
-
SYSTEM_ONE_DECISION_NODE_TYPE,
|
|
528
|
-
SystemOneDecisionConfigSchema,
|
|
529
|
-
SystemOneDecisionExecutor,
|
|
530
|
-
generateEdges,
|
|
531
|
-
resolveValidationPort,
|
|
532
|
-
getSuccessors,
|
|
533
|
-
definitionNodeIds,
|
|
534
|
-
validateDefinition,
|
|
535
|
-
applyDefinitionPatch
|
|
536
|
-
} from "./cli-q6r7t299.js";
|
|
522
|
+
} from "./cli-ftmq4nvk.js";
|
|
537
523
|
import {
|
|
538
524
|
workflowEventBus2,
|
|
539
525
|
init_event_bus
|
|
540
|
-
} from "./cli-
|
|
526
|
+
} from "./cli-dabehxhp.js";
|
|
527
|
+
import {
|
|
528
|
+
shapeApprovalResolution,
|
|
529
|
+
SubWorkflowExecutor,
|
|
530
|
+
WaitExecutor,
|
|
531
|
+
failStepAndRunIfWaiting,
|
|
532
|
+
checkpointPortStepAndResolveSuccessors,
|
|
533
|
+
scheduleTaskStepRetry,
|
|
534
|
+
completeTaskStepAndResolveSuccessors,
|
|
535
|
+
setupWorkflowResumeListener2,
|
|
536
|
+
finalizeOrWait2,
|
|
537
|
+
retryFailedRun2,
|
|
538
|
+
cancelWorkflowRunRows2,
|
|
539
|
+
cancelWorkflowRun2,
|
|
540
|
+
resumeWaitState2,
|
|
541
|
+
recoverResolvedWaitState2,
|
|
542
|
+
resumeFromChildRun2,
|
|
543
|
+
initWaitBusSubscriptions2
|
|
544
|
+
} from "./cli-3zwye9sn.js";
|
|
541
545
|
import {
|
|
542
546
|
duplicateGuardedQueryKey,
|
|
543
547
|
parseQueryParams,
|
|
@@ -564,19 +568,21 @@ import {
|
|
|
564
568
|
isPublicRoute,
|
|
565
569
|
findRoute,
|
|
566
570
|
route
|
|
567
|
-
} from "./cli-
|
|
571
|
+
} from "./cli-9ce2xw98.js";
|
|
568
572
|
import {
|
|
569
573
|
isMultiRuntimeEnabled
|
|
570
574
|
} from "./cli-e8xyjvfc.js";
|
|
571
575
|
import {
|
|
576
|
+
FilesError,
|
|
572
577
|
providerPath,
|
|
578
|
+
normalizeStoredKey,
|
|
573
579
|
AgentFsProvider,
|
|
574
580
|
getFileStorageProvider2
|
|
575
|
-
} from "./cli-
|
|
581
|
+
} from "./cli-g9ypd5en.js";
|
|
576
582
|
import {
|
|
577
583
|
getRuntimePool2,
|
|
578
584
|
init_db
|
|
579
|
-
} from "./cli-
|
|
585
|
+
} from "./cli-5rvg1ddk.js";
|
|
580
586
|
import {
|
|
581
587
|
getMemoryRaterNames,
|
|
582
588
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
@@ -587,7 +593,7 @@ import {
|
|
|
587
593
|
COMPOSIO_HTTP_METHODS,
|
|
588
594
|
executeComposioRequest,
|
|
589
595
|
composioArgsFromParts
|
|
590
|
-
} from "./cli-
|
|
596
|
+
} from "./cli-pasyvjmm.js";
|
|
591
597
|
import {
|
|
592
598
|
require_fast_deep_equal
|
|
593
599
|
} from "./cli-bhp11egn.js";
|
|
@@ -601,7 +607,7 @@ import {
|
|
|
601
607
|
import {
|
|
602
608
|
canProvisionKind,
|
|
603
609
|
init_runtime_providers
|
|
604
|
-
} from "./cli-
|
|
610
|
+
} from "./cli-p859hcc8.js";
|
|
605
611
|
import {
|
|
606
612
|
findUserById,
|
|
607
613
|
findUserByExternalId,
|
|
@@ -617,7 +623,7 @@ import {
|
|
|
617
623
|
resolveSessionToken,
|
|
618
624
|
fingerprintApiKey,
|
|
619
625
|
init_users
|
|
620
|
-
} from "./cli-
|
|
626
|
+
} from "./cli-xt768r5m.js";
|
|
621
627
|
import {
|
|
622
628
|
isRbacEnabled,
|
|
623
629
|
decideAdmission,
|
|
@@ -686,7 +692,7 @@ import {
|
|
|
686
692
|
KvNamespaceSchema,
|
|
687
693
|
KvKeySchema,
|
|
688
694
|
init_types
|
|
689
|
-
} from "./cli-
|
|
695
|
+
} from "./cli-rh5smt8t.js";
|
|
690
696
|
import {
|
|
691
697
|
generateDefaultClaudeMd2,
|
|
692
698
|
generateDefaultSoulMd2,
|
|
@@ -695,7 +701,7 @@ import {
|
|
|
695
701
|
taskAttachmentFetchCommand,
|
|
696
702
|
taskAttachmentDisplayUrl,
|
|
697
703
|
init_task_attachment_links
|
|
698
|
-
} from "./cli-
|
|
704
|
+
} from "./cli-gpv60278.js";
|
|
699
705
|
import {
|
|
700
706
|
getSlackConfiguration,
|
|
701
707
|
init_config
|
|
@@ -707,7 +713,6 @@ import {
|
|
|
707
713
|
import {
|
|
708
714
|
findInterpolationTokens,
|
|
709
715
|
interpolate,
|
|
710
|
-
deepInterpolate,
|
|
711
716
|
init_template,
|
|
712
717
|
registerTemplate,
|
|
713
718
|
getTemplateDefinition,
|
|
@@ -733,7 +738,6 @@ import {
|
|
|
733
738
|
_null,
|
|
734
739
|
any,
|
|
735
740
|
unknown,
|
|
736
|
-
never,
|
|
737
741
|
array2,
|
|
738
742
|
object2,
|
|
739
743
|
looseObject,
|
|
@@ -757,7 +761,7 @@ import {
|
|
|
757
761
|
import {
|
|
758
762
|
init_package,
|
|
759
763
|
package_default
|
|
760
|
-
} from "./cli-
|
|
764
|
+
} from "./cli-179xcyky.js";
|
|
761
765
|
import {
|
|
762
766
|
realtimeBus,
|
|
763
767
|
init_bus
|
|
@@ -786,11 +790,12 @@ import {
|
|
|
786
790
|
import {
|
|
787
791
|
scrubSecrets,
|
|
788
792
|
scrubObject,
|
|
793
|
+
createValueScrubber,
|
|
789
794
|
refreshSecretScrubberCache,
|
|
790
795
|
registerVolatileSecret,
|
|
791
796
|
registerSensitiveKeyName,
|
|
792
797
|
init_secret_scrubber
|
|
793
|
-
} from "./cli-
|
|
798
|
+
} from "./cli-n4c8e3s5.js";
|
|
794
799
|
import {
|
|
795
800
|
isAlias,
|
|
796
801
|
parseAlias,
|
|
@@ -16809,6 +16814,9 @@ class Protocol {
|
|
|
16809
16814
|
this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
|
|
16810
16815
|
const handleTaskResult = async () => {
|
|
16811
16816
|
const taskId = request.params.taskId;
|
|
16817
|
+
if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
|
|
16818
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
16819
|
+
}
|
|
16812
16820
|
if (this._taskMessageQueue) {
|
|
16813
16821
|
let queuedMessage;
|
|
16814
16822
|
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
@@ -16839,12 +16847,12 @@ class Protocol {
|
|
|
16839
16847
|
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
16840
16848
|
}
|
|
16841
16849
|
if (!isTerminal(task.status)) {
|
|
16842
|
-
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
16850
|
+
await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
|
|
16843
16851
|
return await handleTaskResult();
|
|
16844
16852
|
}
|
|
16845
16853
|
if (isTerminal(task.status)) {
|
|
16846
16854
|
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
16847
|
-
this._clearTaskQueue(taskId);
|
|
16855
|
+
this._clearTaskQueue(taskId, extra.sessionId);
|
|
16848
16856
|
return {
|
|
16849
16857
|
...result,
|
|
16850
16858
|
_meta: {
|
|
@@ -16881,7 +16889,7 @@ class Protocol {
|
|
|
16881
16889
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
16882
16890
|
}
|
|
16883
16891
|
await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
16884
|
-
this._clearTaskQueue(request.params.taskId);
|
|
16892
|
+
this._clearTaskQueue(request.params.taskId, extra.sessionId);
|
|
16885
16893
|
const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
16886
16894
|
if (!cancelledTask) {
|
|
16887
16895
|
throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
|
|
@@ -17004,6 +17012,19 @@ class Protocol {
|
|
|
17004
17012
|
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
17005
17013
|
const capturedTransport = this._transport;
|
|
17006
17014
|
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
17015
|
+
const sessionId = capturedTransport?.sessionId;
|
|
17016
|
+
const store = this._taskStore;
|
|
17017
|
+
let relatedTaskFound = true;
|
|
17018
|
+
let relatedTaskLookup;
|
|
17019
|
+
if (relatedTaskId && store && this._taskMessageQueue && sessionId !== undefined) {
|
|
17020
|
+
relatedTaskFound = false;
|
|
17021
|
+
relatedTaskLookup = (async () => {
|
|
17022
|
+
if (!await store.getTask(relatedTaskId, sessionId)) {
|
|
17023
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
|
|
17024
|
+
}
|
|
17025
|
+
relatedTaskFound = true;
|
|
17026
|
+
})();
|
|
17027
|
+
}
|
|
17007
17028
|
if (handler === undefined) {
|
|
17008
17029
|
const errorResponse = {
|
|
17009
17030
|
jsonrpc: "2.0",
|
|
@@ -17013,7 +17034,10 @@ class Protocol {
|
|
|
17013
17034
|
message: "Method not found"
|
|
17014
17035
|
}
|
|
17015
17036
|
};
|
|
17016
|
-
if (relatedTaskId &&
|
|
17037
|
+
if (relatedTaskId && relatedTaskLookup) {
|
|
17038
|
+
const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
|
|
17039
|
+
relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
17040
|
+
} else if (relatedTaskId && this._taskMessageQueue) {
|
|
17017
17041
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
17018
17042
|
type: "error",
|
|
17019
17043
|
message: errorResponse,
|
|
@@ -17064,7 +17088,10 @@ class Protocol {
|
|
|
17064
17088
|
closeSSEStream: extra?.closeSSEStream,
|
|
17065
17089
|
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
17066
17090
|
};
|
|
17067
|
-
Promise.resolve().then(() => {
|
|
17091
|
+
(relatedTaskLookup ?? Promise.resolve()).then(() => {
|
|
17092
|
+
if (relatedTaskLookup && abortController.signal.aborted) {
|
|
17093
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
17094
|
+
}
|
|
17068
17095
|
if (taskCreationParams) {
|
|
17069
17096
|
this.assertTaskHandlerCapability(request.method);
|
|
17070
17097
|
}
|
|
@@ -17099,7 +17126,7 @@ class Protocol {
|
|
|
17099
17126
|
...error["data"] !== undefined && { data: error["data"] }
|
|
17100
17127
|
}
|
|
17101
17128
|
};
|
|
17102
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
17129
|
+
if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
|
|
17103
17130
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
17104
17131
|
type: "error",
|
|
17105
17132
|
message: errorResponse,
|
|
@@ -17487,7 +17514,7 @@ class Protocol {
|
|
|
17487
17514
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
17488
17515
|
}
|
|
17489
17516
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
17490
|
-
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
17517
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
|
|
17491
17518
|
}
|
|
17492
17519
|
async _clearTaskQueue(taskId, sessionId) {
|
|
17493
17520
|
if (this._taskMessageQueue) {
|
|
@@ -17506,10 +17533,10 @@ class Protocol {
|
|
|
17506
17533
|
}
|
|
17507
17534
|
}
|
|
17508
17535
|
}
|
|
17509
|
-
async _waitForTaskUpdate(taskId, signal) {
|
|
17536
|
+
async _waitForTaskUpdate(taskId, signal, sessionId) {
|
|
17510
17537
|
let interval = this._options?.defaultTaskPollInterval ?? 1000;
|
|
17511
17538
|
try {
|
|
17512
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
17539
|
+
const task = await this._taskStore?.getTask(taskId, sessionId);
|
|
17513
17540
|
if (task?.pollInterval) {
|
|
17514
17541
|
interval = task.pollInterval;
|
|
17515
17542
|
}
|
|
@@ -18178,6 +18205,42 @@ class ExperimentalMcpServerTasks {
|
|
|
18178
18205
|
|
|
18179
18206
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
18180
18207
|
init_zod();
|
|
18208
|
+
function toolInputElementCount(value, max) {
|
|
18209
|
+
let count = 0;
|
|
18210
|
+
const stack = [value];
|
|
18211
|
+
while (stack.length > 0) {
|
|
18212
|
+
const node = stack.pop();
|
|
18213
|
+
if (node === null || typeof node !== "object")
|
|
18214
|
+
continue;
|
|
18215
|
+
if (Array.isArray(node)) {
|
|
18216
|
+
for (const child of node) {
|
|
18217
|
+
if (++count > max)
|
|
18218
|
+
return count;
|
|
18219
|
+
if (child !== null && typeof child === "object")
|
|
18220
|
+
stack.push(child);
|
|
18221
|
+
}
|
|
18222
|
+
} else {
|
|
18223
|
+
for (const key in node) {
|
|
18224
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
18225
|
+
continue;
|
|
18226
|
+
if (++count > max)
|
|
18227
|
+
return count;
|
|
18228
|
+
const child = node[key];
|
|
18229
|
+
if (child !== null && typeof child === "object")
|
|
18230
|
+
stack.push(child);
|
|
18231
|
+
}
|
|
18232
|
+
}
|
|
18233
|
+
}
|
|
18234
|
+
return count;
|
|
18235
|
+
}
|
|
18236
|
+
function resolveMaxToolInputElements(value) {
|
|
18237
|
+
if (value === undefined || value === Infinity)
|
|
18238
|
+
return;
|
|
18239
|
+
if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
|
|
18240
|
+
throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
|
|
18241
|
+
}
|
|
18242
|
+
return value;
|
|
18243
|
+
}
|
|
18181
18244
|
|
|
18182
18245
|
class McpServer {
|
|
18183
18246
|
constructor(serverInfo, options) {
|
|
@@ -18190,6 +18253,7 @@ class McpServer {
|
|
|
18190
18253
|
this._resourceHandlersInitialized = false;
|
|
18191
18254
|
this._promptHandlersInitialized = false;
|
|
18192
18255
|
this.server = new Server(serverInfo, options);
|
|
18256
|
+
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
18193
18257
|
}
|
|
18194
18258
|
get experimental() {
|
|
18195
18259
|
if (!this._experimental) {
|
|
@@ -18296,12 +18360,15 @@ class McpServer {
|
|
|
18296
18360
|
};
|
|
18297
18361
|
}
|
|
18298
18362
|
async validateToolInput(tool, args, toolName) {
|
|
18363
|
+
if (this._maxToolInputElements !== undefined && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
|
|
18364
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
|
|
18365
|
+
}
|
|
18299
18366
|
if (!tool.inputSchema) {
|
|
18300
18367
|
return;
|
|
18301
18368
|
}
|
|
18302
18369
|
const inputObj = normalizeObjectSchema(tool.inputSchema);
|
|
18303
18370
|
const schemaToParse = inputObj ?? tool.inputSchema;
|
|
18304
|
-
const parseResult = await safeParseAsync2(schemaToParse, args);
|
|
18371
|
+
const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
|
|
18305
18372
|
if (!parseResult.success) {
|
|
18306
18373
|
const error = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
18307
18374
|
const errorMessage = getParseErrorMessage(error);
|
|
@@ -18526,7 +18593,7 @@ class McpServer {
|
|
|
18526
18593
|
}
|
|
18527
18594
|
if (prompt.argsSchema) {
|
|
18528
18595
|
const argsObj = normalizeObjectSchema(prompt.argsSchema);
|
|
18529
|
-
const parseResult = await safeParseAsync2(argsObj, request.params.arguments);
|
|
18596
|
+
const parseResult = await safeParseAsync2(argsObj, request.params.arguments ?? {});
|
|
18530
18597
|
if (!parseResult.success) {
|
|
18531
18598
|
const error = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
18532
18599
|
const errorMessage = getParseErrorMessage(error);
|
|
@@ -20070,6 +20137,7 @@ async function recoverIncompleteRuns(registry) {
|
|
|
20070
20137
|
console.error(`[workflows] Failed to resume sub-workflow step ${parentStepId}:`, err);
|
|
20071
20138
|
}
|
|
20072
20139
|
}
|
|
20140
|
+
recovered += await recoverForeachFanouts(registry);
|
|
20073
20141
|
if (recovered > 0) {
|
|
20074
20142
|
console.log(`[workflows] Recovered ${recovered} incomplete run(s)`);
|
|
20075
20143
|
}
|
|
@@ -20163,10 +20231,10 @@ async function recoverWaitingRuns(registry) {
|
|
|
20163
20231
|
if (retry !== "not-eligible")
|
|
20164
20232
|
continue;
|
|
20165
20233
|
}
|
|
20166
|
-
if (!taskCompleted && (workflow.definition.
|
|
20234
|
+
if (!taskCompleted && stepFailureMode(workflow.definition, stuck.nodeId) === "fail") {
|
|
20167
20235
|
const reason = stuck.taskStatus === "failed" ? "Task failed (recovered)" : "Task cancelled (recovered)";
|
|
20168
|
-
const
|
|
20169
|
-
if (!claimed)
|
|
20236
|
+
const failed = await failStepAndRunIfWaiting(workflow.definition, stuck.stepId, stuck.runId, reason, stuck.taskId, { registry });
|
|
20237
|
+
if (!failed.claimed)
|
|
20170
20238
|
continue;
|
|
20171
20239
|
recovered++;
|
|
20172
20240
|
continue;
|
|
@@ -20180,7 +20248,7 @@ async function recoverWaitingRuns(registry) {
|
|
|
20180
20248
|
const step = await getWorkflowRunStep2(stuck.stepId);
|
|
20181
20249
|
if (!step)
|
|
20182
20250
|
continue;
|
|
20183
|
-
const routing = await completeTaskStepAndResolveSuccessors(workflow.definition, stuck.runId, step, stepOutput, ctx, taskCompleted ? undefined : reason, stuck.taskId);
|
|
20251
|
+
const routing = await completeTaskStepAndResolveSuccessors(workflow.definition, stuck.runId, step, stepOutput, ctx, taskCompleted ? undefined : reason, stuck.taskId, registry);
|
|
20184
20252
|
if (!routing.claimed)
|
|
20185
20253
|
continue;
|
|
20186
20254
|
if (routing.foreachChild && !routing.joined) {
|
|
@@ -20235,7 +20303,7 @@ async function recoverApprovalWaitingRuns(registry) {
|
|
|
20235
20303
|
status: approvalStatus,
|
|
20236
20304
|
responses: approval?.responses ?? null
|
|
20237
20305
|
});
|
|
20238
|
-
return await checkpointPortStepAndResolveSuccessors(workflow.definition, stuck.runId, stuck.stepId, stuck.nodeId, stepOutput, nextPort, ctx);
|
|
20306
|
+
return await checkpointPortStepAndResolveSuccessors(workflow.definition, stuck.runId, stuck.stepId, stuck.nodeId, stepOutput, nextPort, ctx, registry);
|
|
20239
20307
|
});
|
|
20240
20308
|
if (!routing?.claimed)
|
|
20241
20309
|
continue;
|
|
@@ -20274,6 +20342,42 @@ async function recoverWaitStates(registry) {
|
|
|
20274
20342
|
}
|
|
20275
20343
|
return recovered;
|
|
20276
20344
|
}
|
|
20345
|
+
async function recoverForeachFanouts(registry) {
|
|
20346
|
+
const rows = await getDbClient2().query(`SELECT s.runId AS runId, r.workflowId AS workflowId, s.id AS stepId, s.nodeId AS nodeId, s.status AS status
|
|
20347
|
+
FROM workflow_run_steps s
|
|
20348
|
+
JOIN workflow_runs r ON r.id = s.runId
|
|
20349
|
+
WHERE r.status IN ('running', 'waiting')
|
|
20350
|
+
AND s.status IN ('pending', 'running')
|
|
20351
|
+
AND instr(s.nodeId, '#') > 1`);
|
|
20352
|
+
const fanouts = new Map;
|
|
20353
|
+
for (const row of rows) {
|
|
20354
|
+
if (row.status === "running" && isForeachChildOwned(row.stepId))
|
|
20355
|
+
continue;
|
|
20356
|
+
const parentNodeId = row.nodeId.slice(0, row.nodeId.indexOf("#"));
|
|
20357
|
+
fanouts.set(`${row.runId}\x00${parentNodeId}`, {
|
|
20358
|
+
runId: row.runId,
|
|
20359
|
+
workflowId: row.workflowId,
|
|
20360
|
+
parentNodeId
|
|
20361
|
+
});
|
|
20362
|
+
}
|
|
20363
|
+
let recovered = 0;
|
|
20364
|
+
for (const fanout of fanouts.values()) {
|
|
20365
|
+
try {
|
|
20366
|
+
const workflow = await getWorkflow2(fanout.workflowId);
|
|
20367
|
+
const parent = workflow?.definition.nodes.find((node) => node.id === fanout.parentNodeId);
|
|
20368
|
+
if (parent?.type !== "foreach")
|
|
20369
|
+
continue;
|
|
20370
|
+
const drive = await runForeachDrive(fanout.runId, fanout.parentNodeId, registry);
|
|
20371
|
+
if (drive.claimed > 0)
|
|
20372
|
+
recovered++;
|
|
20373
|
+
} catch (err) {
|
|
20374
|
+
if (await failRunOnUnreadableReplay(fanout.runId, err))
|
|
20375
|
+
continue;
|
|
20376
|
+
console.error(`[workflows] Failed to re-drive foreach ${fanout.parentNodeId} of run ${fanout.runId}:`, err);
|
|
20377
|
+
}
|
|
20378
|
+
}
|
|
20379
|
+
return recovered;
|
|
20380
|
+
}
|
|
20277
20381
|
async function getRunIdsByStatus(status) {
|
|
20278
20382
|
const rows = await getDbClient2().query("SELECT id FROM workflow_runs WHERE status = ?", [status]);
|
|
20279
20383
|
return rows.map((r) => r.id);
|
|
@@ -20303,17 +20407,16 @@ function startRetryPoller(registry, intervalMs = 5000) {
|
|
|
20303
20407
|
release = holdWorkflowRun(run.id);
|
|
20304
20408
|
if (!await claimRetry(run.id, step.id))
|
|
20305
20409
|
continue;
|
|
20306
|
-
const
|
|
20307
|
-
|
|
20308
|
-
|
|
20309
|
-
|
|
20310
|
-
|
|
20311
|
-
|
|
20410
|
+
const {
|
|
20411
|
+
ctx,
|
|
20412
|
+
inputCtx,
|
|
20413
|
+
config: interpolatedConfig,
|
|
20414
|
+
scriptBodyUnresolved
|
|
20415
|
+
} = await rebuildNodeExecutionInput(workflow.definition, run, node, registry);
|
|
20312
20416
|
if (scriptBodyUnresolved && scriptBodyUnresolved.length > 0) {
|
|
20313
20417
|
await checkpointStepFailure(run.id, step.id, scriptBodyInterpolationError(node.id, scriptBodyUnresolved), step.retryCount);
|
|
20314
20418
|
continue;
|
|
20315
20419
|
}
|
|
20316
|
-
const interpolatedConfig = interpolatedValue;
|
|
20317
20420
|
const executor = registry.get(node.type);
|
|
20318
20421
|
const meta = {
|
|
20319
20422
|
runId: run.id,
|
|
@@ -20333,6 +20436,21 @@ function startRetryPoller(registry, intervalMs = 5000) {
|
|
|
20333
20436
|
if (result.status === "failed") {
|
|
20334
20437
|
const retryPolicy = node.retry || executor.retryPolicy;
|
|
20335
20438
|
await checkpointStepFailure(run.id, step.id, result.error || "Retry failed", step.retryCount, retryPolicy);
|
|
20439
|
+
} else if ("async" in result && result.async && result.waitFor === FOREACH_ITEMS_WAIT_FOR) {
|
|
20440
|
+
const drive = await parkAndDriveForeach({
|
|
20441
|
+
runId: run.id,
|
|
20442
|
+
stepId: step.id,
|
|
20443
|
+
parentNodeId: node.id,
|
|
20444
|
+
ctx,
|
|
20445
|
+
registry
|
|
20446
|
+
});
|
|
20447
|
+
if (!drive.joined)
|
|
20448
|
+
continue;
|
|
20449
|
+
if (drive.successors.length > 0) {
|
|
20450
|
+
await walkGraph(workflow.definition, run.id, ctx, drive.successors, registry, workflow.id);
|
|
20451
|
+
} else {
|
|
20452
|
+
await completeRunIfSettled(run.id, ctx);
|
|
20453
|
+
}
|
|
20336
20454
|
} else if ("async" in result && result.async) {
|
|
20337
20455
|
const waiting = await checkpointStepWaiting(run.id, step.id, ctx);
|
|
20338
20456
|
if (!waiting)
|
|
@@ -20958,154 +21076,6 @@ class CodeMatchExecutor extends BaseExecutor {
|
|
|
20958
21076
|
}
|
|
20959
21077
|
}
|
|
20960
21078
|
|
|
20961
|
-
// src/workflows/executors/foreach.ts
|
|
20962
|
-
init_zod();
|
|
20963
|
-
init_template();
|
|
20964
|
-
var ForeachBodySchema = object2({
|
|
20965
|
-
type: literal2("agent-task"),
|
|
20966
|
-
config: record2(string2(), unknown())
|
|
20967
|
-
});
|
|
20968
|
-
var ForeachConfigSchema = object2({
|
|
20969
|
-
over: array2(record2(string2(), unknown())),
|
|
20970
|
-
itemKey: string2().min(1),
|
|
20971
|
-
body: ForeachBodySchema,
|
|
20972
|
-
concurrency: never().optional()
|
|
20973
|
-
});
|
|
20974
|
-
var ForeachResultSchema = object2({
|
|
20975
|
-
itemKey: string2(),
|
|
20976
|
-
status: _enum2(["completed", "failed", "cancelled", "skipped"]),
|
|
20977
|
-
output: unknown().optional()
|
|
20978
|
-
});
|
|
20979
|
-
var ForeachOutputSchema = object2({
|
|
20980
|
-
results: array2(ForeachResultSchema),
|
|
20981
|
-
okCount: number2().int().nonnegative(),
|
|
20982
|
-
failedCount: number2().int().nonnegative()
|
|
20983
|
-
});
|
|
20984
|
-
|
|
20985
|
-
class ForeachExecutor extends BaseExecutor {
|
|
20986
|
-
type = "foreach";
|
|
20987
|
-
mode = "async";
|
|
20988
|
-
configSchema = ForeachConfigSchema;
|
|
20989
|
-
outputSchema = ForeachOutputSchema;
|
|
20990
|
-
async execute(config, context, meta) {
|
|
20991
|
-
if (config.over.length === 0) {
|
|
20992
|
-
return {
|
|
20993
|
-
status: "success",
|
|
20994
|
-
output: { results: [], okCount: 0, failedCount: 0 }
|
|
20995
|
-
};
|
|
20996
|
-
}
|
|
20997
|
-
const items = config.over.map((item, index) => {
|
|
20998
|
-
const rawItemKey = item[config.itemKey];
|
|
20999
|
-
if (typeof rawItemKey !== "string" || rawItemKey.length === 0) {
|
|
21000
|
-
throw new Error(`foreach item at index ${index} is missing non-empty string itemKey property "${config.itemKey}"`);
|
|
21001
|
-
}
|
|
21002
|
-
return { item, index, itemKey: rawItemKey };
|
|
21003
|
-
});
|
|
21004
|
-
const seenItemKeys = new Set;
|
|
21005
|
-
for (const { itemKey } of items) {
|
|
21006
|
-
if (seenItemKeys.has(itemKey)) {
|
|
21007
|
-
throw new Error(`foreach itemKey "${itemKey}" is duplicated`);
|
|
21008
|
-
}
|
|
21009
|
-
seenItemKeys.add(itemKey);
|
|
21010
|
-
}
|
|
21011
|
-
const agentTaskExecutor = new AgentTaskExecutor(this.deps);
|
|
21012
|
-
const runSteps = await this.deps.db.getWorkflowRunStepsByRunId(meta.runId);
|
|
21013
|
-
const childStepsByNodeId = new Map(runSteps.filter((step) => parseSyntheticNodeId(step.nodeId)?.parentNodeId === meta.nodeId).map((step) => [step.nodeId, step]));
|
|
21014
|
-
const childCountToCreate = items.filter(({ itemKey }) => !childStepsByNodeId.has(`${meta.nodeId}#${itemKey}`)).length;
|
|
21015
|
-
const maxSteps = getMaxWorkflowStepsPerRun();
|
|
21016
|
-
const workflow = await this.deps.db.getWorkflow(meta.workflowId);
|
|
21017
|
-
const hasSuccessors = workflow ? getSuccessors(workflow.definition, meta.nodeId).length > 0 : true;
|
|
21018
|
-
const totalSteps = runSteps.length + childCountToCreate;
|
|
21019
|
-
const capBreached = hasSuccessors ? totalSteps >= maxSteps : totalSteps > maxSteps;
|
|
21020
|
-
if (childCountToCreate > 0 && capBreached) {
|
|
21021
|
-
return {
|
|
21022
|
-
status: "failed",
|
|
21023
|
-
error: `foreach would reach ${maxSteps} total steps (WORKFLOW_MAX_STEPS_PER_RUN): ${runSteps.length} existing + ${childCountToCreate} children${hasSuccessors ? " leaves no room for the post-join walk" : " exceeds the per-run cap"}`
|
|
21024
|
-
};
|
|
21025
|
-
}
|
|
21026
|
-
for (const { index, itemKey } of items) {
|
|
21027
|
-
const childNodeId = `${meta.nodeId}#${itemKey}`;
|
|
21028
|
-
if (childStepsByNodeId.has(childNodeId))
|
|
21029
|
-
continue;
|
|
21030
|
-
const childStepId = crypto.randomUUID();
|
|
21031
|
-
const childStep = await this.deps.db.createWorkflowRunStep({
|
|
21032
|
-
id: childStepId,
|
|
21033
|
-
runId: meta.runId,
|
|
21034
|
-
nodeId: childNodeId,
|
|
21035
|
-
nodeType: "agent-task",
|
|
21036
|
-
input: { itemKey, index }
|
|
21037
|
-
});
|
|
21038
|
-
await this.deps.db.updateWorkflowRunStep(childStepId, {
|
|
21039
|
-
idempotencyKey: `${meta.runId}:${childNodeId}:0`
|
|
21040
|
-
});
|
|
21041
|
-
childStepsByNodeId.set(childNodeId, childStep);
|
|
21042
|
-
}
|
|
21043
|
-
for (const { item, index, itemKey } of items) {
|
|
21044
|
-
const childNodeId = `${meta.nodeId}#${itemKey}`;
|
|
21045
|
-
const childStep = childStepsByNodeId.get(childNodeId);
|
|
21046
|
-
if (FOREACH_TERMINAL_STEP_STATUSES.has(childStep.status))
|
|
21047
|
-
continue;
|
|
21048
|
-
const bodyCtx = { ...meta.inputCtx ?? context, item, index };
|
|
21049
|
-
const childInterpolation = deepInterpolate(config.body.config, bodyCtx);
|
|
21050
|
-
if (childInterpolation.unresolved.length > 0) {
|
|
21051
|
-
console.warn(`[workflow] Step ${childNodeId}: unresolved interpolation tokens: ${childInterpolation.unresolved.join(", ")}`);
|
|
21052
|
-
await this.deps.db.updateWorkflowRunStep(childStep.id, {
|
|
21053
|
-
diagnostics: JSON.stringify({ unresolvedTokens: childInterpolation.unresolved })
|
|
21054
|
-
});
|
|
21055
|
-
}
|
|
21056
|
-
const linkedTask = await this.deps.db.getTaskByWorkflowRunStepId(childStep.id);
|
|
21057
|
-
if (linkedTask?.status === "failed" || linkedTask?.status === "cancelled") {
|
|
21058
|
-
await this.deps.db.detachTaskFromWorkflowRunStep(linkedTask.id);
|
|
21059
|
-
}
|
|
21060
|
-
const childResult = await agentTaskExecutor.run({
|
|
21061
|
-
config: childInterpolation.value,
|
|
21062
|
-
context,
|
|
21063
|
-
meta: {
|
|
21064
|
-
...meta,
|
|
21065
|
-
stepId: childStep.id,
|
|
21066
|
-
nodeId: childNodeId
|
|
21067
|
-
}
|
|
21068
|
-
});
|
|
21069
|
-
if (childResult.status !== "success") {
|
|
21070
|
-
throw new Error(childResult.error ?? `foreach child "${itemKey}" failed to start`);
|
|
21071
|
-
}
|
|
21072
|
-
if ("async" in childResult) {
|
|
21073
|
-
await this.deps.db.updateWorkflowRunStep(childStep.id, { status: "waiting" });
|
|
21074
|
-
} else {
|
|
21075
|
-
await this.deps.db.updateWorkflowRunStep(childStep.id, {
|
|
21076
|
-
status: "completed",
|
|
21077
|
-
output: normalizeExistingTaskOutput(childResult.output),
|
|
21078
|
-
finishedAt: new Date().toISOString()
|
|
21079
|
-
});
|
|
21080
|
-
}
|
|
21081
|
-
}
|
|
21082
|
-
const childSteps = (await this.deps.db.getWorkflowRunStepsByRunId(meta.runId)).filter((step) => parseSyntheticNodeId(step.nodeId)?.parentNodeId === meta.nodeId);
|
|
21083
|
-
if (childSteps.every((step) => FOREACH_TERMINAL_STEP_STATUSES.has(step.status))) {
|
|
21084
|
-
return { status: "success", output: buildForeachAggregate(childSteps) };
|
|
21085
|
-
}
|
|
21086
|
-
return {
|
|
21087
|
-
status: "success",
|
|
21088
|
-
async: true,
|
|
21089
|
-
waitFor: "task.completed",
|
|
21090
|
-
correlationId: meta.stepId
|
|
21091
|
-
};
|
|
21092
|
-
}
|
|
21093
|
-
}
|
|
21094
|
-
function normalizeExistingTaskOutput(output) {
|
|
21095
|
-
if (typeof output !== "object" || output === null)
|
|
21096
|
-
return output;
|
|
21097
|
-
const record = output;
|
|
21098
|
-
if (typeof record.taskOutput !== "string")
|
|
21099
|
-
return output;
|
|
21100
|
-
try {
|
|
21101
|
-
const parsed = JSON.parse(record.taskOutput);
|
|
21102
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
21103
|
-
return { ...record, taskOutput: parsed };
|
|
21104
|
-
}
|
|
21105
|
-
} catch {}
|
|
21106
|
-
return output;
|
|
21107
|
-
}
|
|
21108
|
-
|
|
21109
21079
|
// src/workflows/executors/notify.ts
|
|
21110
21080
|
init_zod();
|
|
21111
21081
|
init_secret_scrubber();
|
|
@@ -21149,7 +21119,7 @@ class NotifyExecutor extends BaseExecutor {
|
|
|
21149
21119
|
}
|
|
21150
21120
|
}
|
|
21151
21121
|
case "slack": {
|
|
21152
|
-
const { getSlackApp } = await import("./app-
|
|
21122
|
+
const { getSlackApp } = await import("./app-0qp0a2gk.js");
|
|
21153
21123
|
const app = getSlackApp();
|
|
21154
21124
|
if (!app) {
|
|
21155
21125
|
return {
|
|
@@ -24512,7 +24482,7 @@ function setPreloadedTools(server, names) {
|
|
|
24512
24482
|
async function applyPreToolCall(name, args, requestInfo, inputSchema) {
|
|
24513
24483
|
if (requestInfo.callOrigin !== "mcp")
|
|
24514
24484
|
return { args };
|
|
24515
|
-
const dispatcher = await import("./dispatcher-
|
|
24485
|
+
const dispatcher = await import("./dispatcher-64bdyhps.js");
|
|
24516
24486
|
const result = await dispatcher.dispatchPre("pre.tool.call", { tool: name, args, requestInfo }, inputSchema ? {
|
|
24517
24487
|
validateModify: async (data) => {
|
|
24518
24488
|
const schema = normalizeObjectSchema(inputSchema) ?? inputSchema;
|
|
@@ -25722,7 +25692,8 @@ var onChatMessageSent = chatMessageBridge("chat.message.sent", "outbound");
|
|
|
25722
25692
|
var VCS_PROVIDERS = new Set([
|
|
25723
25693
|
"github",
|
|
25724
25694
|
"gitlab",
|
|
25725
|
-
"azure-devops"
|
|
25695
|
+
"azure-devops",
|
|
25696
|
+
"bitbucket"
|
|
25726
25697
|
]);
|
|
25727
25698
|
var VCS_KINDS = new Set([
|
|
25728
25699
|
"pull_request",
|
|
@@ -28013,7 +27984,7 @@ async function handlePullRequestCommented(event) {
|
|
|
28013
27984
|
return { created: false };
|
|
28014
27985
|
}
|
|
28015
27986
|
const requestedByUserId = await resolveAzureDevOpsSender(comment.author, "pull_request_comment", comment.content);
|
|
28016
|
-
const existingTask = await findTaskByVcs2(repo, pr.pullRequestId);
|
|
27987
|
+
const existingTask = await findTaskByVcs2(repo, pr.pullRequestId, "azure-devops");
|
|
28017
27988
|
const existingTaskNote = existingTask ? `
|
|
28018
27989
|
|
|
28019
27990
|
_Note: There's an active task (${existingTask.id}) for this PR #${pr.pullRequestId}._` : "";
|
|
@@ -29127,6 +29098,456 @@ async function syncTelemetryEnabled(via) {
|
|
|
29127
29098
|
track({ event: "telemetry.enabled", properties: { via } });
|
|
29128
29099
|
return true;
|
|
29129
29100
|
}
|
|
29101
|
+
|
|
29102
|
+
// src/bitbucket/api.ts
|
|
29103
|
+
init_secret_scrubber();
|
|
29104
|
+
|
|
29105
|
+
// src/bitbucket/auth.ts
|
|
29106
|
+
init_env_flag();
|
|
29107
|
+
var initialized4 = false;
|
|
29108
|
+
var webhookSecret4 = null;
|
|
29109
|
+
var apiToken2 = null;
|
|
29110
|
+
function isBitbucketEnabled() {
|
|
29111
|
+
return !!process.env.BITBUCKET_WEBHOOK_SECRET && !isEnvFlagEnabled("BITBUCKET_DISABLE", false);
|
|
29112
|
+
}
|
|
29113
|
+
function initBitbucket() {
|
|
29114
|
+
if (initialized4)
|
|
29115
|
+
return;
|
|
29116
|
+
if (!isBitbucketEnabled()) {
|
|
29117
|
+
console.log("[Bitbucket] Integration disabled (BITBUCKET_WEBHOOK_SECRET not set)");
|
|
29118
|
+
return;
|
|
29119
|
+
}
|
|
29120
|
+
webhookSecret4 = process.env.BITBUCKET_WEBHOOK_SECRET;
|
|
29121
|
+
apiToken2 = process.env.BITBUCKET_TOKEN ?? null;
|
|
29122
|
+
initialized4 = true;
|
|
29123
|
+
console.log(`[Bitbucket] Integration initialized (API token: ${apiToken2 ? "set" : "not set"})`);
|
|
29124
|
+
}
|
|
29125
|
+
function verifyBitbucketWebhook(rawBody, signatureHeader) {
|
|
29126
|
+
if (!webhookSecret4)
|
|
29127
|
+
return false;
|
|
29128
|
+
if (!signatureHeader?.startsWith("sha256="))
|
|
29129
|
+
return false;
|
|
29130
|
+
return verifyHmacSignature(webhookSecret4, rawBody, signatureHeader);
|
|
29131
|
+
}
|
|
29132
|
+
function getBitbucketToken() {
|
|
29133
|
+
return apiToken2;
|
|
29134
|
+
}
|
|
29135
|
+
function getBitbucketBotName() {
|
|
29136
|
+
return process.env.BITBUCKET_BOT_NAME || "agent-swarm-bot";
|
|
29137
|
+
}
|
|
29138
|
+
function resetBitbucket() {
|
|
29139
|
+
initialized4 = false;
|
|
29140
|
+
webhookSecret4 = null;
|
|
29141
|
+
apiToken2 = null;
|
|
29142
|
+
}
|
|
29143
|
+
|
|
29144
|
+
// src/bitbucket/api.ts
|
|
29145
|
+
var BITBUCKET_API = "https://api.bitbucket.org/2.0";
|
|
29146
|
+
function headers3() {
|
|
29147
|
+
const token = getBitbucketToken();
|
|
29148
|
+
if (!token)
|
|
29149
|
+
throw new Error("[Bitbucket] No API token configured");
|
|
29150
|
+
return {
|
|
29151
|
+
Authorization: `Bearer ${token}`,
|
|
29152
|
+
"Content-Type": "application/json",
|
|
29153
|
+
Accept: "application/json"
|
|
29154
|
+
};
|
|
29155
|
+
}
|
|
29156
|
+
var cachedBotAccountId = null;
|
|
29157
|
+
async function resolveBitbucketBotAccountId() {
|
|
29158
|
+
const fromEnv = process.env.BITBUCKET_BOT_ACCOUNT_ID?.trim();
|
|
29159
|
+
if (fromEnv)
|
|
29160
|
+
return fromEnv;
|
|
29161
|
+
if (cachedBotAccountId)
|
|
29162
|
+
return cachedBotAccountId;
|
|
29163
|
+
if (!getBitbucketToken())
|
|
29164
|
+
return null;
|
|
29165
|
+
try {
|
|
29166
|
+
const resp = await fetch(`${BITBUCKET_API}/user`, { headers: headers3(), redirect: "error" });
|
|
29167
|
+
if (!resp.ok) {
|
|
29168
|
+
console.error(`[Bitbucket] GET /user returned ${resp.status}`);
|
|
29169
|
+
return null;
|
|
29170
|
+
}
|
|
29171
|
+
const data = await resp.json();
|
|
29172
|
+
cachedBotAccountId = data.account_id?.trim() || null;
|
|
29173
|
+
return cachedBotAccountId;
|
|
29174
|
+
} catch (err) {
|
|
29175
|
+
console.error(`[Bitbucket] Failed to resolve bot identity: ${scrubSecrets(String(err))}`);
|
|
29176
|
+
return null;
|
|
29177
|
+
}
|
|
29178
|
+
}
|
|
29179
|
+
function resetBitbucketBotCache() {
|
|
29180
|
+
cachedBotAccountId = null;
|
|
29181
|
+
}
|
|
29182
|
+
// src/bitbucket/handlers.ts
|
|
29183
|
+
init_db3();
|
|
29184
|
+
init_users();
|
|
29185
|
+
init_resolver();
|
|
29186
|
+
init_context_key();
|
|
29187
|
+
|
|
29188
|
+
// src/bitbucket/templates.ts
|
|
29189
|
+
init_registry();
|
|
29190
|
+
registerTemplate({
|
|
29191
|
+
eventType: "common.delegation_instruction.bitbucket",
|
|
29192
|
+
header: "",
|
|
29193
|
+
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.",
|
|
29194
|
+
variables: [],
|
|
29195
|
+
category: "common"
|
|
29196
|
+
});
|
|
29197
|
+
registerTemplate({
|
|
29198
|
+
eventType: "common.command_suggestions.bitbucket_pr",
|
|
29199
|
+
header: "",
|
|
29200
|
+
defaultBody: 'Workers have `git` authenticated for bitbucket.org and `BITBUCKET_TOKEN` in env; there is no Bitbucket CLI, so use curl against `https://api.bitbucket.org/2.0/repositories/{{repo}}` with `-H "Authorization: Bearer $BITBUCKET_TOKEN"`. Inspect the PR with `GET .../pullrequests/{{pr_id}}` and its diff with `GET .../pullrequests/{{pr_id}}/diff`. Reply with `POST .../pullrequests/{{pr_id}}/comments` and JSON body `{"content":{"raw":"<reply>"}}`. Find a PR by branch with `GET .../pullrequests?q=source.branch.name="<branch>"`. Open a PR with `POST .../pullrequests` and JSON body `{"title":"<title>","source":{"branch":{"name":"<branch>"}},"destination":{"branch":{"name":"<base>"}}}`.',
|
|
29201
|
+
variables: [
|
|
29202
|
+
{ name: "repo", description: "Repository full name (<workspace>/<repo_slug>)" },
|
|
29203
|
+
{ name: "pr_id", description: "Pull request ID" }
|
|
29204
|
+
],
|
|
29205
|
+
category: "common"
|
|
29206
|
+
});
|
|
29207
|
+
var SHARED_VARIABLES2 = [
|
|
29208
|
+
{ name: "pr_id", description: "Pull request ID" },
|
|
29209
|
+
{ name: "pr_title", description: "Pull request title" },
|
|
29210
|
+
{ name: "repo", description: "Repository full name (<workspace>/<repo_slug>)" },
|
|
29211
|
+
{ name: "pr_url", description: "Pull request web URL" }
|
|
29212
|
+
];
|
|
29213
|
+
var PR_BRANCH_VARIABLES = [
|
|
29214
|
+
{ name: "source_branch", description: "Source branch name" },
|
|
29215
|
+
{ name: "target_branch", description: "Target branch name" },
|
|
29216
|
+
{ name: "context_section", description: "Context section with description or empty string" }
|
|
29217
|
+
];
|
|
29218
|
+
registerTemplate({
|
|
29219
|
+
eventType: "bitbucket.pull_request.opened",
|
|
29220
|
+
header: "[Bitbucket PR #{{pr_id}}] {{pr_title}}",
|
|
29221
|
+
defaultBody: `Repo: {{repo}}
|
|
29222
|
+
Author: {{username}}
|
|
29223
|
+
Branch: {{source_branch}} → {{target_branch}}
|
|
29224
|
+
URL: {{pr_url}}
|
|
29225
|
+
|
|
29226
|
+
{{context_section}}{{@template[common.command_suggestions.bitbucket_pr]}}{{@template[common.delegation_instruction.bitbucket]}}`,
|
|
29227
|
+
variables: [
|
|
29228
|
+
...SHARED_VARIABLES2,
|
|
29229
|
+
{
|
|
29230
|
+
name: "username",
|
|
29231
|
+
description: "Author identity — resolved canonical name (e.g. 'Luis (bitbucket:557058:…)') or the UNKNOWN sentinel"
|
|
29232
|
+
},
|
|
29233
|
+
...PR_BRANCH_VARIABLES
|
|
29234
|
+
],
|
|
29235
|
+
category: "event"
|
|
29236
|
+
});
|
|
29237
|
+
registerTemplate({
|
|
29238
|
+
eventType: "bitbucket.pull_request.review_requested",
|
|
29239
|
+
header: "[Bitbucket PR #{{pr_id}}] Review requested: {{pr_title}}",
|
|
29240
|
+
defaultBody: `Repo: {{repo}}
|
|
29241
|
+
Author: {{username}}
|
|
29242
|
+
Branch: {{source_branch}} → {{target_branch}}
|
|
29243
|
+
URL: {{pr_url}}
|
|
29244
|
+
|
|
29245
|
+
You were added as a reviewer on this pull request.
|
|
29246
|
+
|
|
29247
|
+
{{context_section}}{{@template[common.command_suggestions.bitbucket_pr]}}{{@template[common.delegation_instruction.bitbucket]}}`,
|
|
29248
|
+
variables: [
|
|
29249
|
+
...SHARED_VARIABLES2,
|
|
29250
|
+
{
|
|
29251
|
+
name: "username",
|
|
29252
|
+
description: "Author identity — resolved canonical name (e.g. 'Luis (bitbucket:557058:…)') or the UNKNOWN sentinel"
|
|
29253
|
+
},
|
|
29254
|
+
...PR_BRANCH_VARIABLES
|
|
29255
|
+
],
|
|
29256
|
+
category: "event"
|
|
29257
|
+
});
|
|
29258
|
+
registerTemplate({
|
|
29259
|
+
eventType: "bitbucket.comment.mentioned",
|
|
29260
|
+
header: "[Bitbucket Comment on PR #{{pr_id}}] {{username}} mentioned bot",
|
|
29261
|
+
defaultBody: `Repo: {{repo}}
|
|
29262
|
+
PR: {{pr_title}}
|
|
29263
|
+
URL: {{pr_url}}
|
|
29264
|
+
{{location_section}}
|
|
29265
|
+
Comment:
|
|
29266
|
+
{{context}}{{existing_task_note}}
|
|
29267
|
+
|
|
29268
|
+
{{@template[common.command_suggestions.bitbucket_pr]}}{{@template[common.delegation_instruction.bitbucket]}}`,
|
|
29269
|
+
variables: [
|
|
29270
|
+
...SHARED_VARIABLES2,
|
|
29271
|
+
{
|
|
29272
|
+
name: "username",
|
|
29273
|
+
description: "Comment author identity — resolved canonical name (e.g. 'Luis (bitbucket:557058:…)') or the UNKNOWN sentinel"
|
|
29274
|
+
},
|
|
29275
|
+
{
|
|
29276
|
+
name: "location_section",
|
|
29277
|
+
description: "`File: <path>:<line>` line for inline comments, or empty string"
|
|
29278
|
+
},
|
|
29279
|
+
{ name: "context", description: "Extracted mention context from comment" },
|
|
29280
|
+
{
|
|
29281
|
+
name: "existing_task_note",
|
|
29282
|
+
description: "Note about existing active task, or empty string"
|
|
29283
|
+
}
|
|
29284
|
+
],
|
|
29285
|
+
category: "event"
|
|
29286
|
+
});
|
|
29287
|
+
|
|
29288
|
+
// src/bitbucket/handlers.ts
|
|
29289
|
+
var DEDUP_TTL_MS2 = 60000;
|
|
29290
|
+
var processedEvents3 = new Map;
|
|
29291
|
+
var processedDeliveries = new Map;
|
|
29292
|
+
function sweep(cache, now) {
|
|
29293
|
+
for (const [k, ts] of cache) {
|
|
29294
|
+
if (now - ts > DEDUP_TTL_MS2)
|
|
29295
|
+
cache.delete(k);
|
|
29296
|
+
}
|
|
29297
|
+
}
|
|
29298
|
+
function isDuplicate3(key) {
|
|
29299
|
+
const now = Date.now();
|
|
29300
|
+
sweep(processedEvents3, now);
|
|
29301
|
+
if (processedEvents3.has(key))
|
|
29302
|
+
return true;
|
|
29303
|
+
processedEvents3.set(key, now);
|
|
29304
|
+
return false;
|
|
29305
|
+
}
|
|
29306
|
+
async function withDedupReservation(key, fn) {
|
|
29307
|
+
if (isDuplicate3(key))
|
|
29308
|
+
return null;
|
|
29309
|
+
try {
|
|
29310
|
+
return await fn();
|
|
29311
|
+
} catch (err) {
|
|
29312
|
+
processedEvents3.delete(key);
|
|
29313
|
+
throw err;
|
|
29314
|
+
}
|
|
29315
|
+
}
|
|
29316
|
+
function isDuplicateDelivery(requestUuid) {
|
|
29317
|
+
if (!requestUuid)
|
|
29318
|
+
return false;
|
|
29319
|
+
sweep(processedDeliveries, Date.now());
|
|
29320
|
+
return processedDeliveries.has(requestUuid);
|
|
29321
|
+
}
|
|
29322
|
+
function markDeliveryProcessed(requestUuid) {
|
|
29323
|
+
if (requestUuid)
|
|
29324
|
+
processedDeliveries.set(requestUuid, Date.now());
|
|
29325
|
+
}
|
|
29326
|
+
function escapeRegExp2(value) {
|
|
29327
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29328
|
+
}
|
|
29329
|
+
function mentionPatterns2(botAccountId) {
|
|
29330
|
+
const patterns = [new RegExp(`@${escapeRegExp2(getBitbucketBotName())}(?![\\w-])`, "gi")];
|
|
29331
|
+
if (botAccountId)
|
|
29332
|
+
patterns.push(new RegExp(`@\\{${escapeRegExp2(botAccountId)}\\}`, "gi"));
|
|
29333
|
+
return patterns;
|
|
29334
|
+
}
|
|
29335
|
+
function detectMention2(text, botAccountId) {
|
|
29336
|
+
if (!text)
|
|
29337
|
+
return false;
|
|
29338
|
+
return mentionPatterns2(botAccountId).some((re) => {
|
|
29339
|
+
re.lastIndex = 0;
|
|
29340
|
+
return re.test(text);
|
|
29341
|
+
});
|
|
29342
|
+
}
|
|
29343
|
+
function extractMentionContext2(text, botAccountId) {
|
|
29344
|
+
return mentionPatterns2(botAccountId).reduce((acc, re) => acc.replace(re, ""), text).trim();
|
|
29345
|
+
}
|
|
29346
|
+
function isBot2(account, botAccountId) {
|
|
29347
|
+
return !!botAccountId && account?.account_id === botAccountId;
|
|
29348
|
+
}
|
|
29349
|
+
function pullRequestWebUrl2(repo, pr) {
|
|
29350
|
+
return pr.links?.html?.href ?? `https://bitbucket.org/${repo}/pull-requests/${pr.id}`;
|
|
29351
|
+
}
|
|
29352
|
+
function contextKeyOf(event) {
|
|
29353
|
+
return bitbucketContextKey({
|
|
29354
|
+
repoUuid: event.repository.uuid,
|
|
29355
|
+
pullRequestId: event.pullrequest.id
|
|
29356
|
+
});
|
|
29357
|
+
}
|
|
29358
|
+
function pullRequestEventOf(body) {
|
|
29359
|
+
const event = body;
|
|
29360
|
+
const pr = event?.pullrequest;
|
|
29361
|
+
const repo = event?.repository;
|
|
29362
|
+
if (typeof pr?.id !== "number" || typeof pr.title !== "string" || typeof repo?.uuid !== "string" || typeof repo.full_name !== "string" || !event?.actor) {
|
|
29363
|
+
return null;
|
|
29364
|
+
}
|
|
29365
|
+
return event;
|
|
29366
|
+
}
|
|
29367
|
+
function pullRequestCommentEventOf(body) {
|
|
29368
|
+
const event = pullRequestEventOf(body);
|
|
29369
|
+
const comment = event?.comment;
|
|
29370
|
+
if (!event || typeof comment?.id !== "number" || typeof comment.content?.raw !== "string") {
|
|
29371
|
+
return null;
|
|
29372
|
+
}
|
|
29373
|
+
return event;
|
|
29374
|
+
}
|
|
29375
|
+
function warnMalformed2(eventKey) {
|
|
29376
|
+
console.warn(`[Bitbucket] Ignoring ${eventKey} event: required payload fields are missing`);
|
|
29377
|
+
}
|
|
29378
|
+
async function findLeadAgent3() {
|
|
29379
|
+
const agents = await getAllAgents2();
|
|
29380
|
+
return agents.find((a) => a.role === "lead" && a.status === "idle") ?? agents.find((a) => a.role === "lead") ?? null;
|
|
29381
|
+
}
|
|
29382
|
+
var UNMAPPED_NAMESPACE2 = "integration:unmapped:bitbucket";
|
|
29383
|
+
var UNMAPPED_TTL_MS2 = 30 * 24 * 60 * 60 * 1000;
|
|
29384
|
+
function externalIdOf2(account) {
|
|
29385
|
+
return account?.account_id?.trim() || account?.uuid?.trim() || null;
|
|
29386
|
+
}
|
|
29387
|
+
async function resolveBitbucketSender(account, sampleEventType, sampleContext) {
|
|
29388
|
+
const externalId = externalIdOf2(account);
|
|
29389
|
+
if (!externalId)
|
|
29390
|
+
return;
|
|
29391
|
+
const existing = await findUserByExternalId("bitbucket", externalId);
|
|
29392
|
+
if (existing)
|
|
29393
|
+
return existing.id;
|
|
29394
|
+
await upsertKv2({
|
|
29395
|
+
namespace: UNMAPPED_NAMESPACE2,
|
|
29396
|
+
key: `${externalId}:meta`,
|
|
29397
|
+
value: {
|
|
29398
|
+
lastSeenAt: new Date().toISOString(),
|
|
29399
|
+
displayName: account?.display_name,
|
|
29400
|
+
sampleEventType,
|
|
29401
|
+
sampleContext: sampleContext.slice(0, 100)
|
|
29402
|
+
},
|
|
29403
|
+
valueType: "json",
|
|
29404
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS2
|
|
29405
|
+
});
|
|
29406
|
+
await incrKv2(UNMAPPED_NAMESPACE2, `${externalId}:count`, 1);
|
|
29407
|
+
return;
|
|
29408
|
+
}
|
|
29409
|
+
async function renderBitbucketIdentity(account) {
|
|
29410
|
+
return renderIdentity(await resolveIdentity("bitbucket", externalIdOf2(account) ?? ""));
|
|
29411
|
+
}
|
|
29412
|
+
async function createBitbucketTask(text, event, fields) {
|
|
29413
|
+
const { pullrequest: pr, repository } = event;
|
|
29414
|
+
const lead = await findLeadAgent3();
|
|
29415
|
+
const task = await createTaskWithSiblingAwareness(text, {
|
|
29416
|
+
agentId: lead?.id ?? null,
|
|
29417
|
+
routingReason: lead ? "skill" : undefined,
|
|
29418
|
+
routingSource: lead ? "engine_default" : undefined,
|
|
29419
|
+
source: "bitbucket",
|
|
29420
|
+
vcsProvider: "bitbucket",
|
|
29421
|
+
taskType: fields.taskType,
|
|
29422
|
+
vcsRepo: repository.full_name,
|
|
29423
|
+
vcsEventType: fields.vcsEventType,
|
|
29424
|
+
vcsNumber: pr.id,
|
|
29425
|
+
vcsCommentId: fields.vcsCommentId,
|
|
29426
|
+
vcsAuthor: externalIdOf2(fields.author) ?? undefined,
|
|
29427
|
+
requestedByUserId: fields.requestedByUserId,
|
|
29428
|
+
vcsUrl: pullRequestWebUrl2(repository.full_name, pr),
|
|
29429
|
+
parentTaskId: fields.parentTaskId,
|
|
29430
|
+
contextKey: contextKeyOf(event)
|
|
29431
|
+
}, { origin: "webhook" });
|
|
29432
|
+
return { created: true, taskId: task.id };
|
|
29433
|
+
}
|
|
29434
|
+
async function handlePullRequestCreated2(body) {
|
|
29435
|
+
const event = pullRequestEventOf(body);
|
|
29436
|
+
if (!event) {
|
|
29437
|
+
warnMalformed2("pullrequest:created");
|
|
29438
|
+
return { created: false };
|
|
29439
|
+
}
|
|
29440
|
+
const { pullrequest: pr, repository } = event;
|
|
29441
|
+
const repo = repository.full_name;
|
|
29442
|
+
const author = pr.author ?? event.actor;
|
|
29443
|
+
console.log(`[Bitbucket] PR #${pr.id} created by ${author.display_name} in ${repo}`);
|
|
29444
|
+
const botAccountId = await resolveBitbucketBotAccountId();
|
|
29445
|
+
if (isBot2(author, botAccountId)) {
|
|
29446
|
+
console.log(`[Bitbucket] PR opened by the bot itself, skipping`);
|
|
29447
|
+
return { created: false };
|
|
29448
|
+
}
|
|
29449
|
+
const mentioned = detectMention2(pr.description, botAccountId);
|
|
29450
|
+
const reviewRequested = !!botAccountId && (pr.reviewers ?? []).some((r) => r.account_id === botAccountId);
|
|
29451
|
+
if (!mentioned && !reviewRequested) {
|
|
29452
|
+
console.log(`[Bitbucket] PR opened without bot mention or review request, skipping`);
|
|
29453
|
+
return { created: false };
|
|
29454
|
+
}
|
|
29455
|
+
const dedupKey = `bitbucket-pr-${repository.uuid}-${pr.id}-created`;
|
|
29456
|
+
const outcome = await withDedupReservation(dedupKey, async () => {
|
|
29457
|
+
const requestedByUserId = await resolveBitbucketSender(author, "pull_request", `PR #${pr.id}: ${pr.title}`);
|
|
29458
|
+
const context = pr.description ? extractMentionContext2(pr.description, botAccountId) : "";
|
|
29459
|
+
const templateId = mentioned ? "bitbucket.pull_request.opened" : "bitbucket.pull_request.review_requested";
|
|
29460
|
+
const result = resolveTemplate(templateId, {
|
|
29461
|
+
pr_id: pr.id,
|
|
29462
|
+
pr_title: pr.title,
|
|
29463
|
+
repo,
|
|
29464
|
+
username: await renderBitbucketIdentity(author),
|
|
29465
|
+
source_branch: pr.source?.branch?.name ?? "",
|
|
29466
|
+
target_branch: pr.destination?.branch?.name ?? "",
|
|
29467
|
+
pr_url: pullRequestWebUrl2(repo, pr),
|
|
29468
|
+
context_section: context ? `Context: ${context}
|
|
29469
|
+
|
|
29470
|
+
` : ""
|
|
29471
|
+
});
|
|
29472
|
+
if (result.skipped) {
|
|
29473
|
+
return { created: false };
|
|
29474
|
+
}
|
|
29475
|
+
return createBitbucketTask(result.text, event, {
|
|
29476
|
+
taskType: "bitbucket-pr",
|
|
29477
|
+
vcsEventType: "pull_request",
|
|
29478
|
+
author,
|
|
29479
|
+
requestedByUserId
|
|
29480
|
+
});
|
|
29481
|
+
});
|
|
29482
|
+
if (!outcome)
|
|
29483
|
+
console.log(`[Bitbucket] Skipping duplicate PR event`);
|
|
29484
|
+
return outcome ?? { created: false };
|
|
29485
|
+
}
|
|
29486
|
+
async function handlePullRequestCommentCreated(body) {
|
|
29487
|
+
const event = pullRequestCommentEventOf(body);
|
|
29488
|
+
if (!event) {
|
|
29489
|
+
warnMalformed2("pullrequest:comment_created");
|
|
29490
|
+
return { created: false };
|
|
29491
|
+
}
|
|
29492
|
+
const { pullrequest: pr, repository, comment } = event;
|
|
29493
|
+
const repo = repository.full_name;
|
|
29494
|
+
const author = comment.user ?? event.actor;
|
|
29495
|
+
const botAccountId = await resolveBitbucketBotAccountId();
|
|
29496
|
+
if (isBot2(author, botAccountId)) {
|
|
29497
|
+
return { created: false };
|
|
29498
|
+
}
|
|
29499
|
+
if (!detectMention2(comment.content.raw, botAccountId)) {
|
|
29500
|
+
return { created: false };
|
|
29501
|
+
}
|
|
29502
|
+
console.log(`[Bitbucket] Comment by ${author.display_name} on PR #${pr.id} in ${repo}`);
|
|
29503
|
+
const dedupKey = `bitbucket-comment-${repository.uuid}-${pr.id}-${comment.id}`;
|
|
29504
|
+
const outcome = await withDedupReservation(dedupKey, async () => {
|
|
29505
|
+
const requestedByUserId = await resolveBitbucketSender(author, "pull_request_comment", comment.content.raw);
|
|
29506
|
+
const existingTask = await findTaskByVcs2(repo, pr.id, "bitbucket");
|
|
29507
|
+
const existingTaskNote = existingTask ? `
|
|
29508
|
+
|
|
29509
|
+
_Note: There's an active task (${existingTask.id}) for this PR #${pr.id}._` : "";
|
|
29510
|
+
const line = comment.inline?.to ?? comment.inline?.from;
|
|
29511
|
+
const locationSection = comment.inline ? `File: ${comment.inline.path}${line != null ? `:${line}` : ""}
|
|
29512
|
+
` : "";
|
|
29513
|
+
const result = resolveTemplate("bitbucket.comment.mentioned", {
|
|
29514
|
+
pr_id: pr.id,
|
|
29515
|
+
pr_title: pr.title,
|
|
29516
|
+
username: await renderBitbucketIdentity(author),
|
|
29517
|
+
repo,
|
|
29518
|
+
pr_url: comment.links?.html?.href ?? pullRequestWebUrl2(repo, pr),
|
|
29519
|
+
location_section: locationSection,
|
|
29520
|
+
context: extractMentionContext2(comment.content.raw, botAccountId),
|
|
29521
|
+
existing_task_note: existingTaskNote
|
|
29522
|
+
});
|
|
29523
|
+
if (result.skipped) {
|
|
29524
|
+
return { created: false };
|
|
29525
|
+
}
|
|
29526
|
+
return createBitbucketTask(result.text, event, {
|
|
29527
|
+
taskType: "bitbucket-comment",
|
|
29528
|
+
vcsEventType: "pull_request_comment",
|
|
29529
|
+
author,
|
|
29530
|
+
requestedByUserId,
|
|
29531
|
+
vcsCommentId: comment.id,
|
|
29532
|
+
parentTaskId: existingTask?.id
|
|
29533
|
+
});
|
|
29534
|
+
});
|
|
29535
|
+
return outcome ?? { created: false };
|
|
29536
|
+
}
|
|
29537
|
+
async function handlePullRequestClosed(body, outcome) {
|
|
29538
|
+
const event = pullRequestEventOf(body);
|
|
29539
|
+
if (!event) {
|
|
29540
|
+
warnMalformed2(outcome === "merged" ? "pullrequest:fulfilled" : "pullrequest:rejected");
|
|
29541
|
+
return { created: false };
|
|
29542
|
+
}
|
|
29543
|
+
const { pullrequest: pr, repository } = event;
|
|
29544
|
+
const reason = outcome === "merged" ? "PR was merged" : "PR was declined";
|
|
29545
|
+
for (const task of await findActiveTasksByVcs2(repository.full_name, pr.id, "bitbucket")) {
|
|
29546
|
+
console.log(`[Bitbucket] Cancelling task ${task.id} — ${reason}`);
|
|
29547
|
+
await failTask2(task.id, reason);
|
|
29548
|
+
}
|
|
29549
|
+
return { created: false };
|
|
29550
|
+
}
|
|
29130
29551
|
// src/github/handlers.ts
|
|
29131
29552
|
init_db3();
|
|
29132
29553
|
init_users();
|
|
@@ -29151,12 +29572,12 @@ function computeMentionPattern(names) {
|
|
|
29151
29572
|
}
|
|
29152
29573
|
var BOT_NAMES = computeBotNames();
|
|
29153
29574
|
var MENTION_PATTERN = computeMentionPattern(BOT_NAMES);
|
|
29154
|
-
function
|
|
29575
|
+
function detectMention3(text) {
|
|
29155
29576
|
if (!text)
|
|
29156
29577
|
return false;
|
|
29157
29578
|
return MENTION_PATTERN.test(text);
|
|
29158
29579
|
}
|
|
29159
|
-
function
|
|
29580
|
+
function extractMentionContext3(text) {
|
|
29160
29581
|
if (!text)
|
|
29161
29582
|
return "";
|
|
29162
29583
|
return text.replace(MENTION_PATTERN, "").trim();
|
|
@@ -29599,7 +30020,7 @@ Related task: {{related_task_id}}
|
|
|
29599
30020
|
});
|
|
29600
30021
|
|
|
29601
30022
|
// src/github/handlers.ts
|
|
29602
|
-
var
|
|
30023
|
+
var processedEvents4 = new Map;
|
|
29603
30024
|
var EVENT_TTL2 = 60000;
|
|
29604
30025
|
function buildGithubContextKey(fullName, kind, number) {
|
|
29605
30026
|
const [owner, repo] = fullName.split("/");
|
|
@@ -29643,34 +30064,34 @@ function getCommandSuggestions(taskType, targetType) {
|
|
|
29643
30064
|
return "";
|
|
29644
30065
|
}
|
|
29645
30066
|
}
|
|
29646
|
-
function
|
|
30067
|
+
function isDuplicate4(eventKey) {
|
|
29647
30068
|
const now = Date.now();
|
|
29648
|
-
for (const [key, timestamp] of
|
|
30069
|
+
for (const [key, timestamp] of processedEvents4) {
|
|
29649
30070
|
if (now - timestamp > EVENT_TTL2) {
|
|
29650
|
-
|
|
30071
|
+
processedEvents4.delete(key);
|
|
29651
30072
|
}
|
|
29652
30073
|
}
|
|
29653
|
-
if (
|
|
30074
|
+
if (processedEvents4.has(eventKey)) {
|
|
29654
30075
|
return true;
|
|
29655
30076
|
}
|
|
29656
|
-
|
|
30077
|
+
processedEvents4.set(eventKey, now);
|
|
29657
30078
|
return false;
|
|
29658
30079
|
}
|
|
29659
|
-
async function
|
|
30080
|
+
async function findLeadAgent4() {
|
|
29660
30081
|
const agents = await getAllAgents2();
|
|
29661
30082
|
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
29662
30083
|
if (onlineLead)
|
|
29663
30084
|
return onlineLead;
|
|
29664
30085
|
return agents.find((a) => a.isLead) ?? null;
|
|
29665
30086
|
}
|
|
29666
|
-
var
|
|
29667
|
-
var
|
|
30087
|
+
var UNMAPPED_NAMESPACE3 = "integration:unmapped:github";
|
|
30088
|
+
var UNMAPPED_TTL_MS3 = 30 * 24 * 60 * 60 * 1000;
|
|
29668
30089
|
async function resolveGitHubSender(login, sampleEventType, sampleContext) {
|
|
29669
30090
|
const existing = await findUserByExternalId("github", login);
|
|
29670
30091
|
if (existing)
|
|
29671
30092
|
return existing.id;
|
|
29672
30093
|
await upsertKv2({
|
|
29673
|
-
namespace:
|
|
30094
|
+
namespace: UNMAPPED_NAMESPACE3,
|
|
29674
30095
|
key: `${login}:meta`,
|
|
29675
30096
|
value: {
|
|
29676
30097
|
lastSeenAt: new Date().toISOString(),
|
|
@@ -29678,9 +30099,9 @@ async function resolveGitHubSender(login, sampleEventType, sampleContext) {
|
|
|
29678
30099
|
sampleContext: sampleContext.slice(0, 100)
|
|
29679
30100
|
},
|
|
29680
30101
|
valueType: "json",
|
|
29681
|
-
expiresAt: Date.now() +
|
|
30102
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS3
|
|
29682
30103
|
});
|
|
29683
|
-
await incrKv2(
|
|
30104
|
+
await incrKv2(UNMAPPED_NAMESPACE3, `${login}:count`, 1);
|
|
29684
30105
|
return;
|
|
29685
30106
|
}
|
|
29686
30107
|
async function handlePullRequest(event) {
|
|
@@ -29699,10 +30120,10 @@ async function handlePullRequest(event) {
|
|
|
29699
30120
|
return { created: false };
|
|
29700
30121
|
}
|
|
29701
30122
|
const eventKey = `pr-assigned:${repository.full_name}:${pr.number}`;
|
|
29702
|
-
if (
|
|
30123
|
+
if (isDuplicate4(eventKey)) {
|
|
29703
30124
|
return { created: false };
|
|
29704
30125
|
}
|
|
29705
|
-
const lead = await
|
|
30126
|
+
const lead = await findLeadAgent4();
|
|
29706
30127
|
const result = resolveTemplate("github.pull_request.assigned", {
|
|
29707
30128
|
pr_number: pr.number,
|
|
29708
30129
|
pr_title: pr.title,
|
|
@@ -29749,7 +30170,7 @@ async function handlePullRequest(event) {
|
|
|
29749
30170
|
console.log(`[GitHub] unassign cancel disabled by config — leaving task untouched (PR #${pr.number})`);
|
|
29750
30171
|
return { created: false };
|
|
29751
30172
|
}
|
|
29752
|
-
const task = await findTaskByVcs2(repository.full_name, pr.number);
|
|
30173
|
+
const task = await findTaskByVcs2(repository.full_name, pr.number, "github");
|
|
29753
30174
|
if (!task) {
|
|
29754
30175
|
console.log(`[GitHub] No active task found for PR #${pr.number} to cancel`);
|
|
29755
30176
|
return { created: false };
|
|
@@ -29766,15 +30187,15 @@ async function handlePullRequest(event) {
|
|
|
29766
30187
|
return { created: false };
|
|
29767
30188
|
}
|
|
29768
30189
|
const eventKey = `pr-review-requested:${repository.full_name}:${pr.number}`;
|
|
29769
|
-
if (
|
|
30190
|
+
if (isDuplicate4(eventKey)) {
|
|
29770
30191
|
return { created: false };
|
|
29771
30192
|
}
|
|
29772
|
-
const existingTask = await findTaskByVcs2(repository.full_name, pr.number);
|
|
30193
|
+
const existingTask = await findTaskByVcs2(repository.full_name, pr.number, "github");
|
|
29773
30194
|
if (existingTask) {
|
|
29774
30195
|
console.log(`[GitHub] Skipping review task for PR #${pr.number} — active task ${existingTask.id} already exists`);
|
|
29775
30196
|
return { created: false };
|
|
29776
30197
|
}
|
|
29777
|
-
const lead = await
|
|
30198
|
+
const lead = await findLeadAgent4();
|
|
29778
30199
|
const result = resolveTemplate("github.pull_request.review_requested", {
|
|
29779
30200
|
pr_number: pr.number,
|
|
29780
30201
|
pr_title: pr.title,
|
|
@@ -29821,7 +30242,7 @@ async function handlePullRequest(event) {
|
|
|
29821
30242
|
console.log(`[GitHub] review-request-removed cancel disabled by config — leaving task untouched (PR #${pr.number})`);
|
|
29822
30243
|
return { created: false };
|
|
29823
30244
|
}
|
|
29824
|
-
const task = await findTaskByVcs2(repository.full_name, pr.number);
|
|
30245
|
+
const task = await findTaskByVcs2(repository.full_name, pr.number, "github");
|
|
29825
30246
|
if (!task) {
|
|
29826
30247
|
console.log(`[GitHub] No active task found for PR #${pr.number} to cancel`);
|
|
29827
30248
|
return { created: false };
|
|
@@ -29839,10 +30260,10 @@ async function handlePullRequest(event) {
|
|
|
29839
30260
|
return { created: false };
|
|
29840
30261
|
}
|
|
29841
30262
|
const eventKey = `pr-labeled:${repository.full_name}:${pr.number}:${labelName}`;
|
|
29842
|
-
if (
|
|
30263
|
+
if (isDuplicate4(eventKey)) {
|
|
29843
30264
|
return { created: false };
|
|
29844
30265
|
}
|
|
29845
|
-
const lead = await
|
|
30266
|
+
const lead = await findLeadAgent4();
|
|
29846
30267
|
const result = resolveTemplate("github.pull_request.labeled", {
|
|
29847
30268
|
pr_number: pr.number,
|
|
29848
30269
|
pr_title: pr.title,
|
|
@@ -29892,16 +30313,16 @@ async function handlePullRequest(event) {
|
|
|
29892
30313
|
if (action !== "opened" && action !== "edited") {
|
|
29893
30314
|
return { created: false };
|
|
29894
30315
|
}
|
|
29895
|
-
const hasMention =
|
|
30316
|
+
const hasMention = detectMention3(pr.title) || detectMention3(pr.body);
|
|
29896
30317
|
if (!hasMention) {
|
|
29897
30318
|
return { created: false };
|
|
29898
30319
|
}
|
|
29899
30320
|
const eventKey = `pr:${repository.full_name}:${pr.number}:${action}`;
|
|
29900
|
-
if (
|
|
30321
|
+
if (isDuplicate4(eventKey)) {
|
|
29901
30322
|
return { created: false };
|
|
29902
30323
|
}
|
|
29903
|
-
const lead = await
|
|
29904
|
-
const context =
|
|
30324
|
+
const lead = await findLeadAgent4();
|
|
30325
|
+
const context = extractMentionContext3(pr.body) || pr.title;
|
|
29905
30326
|
const result = resolveTemplate("github.pull_request.mentioned", {
|
|
29906
30327
|
pr_number: pr.number,
|
|
29907
30328
|
pr_title: pr.title,
|
|
@@ -29947,10 +30368,10 @@ async function handleIssue(event) {
|
|
|
29947
30368
|
return { created: false };
|
|
29948
30369
|
}
|
|
29949
30370
|
const eventKey = `issue-assigned:${repository.full_name}:${issue.number}`;
|
|
29950
|
-
if (
|
|
30371
|
+
if (isDuplicate4(eventKey)) {
|
|
29951
30372
|
return { created: false };
|
|
29952
30373
|
}
|
|
29953
|
-
const lead = await
|
|
30374
|
+
const lead = await findLeadAgent4();
|
|
29954
30375
|
const result = resolveTemplate("github.issue.assigned", {
|
|
29955
30376
|
issue_number: issue.number,
|
|
29956
30377
|
issue_title: issue.title,
|
|
@@ -29995,7 +30416,7 @@ async function handleIssue(event) {
|
|
|
29995
30416
|
console.log(`[GitHub] unassign cancel disabled by config — leaving task untouched (issue #${issue.number})`);
|
|
29996
30417
|
return { created: false };
|
|
29997
30418
|
}
|
|
29998
|
-
const task = await findTaskByVcs2(repository.full_name, issue.number);
|
|
30419
|
+
const task = await findTaskByVcs2(repository.full_name, issue.number, "github");
|
|
29999
30420
|
if (!task) {
|
|
30000
30421
|
console.log(`[GitHub] No active task found for issue #${issue.number} to cancel`);
|
|
30001
30422
|
return { created: false };
|
|
@@ -30013,10 +30434,10 @@ async function handleIssue(event) {
|
|
|
30013
30434
|
return { created: false };
|
|
30014
30435
|
}
|
|
30015
30436
|
const eventKey = `issue-labeled:${repository.full_name}:${issue.number}:${labelName}`;
|
|
30016
|
-
if (
|
|
30437
|
+
if (isDuplicate4(eventKey)) {
|
|
30017
30438
|
return { created: false };
|
|
30018
30439
|
}
|
|
30019
|
-
const lead = await
|
|
30440
|
+
const lead = await findLeadAgent4();
|
|
30020
30441
|
const result = resolveTemplate("github.issue.labeled", {
|
|
30021
30442
|
issue_number: issue.number,
|
|
30022
30443
|
issue_title: issue.title,
|
|
@@ -30056,16 +30477,16 @@ async function handleIssue(event) {
|
|
|
30056
30477
|
if (action !== "opened" && action !== "edited") {
|
|
30057
30478
|
return { created: false };
|
|
30058
30479
|
}
|
|
30059
|
-
const hasMention =
|
|
30480
|
+
const hasMention = detectMention3(issue.title) || detectMention3(issue.body);
|
|
30060
30481
|
if (!hasMention) {
|
|
30061
30482
|
return { created: false };
|
|
30062
30483
|
}
|
|
30063
30484
|
const eventKey = `issue:${repository.full_name}:${issue.number}:${action}`;
|
|
30064
|
-
if (
|
|
30485
|
+
if (isDuplicate4(eventKey)) {
|
|
30065
30486
|
return { created: false };
|
|
30066
30487
|
}
|
|
30067
|
-
const lead = await
|
|
30068
|
-
const context =
|
|
30488
|
+
const lead = await findLeadAgent4();
|
|
30489
|
+
const context = extractMentionContext3(issue.body) || issue.title;
|
|
30069
30490
|
const result = resolveTemplate("github.issue.mentioned", {
|
|
30070
30491
|
issue_number: issue.number,
|
|
30071
30492
|
issue_title: issue.title,
|
|
@@ -30111,21 +30532,21 @@ async function handleComment(event, eventType) {
|
|
|
30111
30532
|
if (action !== "created") {
|
|
30112
30533
|
return skip("action is not created");
|
|
30113
30534
|
}
|
|
30114
|
-
if (!
|
|
30535
|
+
if (!detectMention3(comment.body)) {
|
|
30115
30536
|
return skip("no bot mention");
|
|
30116
30537
|
}
|
|
30117
30538
|
const eventKey = `comment:${repository.full_name}:${comment.id}`;
|
|
30118
|
-
if (
|
|
30539
|
+
if (isDuplicate4(eventKey)) {
|
|
30119
30540
|
return skip("duplicate delivery");
|
|
30120
30541
|
}
|
|
30121
|
-
const lead = await
|
|
30542
|
+
const lead = await findLeadAgent4();
|
|
30122
30543
|
const target = pull_request || issue;
|
|
30123
30544
|
const targetType = pull_request ? "PR" : "Issue";
|
|
30124
30545
|
const targetNumber = target?.number ?? 0;
|
|
30125
30546
|
const targetTitle = target?.title ?? "Unknown";
|
|
30126
30547
|
const targetUrl = target?.html_url ?? comment.html_url;
|
|
30127
|
-
const existingTask = targetNumber ? await findTaskByVcs2(repository.full_name, targetNumber) : null;
|
|
30128
|
-
const context =
|
|
30548
|
+
const existingTask = targetNumber ? await findTaskByVcs2(repository.full_name, targetNumber, "github") : null;
|
|
30549
|
+
const context = extractMentionContext3(comment.body);
|
|
30129
30550
|
const suggestions = getCommandSuggestions("github-comment", targetType);
|
|
30130
30551
|
const relatedTaskSection = existingTask ? `Related task: ${existingTask.id}
|
|
30131
30552
|
\uD83D\uDD00 Consider routing to the same agent working on the related task.
|
|
@@ -30359,7 +30780,7 @@ async function handlePullRequestReview(event) {
|
|
|
30359
30780
|
return { created: false };
|
|
30360
30781
|
}
|
|
30361
30782
|
const eventKey = `pr-review:${repository.full_name}:${pr.number}:${review.id}`;
|
|
30362
|
-
if (
|
|
30783
|
+
if (isDuplicate4(eventKey)) {
|
|
30363
30784
|
return { created: false };
|
|
30364
30785
|
}
|
|
30365
30786
|
const { comments: inlineComments, degraded } = await fetchReviewComments(repository.full_name, pr.number, review.id, installation?.id);
|
|
@@ -30374,12 +30795,12 @@ async function handlePullRequestReview(event) {
|
|
|
30374
30795
|
return { created: false };
|
|
30375
30796
|
}
|
|
30376
30797
|
}
|
|
30377
|
-
const existingTask = await findTaskByVcs2(repository.full_name, pr.number);
|
|
30798
|
+
const existingTask = await findTaskByVcs2(repository.full_name, pr.number, "github");
|
|
30378
30799
|
const isBotCreator = isBotAssignee(pr.user.login);
|
|
30379
30800
|
if (!isBotCreator && !existingTask) {
|
|
30380
30801
|
return { created: false };
|
|
30381
30802
|
}
|
|
30382
|
-
const lead = await
|
|
30803
|
+
const lead = await findLeadAgent4();
|
|
30383
30804
|
const { emoji, label } = getReviewStateInfo(review.state);
|
|
30384
30805
|
const reviewBodySection = review.body ? `
|
|
30385
30806
|
|
|
@@ -30456,46 +30877,46 @@ async function handleWorkflowRun(event) {
|
|
|
30456
30877
|
}
|
|
30457
30878
|
// src/gitlab/auth.ts
|
|
30458
30879
|
init_env_flag();
|
|
30459
|
-
var
|
|
30460
|
-
var
|
|
30461
|
-
var
|
|
30880
|
+
var initialized5 = false;
|
|
30881
|
+
var webhookSecret5 = null;
|
|
30882
|
+
var apiToken3 = null;
|
|
30462
30883
|
var gitlabUrl = "https://gitlab.com";
|
|
30463
30884
|
function isGitLabEnabled() {
|
|
30464
30885
|
return !!process.env.GITLAB_WEBHOOK_SECRET && !isEnvFlagEnabled("GITLAB_DISABLE", false);
|
|
30465
30886
|
}
|
|
30466
30887
|
function initGitLab() {
|
|
30467
|
-
if (
|
|
30888
|
+
if (initialized5)
|
|
30468
30889
|
return;
|
|
30469
30890
|
if (!isGitLabEnabled()) {
|
|
30470
30891
|
console.log("[GitLab] Integration disabled (GITLAB_WEBHOOK_SECRET not set)");
|
|
30471
30892
|
return;
|
|
30472
30893
|
}
|
|
30473
|
-
|
|
30474
|
-
|
|
30894
|
+
webhookSecret5 = process.env.GITLAB_WEBHOOK_SECRET;
|
|
30895
|
+
apiToken3 = process.env.GITLAB_TOKEN ?? null;
|
|
30475
30896
|
gitlabUrl = process.env.GITLAB_URL ?? "https://gitlab.com";
|
|
30476
|
-
|
|
30897
|
+
initialized5 = true;
|
|
30477
30898
|
console.log(`[GitLab] Integration initialized (url: ${gitlabUrl})`);
|
|
30478
30899
|
}
|
|
30479
30900
|
function verifyGitLabWebhook(tokenHeader) {
|
|
30480
|
-
if (!
|
|
30901
|
+
if (!webhookSecret5)
|
|
30481
30902
|
return false;
|
|
30482
30903
|
if (!tokenHeader)
|
|
30483
30904
|
return false;
|
|
30484
|
-
if (tokenHeader.length !==
|
|
30905
|
+
if (tokenHeader.length !== webhookSecret5.length)
|
|
30485
30906
|
return false;
|
|
30486
|
-
return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(
|
|
30907
|
+
return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(webhookSecret5));
|
|
30487
30908
|
}
|
|
30488
30909
|
function getGitLabToken() {
|
|
30489
|
-
return
|
|
30910
|
+
return apiToken3;
|
|
30490
30911
|
}
|
|
30491
30912
|
function getGitLabUrl() {
|
|
30492
30913
|
return gitlabUrl;
|
|
30493
30914
|
}
|
|
30494
30915
|
var GITLAB_BOT_NAME = process.env.GITLAB_BOT_NAME ?? "agent-swarm-bot";
|
|
30495
30916
|
function resetGitLab() {
|
|
30496
|
-
|
|
30497
|
-
|
|
30498
|
-
|
|
30917
|
+
initialized5 = false;
|
|
30918
|
+
webhookSecret5 = null;
|
|
30919
|
+
apiToken3 = null;
|
|
30499
30920
|
gitlabUrl = "https://gitlab.com";
|
|
30500
30921
|
}
|
|
30501
30922
|
// src/gitlab/handlers.ts
|
|
@@ -30505,7 +30926,7 @@ init_resolver();
|
|
|
30505
30926
|
init_context_key();
|
|
30506
30927
|
|
|
30507
30928
|
// src/gitlab/reactions.ts
|
|
30508
|
-
function
|
|
30929
|
+
function headers4() {
|
|
30509
30930
|
const token = getGitLabToken();
|
|
30510
30931
|
if (!token)
|
|
30511
30932
|
throw new Error("[GitLab] No API token configured");
|
|
@@ -30526,7 +30947,7 @@ async function addGitLabReaction(project, entityType, iid, emojiName) {
|
|
|
30526
30947
|
try {
|
|
30527
30948
|
const resp = await fetch(url, {
|
|
30528
30949
|
method: "POST",
|
|
30529
|
-
headers:
|
|
30950
|
+
headers: headers4(),
|
|
30530
30951
|
body: JSON.stringify({ name: emojiName })
|
|
30531
30952
|
});
|
|
30532
30953
|
if (!resp.ok) {
|
|
@@ -30542,7 +30963,7 @@ async function addGitLabNoteReaction(project, entityType, iid, noteId, emojiName
|
|
|
30542
30963
|
try {
|
|
30543
30964
|
const resp = await fetch(url, {
|
|
30544
30965
|
method: "POST",
|
|
30545
|
-
headers:
|
|
30966
|
+
headers: headers4(),
|
|
30546
30967
|
body: JSON.stringify({ name: emojiName })
|
|
30547
30968
|
});
|
|
30548
30969
|
if (!resp.ok) {
|
|
@@ -30666,33 +31087,33 @@ The CI pipeline has failed. Please investigate and fix the issues.{{@template[co
|
|
|
30666
31087
|
});
|
|
30667
31088
|
|
|
30668
31089
|
// src/gitlab/handlers.ts
|
|
30669
|
-
var
|
|
30670
|
-
var
|
|
30671
|
-
function
|
|
31090
|
+
var processedEvents5 = new Map;
|
|
31091
|
+
var DEDUP_TTL_MS3 = 60000;
|
|
31092
|
+
function isDuplicate5(key) {
|
|
30672
31093
|
const now = Date.now();
|
|
30673
|
-
for (const [k, ts] of
|
|
30674
|
-
if (now - ts >
|
|
30675
|
-
|
|
31094
|
+
for (const [k, ts] of processedEvents5) {
|
|
31095
|
+
if (now - ts > DEDUP_TTL_MS3)
|
|
31096
|
+
processedEvents5.delete(k);
|
|
30676
31097
|
}
|
|
30677
|
-
if (
|
|
31098
|
+
if (processedEvents5.has(key))
|
|
30678
31099
|
return true;
|
|
30679
|
-
|
|
31100
|
+
processedEvents5.set(key, now);
|
|
30680
31101
|
return false;
|
|
30681
31102
|
}
|
|
30682
|
-
function
|
|
31103
|
+
function detectMention4(text) {
|
|
30683
31104
|
if (!text)
|
|
30684
31105
|
return false;
|
|
30685
31106
|
return new RegExp(`@${GITLAB_BOT_NAME}\\b`, "i").test(text);
|
|
30686
31107
|
}
|
|
30687
|
-
function
|
|
31108
|
+
function extractMentionContext4(text) {
|
|
30688
31109
|
return text.replace(new RegExp(`@${GITLAB_BOT_NAME}\\b`, "gi"), "").trim();
|
|
30689
31110
|
}
|
|
30690
|
-
async function
|
|
31111
|
+
async function findLeadAgent5() {
|
|
30691
31112
|
const agents = await getAllAgents2();
|
|
30692
31113
|
return agents.find((a) => a.role === "lead" && a.status === "idle") ?? agents.find((a) => a.role === "lead") ?? null;
|
|
30693
31114
|
}
|
|
30694
|
-
var
|
|
30695
|
-
var
|
|
31115
|
+
var UNMAPPED_NAMESPACE4 = "integration:unmapped:gitlab";
|
|
31116
|
+
var UNMAPPED_TTL_MS4 = 30 * 24 * 60 * 60 * 1000;
|
|
30696
31117
|
var GITLAB_WEBHOOK_ACTOR = { kind: "system", id: "webhook:gitlab" };
|
|
30697
31118
|
async function resolveGitLabSender(user, sampleEventType, sampleContext) {
|
|
30698
31119
|
const existing = await findUserByExternalId("gitlab", user.username);
|
|
@@ -30705,7 +31126,7 @@ async function resolveGitLabSender(user, sampleEventType, sampleContext) {
|
|
|
30705
31126
|
return linked.id;
|
|
30706
31127
|
}
|
|
30707
31128
|
await upsertKv2({
|
|
30708
|
-
namespace:
|
|
31129
|
+
namespace: UNMAPPED_NAMESPACE4,
|
|
30709
31130
|
key: `${user.username}:meta`,
|
|
30710
31131
|
value: {
|
|
30711
31132
|
lastSeenAt: new Date().toISOString(),
|
|
@@ -30713,9 +31134,9 @@ async function resolveGitLabSender(user, sampleEventType, sampleContext) {
|
|
|
30713
31134
|
sampleContext: sampleContext.slice(0, 100)
|
|
30714
31135
|
},
|
|
30715
31136
|
valueType: "json",
|
|
30716
|
-
expiresAt: Date.now() +
|
|
31137
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS4
|
|
30717
31138
|
});
|
|
30718
|
-
await incrKv2(
|
|
31139
|
+
await incrKv2(UNMAPPED_NAMESPACE4, `${user.username}:count`, 1);
|
|
30719
31140
|
return;
|
|
30720
31141
|
}
|
|
30721
31142
|
async function renderGitLabIdentity(username) {
|
|
@@ -30728,19 +31149,19 @@ async function handleMergeRequest(event) {
|
|
|
30728
31149
|
const requestedByUserId = await resolveGitLabSender(user, "merge_request", `MR !${mr.iid}: ${mr.title}`);
|
|
30729
31150
|
console.log(`[GitLab] MR #${mr.iid} ${action} by ${user.username} in ${repo}`);
|
|
30730
31151
|
const dedupKey = `gitlab-mr-${repo}-${mr.iid}-${action}-${user.username}`;
|
|
30731
|
-
if (
|
|
31152
|
+
if (isDuplicate5(dedupKey)) {
|
|
30732
31153
|
console.log(`[GitLab] Skipping duplicate MR event`);
|
|
30733
31154
|
return { created: false };
|
|
30734
31155
|
}
|
|
30735
|
-
const lead = await
|
|
31156
|
+
const lead = await findLeadAgent5();
|
|
30736
31157
|
switch (action) {
|
|
30737
31158
|
case "open": {
|
|
30738
|
-
const hasMention =
|
|
31159
|
+
const hasMention = detectMention4(mr.description);
|
|
30739
31160
|
if (!hasMention) {
|
|
30740
31161
|
console.log(`[GitLab] MR opened without bot mention, skipping`);
|
|
30741
31162
|
return { created: false };
|
|
30742
31163
|
}
|
|
30743
|
-
const context = mr.description ?
|
|
31164
|
+
const context = mr.description ? extractMentionContext4(mr.description) : "";
|
|
30744
31165
|
const contextSection = context ? `Context: ${context}
|
|
30745
31166
|
|
|
30746
31167
|
` : "";
|
|
@@ -30784,7 +31205,7 @@ async function handleMergeRequest(event) {
|
|
|
30784
31205
|
}
|
|
30785
31206
|
case "close":
|
|
30786
31207
|
case "merge": {
|
|
30787
|
-
const existingTask = await findTaskByVcs2(repo, mr.iid);
|
|
31208
|
+
const existingTask = await findTaskByVcs2(repo, mr.iid, "gitlab");
|
|
30788
31209
|
if (existingTask) {
|
|
30789
31210
|
const reason = action === "merge" ? "MR was merged" : "MR was closed";
|
|
30790
31211
|
console.log(`[GitLab] Cancelling task ${existingTask.id} — ${reason}`);
|
|
@@ -30793,7 +31214,7 @@ async function handleMergeRequest(event) {
|
|
|
30793
31214
|
return { created: false };
|
|
30794
31215
|
}
|
|
30795
31216
|
case "update": {
|
|
30796
|
-
const task = await findTaskByVcs2(repo, mr.iid);
|
|
31217
|
+
const task = await findTaskByVcs2(repo, mr.iid, "gitlab");
|
|
30797
31218
|
if (task) {
|
|
30798
31219
|
console.log(`[GitLab] MR #${mr.iid} updated, active task exists: ${task.id}`);
|
|
30799
31220
|
return { created: false };
|
|
@@ -30812,13 +31233,13 @@ async function handleIssue2(event) {
|
|
|
30812
31233
|
const requestedByUserId = await resolveGitLabSender(user, "issue", `Issue #${issue.iid}: ${issue.title}`);
|
|
30813
31234
|
console.log(`[GitLab] Issue #${issue.iid} ${action} by ${user.username} in ${repo}`);
|
|
30814
31235
|
const dedupKey = `gitlab-issue-${repo}-${issue.iid}-${action}-${user.username}`;
|
|
30815
|
-
if (
|
|
31236
|
+
if (isDuplicate5(dedupKey)) {
|
|
30816
31237
|
return { created: false };
|
|
30817
31238
|
}
|
|
30818
|
-
const lead = await
|
|
31239
|
+
const lead = await findLeadAgent5();
|
|
30819
31240
|
switch (action) {
|
|
30820
31241
|
case "open": {
|
|
30821
|
-
const hasMention =
|
|
31242
|
+
const hasMention = detectMention4(issue.description);
|
|
30822
31243
|
if (!hasMention) {
|
|
30823
31244
|
const isBotAssigned = event.assignees?.some((a) => a.username.toLowerCase() === GITLAB_BOT_NAME.toLowerCase());
|
|
30824
31245
|
if (!isBotAssigned) {
|
|
@@ -30826,7 +31247,7 @@ async function handleIssue2(event) {
|
|
|
30826
31247
|
return { created: false };
|
|
30827
31248
|
}
|
|
30828
31249
|
}
|
|
30829
|
-
const context = issue.description ?
|
|
31250
|
+
const context = issue.description ? extractMentionContext4(issue.description) : "";
|
|
30830
31251
|
const contextSection = context ? `Context: ${context}
|
|
30831
31252
|
|
|
30832
31253
|
` : "";
|
|
@@ -30867,7 +31288,7 @@ async function handleIssue2(event) {
|
|
|
30867
31288
|
return { created: true, taskId: task.id };
|
|
30868
31289
|
}
|
|
30869
31290
|
case "close": {
|
|
30870
|
-
const existingTask = await findTaskByVcs2(repo, issue.iid);
|
|
31291
|
+
const existingTask = await findTaskByVcs2(repo, issue.iid, "gitlab");
|
|
30871
31292
|
if (existingTask) {
|
|
30872
31293
|
console.log(`[GitLab] Cancelling task ${existingTask.id} — issue closed`);
|
|
30873
31294
|
await failTask2(existingTask.id, "Issue was closed");
|
|
@@ -30882,16 +31303,16 @@ async function handleNote(event) {
|
|
|
30882
31303
|
const { user, project, object_attributes: note } = event;
|
|
30883
31304
|
const repo = project.path_with_namespace;
|
|
30884
31305
|
const requestedByUserId = await resolveGitLabSender(user, "note", note.note);
|
|
30885
|
-
if (!
|
|
31306
|
+
if (!detectMention4(note.note)) {
|
|
30886
31307
|
return { created: false };
|
|
30887
31308
|
}
|
|
30888
31309
|
console.log(`[GitLab] Note by ${user.username} in ${repo} (${note.noteable_type})`);
|
|
30889
31310
|
const dedupKey = `gitlab-note-${note.id}`;
|
|
30890
|
-
if (
|
|
31311
|
+
if (isDuplicate5(dedupKey)) {
|
|
30891
31312
|
return { created: false };
|
|
30892
31313
|
}
|
|
30893
|
-
const lead = await
|
|
30894
|
-
const context =
|
|
31314
|
+
const lead = await findLeadAgent5();
|
|
31315
|
+
const context = extractMentionContext4(note.note);
|
|
30895
31316
|
let targetNumber;
|
|
30896
31317
|
let targetUrl;
|
|
30897
31318
|
let eventType;
|
|
@@ -30910,7 +31331,7 @@ async function handleNote(event) {
|
|
|
30910
31331
|
console.log(`[GitLab] Ignoring note on ${note.noteable_type}`);
|
|
30911
31332
|
return { created: false };
|
|
30912
31333
|
}
|
|
30913
|
-
const existingTask = targetNumber ? await findTaskByVcs2(repo, targetNumber) : null;
|
|
31334
|
+
const existingTask = targetNumber ? await findTaskByVcs2(repo, targetNumber, "gitlab") : null;
|
|
30914
31335
|
const existingTaskNote = existingTask ? `
|
|
30915
31336
|
|
|
30916
31337
|
_Note: There's an active task (${existingTask.id}) for this ${entityLabel}._` : "";
|
|
@@ -30965,14 +31386,14 @@ async function handlePipeline(event) {
|
|
|
30965
31386
|
}
|
|
30966
31387
|
const mrIid = event.merge_request.iid;
|
|
30967
31388
|
const dedupKey = `gitlab-pipeline-${pipeline.id}`;
|
|
30968
|
-
if (
|
|
31389
|
+
if (isDuplicate5(dedupKey)) {
|
|
30969
31390
|
return { created: false };
|
|
30970
31391
|
}
|
|
30971
|
-
const existingTask = await findTaskByVcs2(repo, mrIid);
|
|
31392
|
+
const existingTask = await findTaskByVcs2(repo, mrIid, "gitlab");
|
|
30972
31393
|
if (!existingTask) {
|
|
30973
31394
|
return { created: false };
|
|
30974
31395
|
}
|
|
30975
|
-
const lead = await
|
|
31396
|
+
const lead = await findLeadAgent5();
|
|
30976
31397
|
const pipelineResult = resolveTemplate("gitlab.pipeline.failed", {
|
|
30977
31398
|
pipeline_id: pipeline.id,
|
|
30978
31399
|
mr_iid: mrIid,
|
|
@@ -31176,6 +31597,71 @@ function readApiUrlOverrides() {
|
|
|
31176
31597
|
}
|
|
31177
31598
|
}
|
|
31178
31599
|
|
|
31600
|
+
// src/integrations/chat-sdk/facts.ts
|
|
31601
|
+
var SNIPPET_MAX = 80;
|
|
31602
|
+
function snippet2(text) {
|
|
31603
|
+
const flat = text?.replace(/\s+/g, " ").trim();
|
|
31604
|
+
if (!flat)
|
|
31605
|
+
return;
|
|
31606
|
+
return flat.length > SNIPPET_MAX ? `${flat.slice(0, SNIPPET_MAX)}...` : flat;
|
|
31607
|
+
}
|
|
31608
|
+
function personLabel(name, username, fallback) {
|
|
31609
|
+
if (name && username && name !== username)
|
|
31610
|
+
return `${name} (@${username})`;
|
|
31611
|
+
if (username)
|
|
31612
|
+
return `@${username}`;
|
|
31613
|
+
return name || fallback;
|
|
31614
|
+
}
|
|
31615
|
+
function replyIsTopicRoot(raw) {
|
|
31616
|
+
const reply = raw.reply_to_message;
|
|
31617
|
+
return reply !== undefined && (reply.forum_topic_created !== undefined || raw.is_topic_message === true && reply.message_id === raw.message_thread_id);
|
|
31618
|
+
}
|
|
31619
|
+
function isTelegramReplyToBot(raw, botUserId) {
|
|
31620
|
+
const fromId = raw.reply_to_message?.from?.id;
|
|
31621
|
+
return !replyIsTopicRoot(raw) && fromId !== undefined && botUserId !== undefined && String(fromId) === botUserId;
|
|
31622
|
+
}
|
|
31623
|
+
function telegramFacts(raw, message, botUserId) {
|
|
31624
|
+
const reply = raw.reply_to_message;
|
|
31625
|
+
const topicRoot = replyIsTopicRoot(raw);
|
|
31626
|
+
const realReply = reply && !topicRoot ? reply : undefined;
|
|
31627
|
+
const topicName = topicRoot ? reply?.forum_topic_created?.name : undefined;
|
|
31628
|
+
const name = [raw.from?.first_name, raw.from?.last_name].filter(Boolean).join(" ").trim();
|
|
31629
|
+
return {
|
|
31630
|
+
chatType: raw.chat?.type,
|
|
31631
|
+
isForum: raw.chat?.is_forum === true ? true : undefined,
|
|
31632
|
+
title: raw.chat?.title,
|
|
31633
|
+
topic: raw.is_topic_message === true && raw.message_thread_id !== undefined ? topicName ? `"${topicName}"` : `#${raw.message_thread_id}` : undefined,
|
|
31634
|
+
from: personLabel(name || undefined, raw.from?.username, message.author.userId),
|
|
31635
|
+
replyToBot: isTelegramReplyToBot(raw, botUserId),
|
|
31636
|
+
replyToSnippet: snippet2(realReply?.text ?? realReply?.caption)
|
|
31637
|
+
};
|
|
31638
|
+
}
|
|
31639
|
+
function readChatMessageFacts(thread, message) {
|
|
31640
|
+
const raw = message.raw;
|
|
31641
|
+
if (thread.adapter.name === "telegram" && raw && typeof raw === "object") {
|
|
31642
|
+
return telegramFacts(raw, message, thread.adapter.botUserId);
|
|
31643
|
+
}
|
|
31644
|
+
const { fullName, userName, userId } = message.author;
|
|
31645
|
+
return {
|
|
31646
|
+
chatType: thread.isDM ? "dm" : undefined,
|
|
31647
|
+
from: personLabel(fullName || undefined, userName || undefined, userId),
|
|
31648
|
+
replyToBot: message.replyTo?.author.isMe === true,
|
|
31649
|
+
replyToSnippet: snippet2(message.replyTo?.text)
|
|
31650
|
+
};
|
|
31651
|
+
}
|
|
31652
|
+
function formatChatHeaderFacts(adapter, facts, addressed) {
|
|
31653
|
+
const oneLine = (text) => text.replace(/\s+/g, " ").trim();
|
|
31654
|
+
const parts = [adapter];
|
|
31655
|
+
if (facts.chatType)
|
|
31656
|
+
parts.push(facts.title ? `${facts.chatType} "${oneLine(facts.title)}"` : facts.chatType);
|
|
31657
|
+
if (facts.isForum)
|
|
31658
|
+
parts.push(facts.topic ? `forum topic ${oneLine(facts.topic)}` : "forum");
|
|
31659
|
+
parts.push(`from: ${oneLine(facts.from)}`, `addressed: ${addressed}`);
|
|
31660
|
+
if (facts.replyToSnippet)
|
|
31661
|
+
parts.push(`reply-to: "${facts.replyToSnippet}"`);
|
|
31662
|
+
return parts.join(" · ");
|
|
31663
|
+
}
|
|
31664
|
+
|
|
31179
31665
|
// src/integrations/chat-sdk/logger.ts
|
|
31180
31666
|
init_secret_scrubber();
|
|
31181
31667
|
var MAX_ISSUE_CHARS = 300;
|
|
@@ -31267,8 +31753,18 @@ async function loadAdapter(name, config, logger) {
|
|
|
31267
31753
|
const base = { ...config, apiUrl, logger };
|
|
31268
31754
|
switch (name) {
|
|
31269
31755
|
case "telegram": {
|
|
31270
|
-
const {
|
|
31271
|
-
|
|
31756
|
+
const { TelegramAdapter } = await import("./index-zsyx51ap.js");
|
|
31757
|
+
|
|
31758
|
+
class SwarmTelegramAdapter extends TelegramAdapter {
|
|
31759
|
+
isBotMentioned(message, text) {
|
|
31760
|
+
return super.isBotMentioned(message, text) || String(message.from?.id) !== this.botUserId && isTelegramReplyToBot(message, this.botUserId);
|
|
31761
|
+
}
|
|
31762
|
+
}
|
|
31763
|
+
return new SwarmTelegramAdapter({
|
|
31764
|
+
...base,
|
|
31765
|
+
allowUnverifiedWebhooks: false,
|
|
31766
|
+
mentionOnReply: true
|
|
31767
|
+
});
|
|
31272
31768
|
}
|
|
31273
31769
|
case "slack": {
|
|
31274
31770
|
const { createSlackAdapter } = await import("./index-zgvqzjsw.js");
|
|
@@ -31870,6 +32366,43 @@ function resetDiscordGatewayHealth() {
|
|
|
31870
32366
|
// src/integrations/chat-sdk/inbound.ts
|
|
31871
32367
|
init_zod();
|
|
31872
32368
|
init_db3();
|
|
32369
|
+
|
|
32370
|
+
// src/be/unmapped-identities.ts
|
|
32371
|
+
init_db3();
|
|
32372
|
+
var TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
32373
|
+
function namespace(kind) {
|
|
32374
|
+
return `integration:unmapped:${kind}`;
|
|
32375
|
+
}
|
|
32376
|
+
async function recordUnmappedIdentity(kind, externalId, meta) {
|
|
32377
|
+
const ns = namespace(kind);
|
|
32378
|
+
const now = new Date().toISOString();
|
|
32379
|
+
const expiresAt = Date.now() + TTL_MS;
|
|
32380
|
+
const countKey = `${externalId}:count`;
|
|
32381
|
+
const countBefore = await getKv2(ns, countKey);
|
|
32382
|
+
await upsertKv2({
|
|
32383
|
+
namespace: ns,
|
|
32384
|
+
key: `${externalId}:meta`,
|
|
32385
|
+
value: {
|
|
32386
|
+
lastSeenAt: now,
|
|
32387
|
+
sampleEventType: meta.sampleEventType,
|
|
32388
|
+
sampleContext: meta.sampleContext.slice(0, 100)
|
|
32389
|
+
},
|
|
32390
|
+
valueType: "json",
|
|
32391
|
+
expiresAt
|
|
32392
|
+
});
|
|
32393
|
+
const incremented = await incrKv2(ns, countKey, 1);
|
|
32394
|
+
if (countBefore === null) {
|
|
32395
|
+
await upsertKv2({
|
|
32396
|
+
namespace: ns,
|
|
32397
|
+
key: countKey,
|
|
32398
|
+
value: Number(incremented.value),
|
|
32399
|
+
valueType: "integer",
|
|
32400
|
+
expiresAt
|
|
32401
|
+
});
|
|
32402
|
+
}
|
|
32403
|
+
}
|
|
32404
|
+
|
|
32405
|
+
// src/integrations/chat-sdk/inbound.ts
|
|
31873
32406
|
init_resolver();
|
|
31874
32407
|
init_context_key();
|
|
31875
32408
|
init_secret_scrubber();
|
|
@@ -31918,10 +32451,191 @@ async function recordTaskAttachmentUpload(input) {
|
|
|
31918
32451
|
throw error;
|
|
31919
32452
|
}
|
|
31920
32453
|
}
|
|
32454
|
+
function scopeFromAttachment(attachment) {
|
|
32455
|
+
const storedKey = attachment.providerKey ?? attachment.path ?? "";
|
|
32456
|
+
return {
|
|
32457
|
+
taskId: attachment.taskId,
|
|
32458
|
+
name: attachment.name,
|
|
32459
|
+
key: storedKey.trim() ? storedKey : undefined,
|
|
32460
|
+
orgId: attachment.orgId,
|
|
32461
|
+
driveId: attachment.driveId
|
|
32462
|
+
};
|
|
32463
|
+
}
|
|
32464
|
+
function backingProviderId(attachment) {
|
|
32465
|
+
if (attachment.kind === "agent-fs")
|
|
32466
|
+
return attachment.providerId ?? "agent-fs";
|
|
32467
|
+
if (attachment.providerId === "local-fs")
|
|
32468
|
+
return "local-fs";
|
|
32469
|
+
return null;
|
|
32470
|
+
}
|
|
32471
|
+
|
|
32472
|
+
// src/utils/transcription.ts
|
|
32473
|
+
init_secret_scrubber();
|
|
32474
|
+
var TRANSCRIPTION_TIMEOUT_MS = 60000;
|
|
32475
|
+
var TRANSCRIPTION_API_KEY_ENV = "TRANSCRIPTION_API_KEY";
|
|
32476
|
+
var openAIShape = {
|
|
32477
|
+
path: "/audio/transcriptions",
|
|
32478
|
+
modelField: "model",
|
|
32479
|
+
authHeaders: (apiKey) => ({ authorization: `Bearer ${apiKey}` })
|
|
32480
|
+
};
|
|
32481
|
+
var PROVIDERS = {
|
|
32482
|
+
openai: {
|
|
32483
|
+
keyEnv: "OPENAI_API_KEY",
|
|
32484
|
+
defaultBaseUrl: "https://api.openai.com/v1",
|
|
32485
|
+
defaultModel: "whisper-1",
|
|
32486
|
+
...openAIShape
|
|
32487
|
+
},
|
|
32488
|
+
groq: {
|
|
32489
|
+
keyEnv: "GROQ_API_KEY",
|
|
32490
|
+
defaultBaseUrl: "https://api.groq.com/openai/v1",
|
|
32491
|
+
defaultModel: "whisper-large-v3-turbo",
|
|
32492
|
+
...openAIShape
|
|
32493
|
+
},
|
|
32494
|
+
elevenlabs: {
|
|
32495
|
+
keyEnv: "ELEVENLABS_API_KEY",
|
|
32496
|
+
defaultBaseUrl: "https://api.elevenlabs.io/v1",
|
|
32497
|
+
defaultModel: "scribe_v2",
|
|
32498
|
+
path: "/speech-to-text",
|
|
32499
|
+
modelField: "model_id",
|
|
32500
|
+
authHeaders: (apiKey) => ({ "xi-api-key": apiKey })
|
|
32501
|
+
}
|
|
32502
|
+
};
|
|
32503
|
+
var AUTO_DETECT_ORDER = ["elevenlabs", "openai", "groq"];
|
|
32504
|
+
var TRANSCRIPTION_ENV_KEYS = [
|
|
32505
|
+
TRANSCRIPTION_API_KEY_ENV,
|
|
32506
|
+
"TRANSCRIPTION_PROVIDER",
|
|
32507
|
+
"TRANSCRIPTION_BASE_URL",
|
|
32508
|
+
"TRANSCRIPTION_MODEL",
|
|
32509
|
+
...AUTO_DETECT_ORDER.map((name) => PROVIDERS[name].keyEnv)
|
|
32510
|
+
];
|
|
32511
|
+
|
|
32512
|
+
class TranscriptionError extends Error {
|
|
32513
|
+
constructor(message) {
|
|
32514
|
+
super(message);
|
|
32515
|
+
this.name = "TranscriptionError";
|
|
32516
|
+
}
|
|
32517
|
+
}
|
|
32518
|
+
function envValue(key) {
|
|
32519
|
+
return process.env[key]?.trim() || undefined;
|
|
32520
|
+
}
|
|
32521
|
+
function resolveTranscriptionConfig() {
|
|
32522
|
+
const pinned = envValue("TRANSCRIPTION_PROVIDER")?.toLowerCase();
|
|
32523
|
+
const explicitKey = envValue(TRANSCRIPTION_API_KEY_ENV);
|
|
32524
|
+
if (explicitKey) {
|
|
32525
|
+
return {
|
|
32526
|
+
provider: pinned ?? "openai",
|
|
32527
|
+
apiKey: explicitKey,
|
|
32528
|
+
keyEnv: TRANSCRIPTION_API_KEY_ENV,
|
|
32529
|
+
source: "explicit"
|
|
32530
|
+
};
|
|
32531
|
+
}
|
|
32532
|
+
const candidates = pinned ? AUTO_DETECT_ORDER.filter((name) => name === pinned) : AUTO_DETECT_ORDER;
|
|
32533
|
+
for (const name of candidates) {
|
|
32534
|
+
const { keyEnv } = PROVIDERS[name];
|
|
32535
|
+
const apiKey = envValue(keyEnv);
|
|
32536
|
+
if (apiKey)
|
|
32537
|
+
return { provider: name, apiKey, keyEnv, source: "auto" };
|
|
32538
|
+
}
|
|
32539
|
+
return null;
|
|
32540
|
+
}
|
|
32541
|
+
function isTranscriptionConfigured() {
|
|
32542
|
+
return resolveTranscriptionConfig() !== null;
|
|
32543
|
+
}
|
|
32544
|
+
function providerSpec(name) {
|
|
32545
|
+
if (!Object.hasOwn(PROVIDERS, name)) {
|
|
32546
|
+
throw new TranscriptionError(`TRANSCRIPTION_PROVIDER "${name}" is not supported (use ${Object.keys(PROVIDERS).join(", ")})`);
|
|
32547
|
+
}
|
|
32548
|
+
return PROVIDERS[name];
|
|
32549
|
+
}
|
|
32550
|
+
function errorDetail(payload, status) {
|
|
32551
|
+
const error = payload?.error;
|
|
32552
|
+
if (typeof error?.message === "string")
|
|
32553
|
+
return error.message;
|
|
32554
|
+
const detail = payload?.detail;
|
|
32555
|
+
if (typeof detail === "string")
|
|
32556
|
+
return detail;
|
|
32557
|
+
if (typeof detail?.message === "string")
|
|
32558
|
+
return detail.message;
|
|
32559
|
+
return `HTTP ${status}`;
|
|
32560
|
+
}
|
|
32561
|
+
async function transcribeAudio(input) {
|
|
32562
|
+
const config = resolveTranscriptionConfig();
|
|
32563
|
+
if (!config)
|
|
32564
|
+
throw new TranscriptionError("no transcription provider key is set");
|
|
32565
|
+
const { apiKey } = config;
|
|
32566
|
+
const provider = providerSpec(config.provider);
|
|
32567
|
+
const baseUrlOverride = config.source === "explicit" ? process.env.TRANSCRIPTION_BASE_URL?.trim() : undefined;
|
|
32568
|
+
const baseUrl = (baseUrlOverride || provider.defaultBaseUrl).replace(/\/+$/, "");
|
|
32569
|
+
const keyScrubber = createValueScrubber([{ value: apiKey, name: config.keyEnv }]);
|
|
32570
|
+
const scrub = (text) => scrubSecrets(keyScrubber.text(text));
|
|
32571
|
+
const form = new FormData;
|
|
32572
|
+
const type = input.mimeType ?? input.data.type;
|
|
32573
|
+
form.append("file", type ? new Blob([input.data], { type }) : input.data, input.filename);
|
|
32574
|
+
form.append(provider.modelField, process.env.TRANSCRIPTION_MODEL?.trim() || provider.defaultModel);
|
|
32575
|
+
let response;
|
|
32576
|
+
try {
|
|
32577
|
+
response = await fetch(`${baseUrl}${provider.path}`, {
|
|
32578
|
+
method: "POST",
|
|
32579
|
+
headers: provider.authHeaders(apiKey),
|
|
32580
|
+
body: form,
|
|
32581
|
+
signal: AbortSignal.timeout(TRANSCRIPTION_TIMEOUT_MS)
|
|
32582
|
+
});
|
|
32583
|
+
} catch (error) {
|
|
32584
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
32585
|
+
throw new TranscriptionError(`no answer within ${TRANSCRIPTION_TIMEOUT_MS / 1000} s`);
|
|
32586
|
+
}
|
|
32587
|
+
throw new TranscriptionError(scrub(error instanceof Error ? error.message : String(error)));
|
|
32588
|
+
}
|
|
32589
|
+
const payload = await response.json().catch(() => null);
|
|
32590
|
+
if (!response.ok || typeof payload?.text !== "string") {
|
|
32591
|
+
throw new TranscriptionError(scrub(errorDetail(payload, response.status)));
|
|
32592
|
+
}
|
|
32593
|
+
return payload.text.trim();
|
|
32594
|
+
}
|
|
32595
|
+
var NOT_TRANSCRIBED_NOTE = `(not transcribed: no transcription provider configured, set ${TRANSCRIPTION_API_KEY_ENV} or one of ${AUTO_DETECT_ORDER.map((name) => PROVIDERS[name].keyEnv).join(", ")})`;
|
|
32596
|
+
var AUDIO_EXTENSIONS = {
|
|
32597
|
+
"audio/ogg": "ogg",
|
|
32598
|
+
"audio/opus": "ogg",
|
|
32599
|
+
"audio/mpeg": "mp3",
|
|
32600
|
+
"audio/mp4": "m4a",
|
|
32601
|
+
"audio/x-m4a": "m4a",
|
|
32602
|
+
"audio/wav": "wav",
|
|
32603
|
+
"audio/x-wav": "wav",
|
|
32604
|
+
"audio/webm": "webm"
|
|
32605
|
+
};
|
|
32606
|
+
async function transcribeAudioNotes(files, logPrefix) {
|
|
32607
|
+
const notes = new Map;
|
|
32608
|
+
if (files.length === 0)
|
|
32609
|
+
return notes;
|
|
32610
|
+
if (!isTranscriptionConfigured()) {
|
|
32611
|
+
for (const file of files)
|
|
32612
|
+
notes.set(file.key, NOT_TRANSCRIBED_NOTE);
|
|
32613
|
+
return notes;
|
|
32614
|
+
}
|
|
32615
|
+
for (const file of files) {
|
|
32616
|
+
const extension = AUDIO_EXTENSIONS[file.mimeType ?? ""] ?? "ogg";
|
|
32617
|
+
const filename = /\.\w+$/.test(file.name) ? file.name : `${file.name}.${extension}`;
|
|
32618
|
+
try {
|
|
32619
|
+
const text = await transcribeAudio({ data: file.data, filename, mimeType: file.mimeType });
|
|
32620
|
+
notes.set(file.key, `[Transcript of ${file.name}]
|
|
32621
|
+
${text || "(no speech recognized)"}`);
|
|
32622
|
+
} catch (error) {
|
|
32623
|
+
const reason = scrubSecrets(error instanceof Error ? error.message : String(error));
|
|
32624
|
+
console.warn(`${logPrefix} could not transcribe file ${file.key}: ${reason}`);
|
|
32625
|
+
notes.set(file.key, `(transcription failed: ${reason})`);
|
|
32626
|
+
}
|
|
32627
|
+
}
|
|
32628
|
+
return notes;
|
|
32629
|
+
}
|
|
31921
32630
|
|
|
31922
32631
|
// src/integrations/chat-sdk/attachments.ts
|
|
31923
32632
|
var DRAFT_LEASE_REFRESH_MS = 60000;
|
|
31924
32633
|
var SHARED_FILE_INTENT = "user-upload";
|
|
32634
|
+
var MB = 1024 * 1024;
|
|
32635
|
+
var CHAT_INBOUND_FILE_LIMITS = { telegram: 20 * MB };
|
|
32636
|
+
function chatInboundFileLimit(adapter) {
|
|
32637
|
+
return Math.min(CHAT_INBOUND_FILE_LIMITS[adapter] ?? MAX_TASK_ATTACHMENT_BYTES, MAX_TASK_ATTACHMENT_BYTES);
|
|
32638
|
+
}
|
|
31925
32639
|
function formatFileSize(bytes) {
|
|
31926
32640
|
if (bytes < 1024)
|
|
31927
32641
|
return `${bytes} B`;
|
|
@@ -31942,16 +32656,42 @@ function toChatFiles(adapter, messageId, attachments) {
|
|
|
31942
32656
|
attachment
|
|
31943
32657
|
}));
|
|
31944
32658
|
}
|
|
31945
|
-
function buildChatAttachmentText(files, failed = []) {
|
|
32659
|
+
function buildChatAttachmentText(files, failed = [], notes = new Map) {
|
|
31946
32660
|
const reasons = new Map(failed.map((f) => [f.file.id, f.reason]));
|
|
31947
32661
|
return files.map((f) => {
|
|
31948
32662
|
const size = typeof f.size === "number" ? formatFileSize(f.size) : "unknown size";
|
|
31949
32663
|
const line = `[File: ${f.name} (${f.mimeType ?? "unknown type"}, ${size}) id=${f.id}]`;
|
|
31950
32664
|
const reason = reasons.get(f.id);
|
|
31951
|
-
|
|
32665
|
+
const note = notes.get(f.id);
|
|
32666
|
+
return [reason ? `${line} (not attached: ${reason})` : line, note].filter(Boolean).join(`
|
|
32667
|
+
`);
|
|
31952
32668
|
}).join(`
|
|
31953
32669
|
`);
|
|
31954
32670
|
}
|
|
32671
|
+
function markdownLiteral(value) {
|
|
32672
|
+
const text = value.replace(/[\r\n]+/g, " ");
|
|
32673
|
+
const longestRun = Math.max(0, ...(text.match(/`+/g) ?? []).map((run) => run.length));
|
|
32674
|
+
const fence = "`".repeat(longestRun + 1);
|
|
32675
|
+
const pad = /^[` ]|[` ]$/.test(text) ? " " : "";
|
|
32676
|
+
return `${fence}${pad}${text}${pad}${fence}`;
|
|
32677
|
+
}
|
|
32678
|
+
function formatTooLargeReply(failed) {
|
|
32679
|
+
const lines = failed.map((f) => `- ${markdownLiteral(f.file.name)}: ${f.reason}`);
|
|
32680
|
+
return [
|
|
32681
|
+
`Too large to read, so the swarm did not get ${failed.length === 1 ? "this file" : "these files"}:`,
|
|
32682
|
+
...lines,
|
|
32683
|
+
"Send a smaller file or a link."
|
|
32684
|
+
].join(`
|
|
32685
|
+
`);
|
|
32686
|
+
}
|
|
32687
|
+
async function transcribeChatAudio(fetched) {
|
|
32688
|
+
return transcribeAudioNotes(fetched.filter(({ file }) => file.attachment.type === "audio").map(({ file, path }) => ({
|
|
32689
|
+
key: file.id,
|
|
32690
|
+
name: file.name,
|
|
32691
|
+
data: Bun.file(path),
|
|
32692
|
+
mimeType: file.mimeType
|
|
32693
|
+
})), "[chat-sdk]");
|
|
32694
|
+
}
|
|
31955
32695
|
async function readAttachment(attachment) {
|
|
31956
32696
|
if (attachment.data instanceof Blob)
|
|
31957
32697
|
return new Uint8Array(await attachment.data.arrayBuffer());
|
|
@@ -31975,17 +32715,25 @@ async function fetchChatFiles(files) {
|
|
|
31975
32715
|
};
|
|
31976
32716
|
if (files.length === 0)
|
|
31977
32717
|
return result;
|
|
31978
|
-
const
|
|
32718
|
+
const tooLarge = (file, size) => {
|
|
32719
|
+
const limit = chatInboundFileLimit(file.adapter);
|
|
32720
|
+
const platform = file.adapter.charAt(0).toUpperCase() + file.adapter.slice(1);
|
|
32721
|
+
return {
|
|
32722
|
+
file,
|
|
32723
|
+
reason: `too large (${formatFileSize(size)}, the limit for files sent to the ${platform} bot is ${formatFileSize(limit)})`,
|
|
32724
|
+
tooLarge: true
|
|
32725
|
+
};
|
|
32726
|
+
};
|
|
31979
32727
|
dir = await mkdtemp(join(tmpdir2(), "chat-files-"));
|
|
31980
32728
|
for (const [index, file] of files.entries()) {
|
|
31981
|
-
if (typeof file.size === "number" && file.size >
|
|
31982
|
-
result.failed.push(
|
|
32729
|
+
if (typeof file.size === "number" && file.size > chatInboundFileLimit(file.adapter)) {
|
|
32730
|
+
result.failed.push(tooLarge(file, file.size));
|
|
31983
32731
|
continue;
|
|
31984
32732
|
}
|
|
31985
32733
|
try {
|
|
31986
32734
|
const bytes = await readAttachment(file.attachment);
|
|
31987
|
-
if (bytes.byteLength >
|
|
31988
|
-
result.failed.push(
|
|
32735
|
+
if (bytes.byteLength > chatInboundFileLimit(file.adapter)) {
|
|
32736
|
+
result.failed.push(tooLarge(file, bytes.byteLength));
|
|
31989
32737
|
continue;
|
|
31990
32738
|
}
|
|
31991
32739
|
const path = join(dir, String(index));
|
|
@@ -32075,6 +32823,17 @@ var FALLBACK_LIMIT = 2000;
|
|
|
32075
32823
|
function chatMessageLimit(adapter) {
|
|
32076
32824
|
return CHAT_MESSAGE_LIMITS[adapter] ?? FALLBACK_LIMIT;
|
|
32077
32825
|
}
|
|
32826
|
+
var MB2 = 1024 * 1024;
|
|
32827
|
+
var CHAT_UPLOAD_LIMITS = {
|
|
32828
|
+
telegram: 50 * MB2,
|
|
32829
|
+
discord: 10 * MB2
|
|
32830
|
+
};
|
|
32831
|
+
var FALLBACK_UPLOAD_LIMIT = 50 * MB2;
|
|
32832
|
+
var TELEGRAM_PHOTO_LIMIT = 10 * MB2;
|
|
32833
|
+
function chatUploadLimit(adapter) {
|
|
32834
|
+
return CHAT_UPLOAD_LIMITS[adapter] ?? FALLBACK_UPLOAD_LIMIT;
|
|
32835
|
+
}
|
|
32836
|
+
var CHAT_FILES_PER_MESSAGE = 10;
|
|
32078
32837
|
function splitChatMessage(text, limit) {
|
|
32079
32838
|
if (limit <= 0)
|
|
32080
32839
|
throw new Error("splitChatMessage: limit must be positive");
|
|
@@ -32115,16 +32874,165 @@ function adapterOfChatId(id) {
|
|
|
32115
32874
|
const index = id.indexOf(":");
|
|
32116
32875
|
return index === -1 ? id : id.slice(0, index);
|
|
32117
32876
|
}
|
|
32877
|
+
|
|
32878
|
+
class ChatFileTooLargeError extends Error {
|
|
32879
|
+
sizeBytes;
|
|
32880
|
+
constructor(sizeBytes) {
|
|
32881
|
+
super(`file is ${formatFileSize(sizeBytes)}`);
|
|
32882
|
+
this.sizeBytes = sizeBytes;
|
|
32883
|
+
this.name = "ChatFileTooLargeError";
|
|
32884
|
+
}
|
|
32885
|
+
}
|
|
32886
|
+
var FENCE_LINE = /^ {0,3}(`{3,}|~{3,})/;
|
|
32887
|
+
var NON_HEADING_HASH = /^( {0,3}(?:>[ \t]?)*[ \t]*(?:(?:[-*+]|\d{1,9}[.)])[ \t]+(?:\[[ xX]\][ \t]+)?)?)(#{7,}|#{1,6}(?=[^\s#]))/;
|
|
32888
|
+
function escapeTelegramHashLines(markdown) {
|
|
32889
|
+
let fence;
|
|
32890
|
+
return markdown.split(`
|
|
32891
|
+
`).map((line) => {
|
|
32892
|
+
const marker = FENCE_LINE.exec(line)?.[1];
|
|
32893
|
+
if (fence) {
|
|
32894
|
+
if (marker && marker[0] === fence[0] && marker.length >= fence.length)
|
|
32895
|
+
fence = undefined;
|
|
32896
|
+
return line;
|
|
32897
|
+
}
|
|
32898
|
+
if (marker) {
|
|
32899
|
+
fence = marker;
|
|
32900
|
+
return line;
|
|
32901
|
+
}
|
|
32902
|
+
return line.replace(NON_HEADING_HASH, "$1\\$2");
|
|
32903
|
+
}).join(`
|
|
32904
|
+
`);
|
|
32905
|
+
}
|
|
32118
32906
|
async function postChunks(adapter, target, text) {
|
|
32119
32907
|
const messageIds = [];
|
|
32120
32908
|
let threadId;
|
|
32121
32909
|
for (const chunk of splitChatMessage(text, chatMessageLimit(adapter))) {
|
|
32122
|
-
const
|
|
32910
|
+
const markdown = adapter === "telegram" ? escapeTelegramHashLines(chunk) : chunk;
|
|
32911
|
+
const sent = await target.post({ markdown });
|
|
32123
32912
|
messageIds.push(sent.id);
|
|
32124
32913
|
threadId ??= sent.threadId;
|
|
32125
32914
|
}
|
|
32126
32915
|
return { messageIds, threadId };
|
|
32127
32916
|
}
|
|
32917
|
+
function resolveMimeType(name, ...candidates) {
|
|
32918
|
+
for (const candidate of candidates) {
|
|
32919
|
+
const type = candidate?.split(";")[0]?.trim().toLowerCase();
|
|
32920
|
+
if (type && type !== "application/octet-stream")
|
|
32921
|
+
return type;
|
|
32922
|
+
}
|
|
32923
|
+
return Bun.file(name).type.split(";")[0] ?? "application/octet-stream";
|
|
32924
|
+
}
|
|
32925
|
+
function telegramAttachmentType(mimeType, sizeBytes) {
|
|
32926
|
+
if ((mimeType === "image/jpeg" || mimeType === "image/png") && sizeBytes <= TELEGRAM_PHOTO_LIMIT) {
|
|
32927
|
+
return "image";
|
|
32928
|
+
}
|
|
32929
|
+
if (mimeType === "video/mp4")
|
|
32930
|
+
return "video";
|
|
32931
|
+
if (mimeType === "audio/mpeg" || mimeType === "audio/mp4" || mimeType === "audio/x-m4a") {
|
|
32932
|
+
return "audio";
|
|
32933
|
+
}
|
|
32934
|
+
return "file";
|
|
32935
|
+
}
|
|
32936
|
+
function fileGroupKey(adapter, file) {
|
|
32937
|
+
if (adapter !== "telegram")
|
|
32938
|
+
return "files";
|
|
32939
|
+
const type = telegramAttachmentType(file.mimeType, file.data.byteLength);
|
|
32940
|
+
return type === "image" || type === "video" ? "visual" : type;
|
|
32941
|
+
}
|
|
32942
|
+
function fileMessage(adapter, files) {
|
|
32943
|
+
if (adapter === "telegram") {
|
|
32944
|
+
return {
|
|
32945
|
+
markdown: "",
|
|
32946
|
+
attachments: files.map((file) => ({
|
|
32947
|
+
type: telegramAttachmentType(file.mimeType, file.data.byteLength),
|
|
32948
|
+
name: file.name,
|
|
32949
|
+
mimeType: file.mimeType,
|
|
32950
|
+
size: file.data.byteLength,
|
|
32951
|
+
data: file.data
|
|
32952
|
+
}))
|
|
32953
|
+
};
|
|
32954
|
+
}
|
|
32955
|
+
return {
|
|
32956
|
+
markdown: "",
|
|
32957
|
+
files: files.map((file) => ({ data: file.data, filename: file.name, mimeType: file.mimeType }))
|
|
32958
|
+
};
|
|
32959
|
+
}
|
|
32960
|
+
function platformName(adapter) {
|
|
32961
|
+
return adapter.charAt(0).toUpperCase() + adapter.slice(1);
|
|
32962
|
+
}
|
|
32963
|
+
async function postFiles(adapter, target, files) {
|
|
32964
|
+
const limit = chatUploadLimit(adapter);
|
|
32965
|
+
const tooLarge = (size) => `${formatFileSize(size)}, over the ${formatFileSize(limit)} upload limit of ${platformName(adapter)}`;
|
|
32966
|
+
const messageIds = [];
|
|
32967
|
+
const unsent = [];
|
|
32968
|
+
const groups = new Map;
|
|
32969
|
+
const send = async (group) => {
|
|
32970
|
+
try {
|
|
32971
|
+
const sent = await target.post(fileMessage(adapter, group));
|
|
32972
|
+
messageIds.push(sent.id);
|
|
32973
|
+
} catch (error) {
|
|
32974
|
+
const reason = `refused by ${platformName(adapter)} (${scrubSecrets(errorMessage(error))})`;
|
|
32975
|
+
for (const file of group)
|
|
32976
|
+
unsent.push({ name: file.name, reason });
|
|
32977
|
+
}
|
|
32978
|
+
};
|
|
32979
|
+
for (const file of files) {
|
|
32980
|
+
if (file.sizeBytes !== undefined && file.sizeBytes > limit) {
|
|
32981
|
+
unsent.push({ name: file.name, reason: tooLarge(file.sizeBytes) });
|
|
32982
|
+
continue;
|
|
32983
|
+
}
|
|
32984
|
+
let loaded;
|
|
32985
|
+
try {
|
|
32986
|
+
const { data, mimeType } = await file.load(limit);
|
|
32987
|
+
if (data.byteLength > limit)
|
|
32988
|
+
throw new ChatFileTooLargeError(data.byteLength);
|
|
32989
|
+
loaded = {
|
|
32990
|
+
name: file.name,
|
|
32991
|
+
mimeType: resolveMimeType(file.name, file.mimeType, mimeType),
|
|
32992
|
+
data: Buffer.from(data.buffer, data.byteOffset, data.byteLength)
|
|
32993
|
+
};
|
|
32994
|
+
} catch (error) {
|
|
32995
|
+
unsent.push({
|
|
32996
|
+
name: file.name,
|
|
32997
|
+
reason: error instanceof ChatFileTooLargeError ? tooLarge(error.sizeBytes) : `could not be read (${scrubSecrets(errorMessage(error))})`
|
|
32998
|
+
});
|
|
32999
|
+
continue;
|
|
33000
|
+
}
|
|
33001
|
+
const key = fileGroupKey(adapter, loaded);
|
|
33002
|
+
const group = [...groups.get(key) ?? [], loaded];
|
|
33003
|
+
if (group.length === CHAT_FILES_PER_MESSAGE) {
|
|
33004
|
+
groups.delete(key);
|
|
33005
|
+
await send(group);
|
|
33006
|
+
} else {
|
|
33007
|
+
groups.set(key, group);
|
|
33008
|
+
}
|
|
33009
|
+
}
|
|
33010
|
+
for (const group of groups.values())
|
|
33011
|
+
await send(group);
|
|
33012
|
+
return { messageIds, unsent };
|
|
33013
|
+
}
|
|
33014
|
+
function unsentFilesSummary(unsent) {
|
|
33015
|
+
return unsent.length === 0 ? "" : ` ${formatUnsentFilesNote(unsent)}`;
|
|
33016
|
+
}
|
|
33017
|
+
function singleLine(text) {
|
|
33018
|
+
return text.replace(/[\u0000-\u001f\u007f\u2028\u2029]+/g, " ").trim();
|
|
33019
|
+
}
|
|
33020
|
+
function breakMentions(text) {
|
|
33021
|
+
return text.replace(/@/g, "@").replace(/<!/g, "<!");
|
|
33022
|
+
}
|
|
33023
|
+
function codeSpan(text) {
|
|
33024
|
+
const value = breakMentions(singleLine(text)) || "(unnamed)";
|
|
33025
|
+
const longestRun = Math.max(0, ...(value.match(/`+/g) ?? []).map((run) => run.length));
|
|
33026
|
+
const fence = "`".repeat(longestRun + 1);
|
|
33027
|
+
const pad = value.startsWith("`") || value.endsWith("`") ? " " : "";
|
|
33028
|
+
return `${fence}${pad}${value}${pad}${fence}`;
|
|
33029
|
+
}
|
|
33030
|
+
function formatUnsentFilesNote(unsent) {
|
|
33031
|
+
const lines = unsent.map((file) => `- ${codeSpan(file.name)}: ${breakMentions(singleLine(file.reason))}`);
|
|
33032
|
+
const count = unsent.length === 1 ? "1 file" : `${unsent.length} files`;
|
|
33033
|
+
return [`Could not send ${count}:`, ...lines].join(`
|
|
33034
|
+
`);
|
|
33035
|
+
}
|
|
32128
33036
|
async function postChatMessage(args) {
|
|
32129
33037
|
assertTrustedChatTarget(args.threadId ?? args.channelId ?? "");
|
|
32130
33038
|
const chat = getChatInstance(args.adapter);
|
|
@@ -32132,27 +33040,42 @@ async function postChatMessage(args) {
|
|
|
32132
33040
|
throw new ChatAdapterUnavailableError(args.adapter);
|
|
32133
33041
|
const text = scrubSecrets(args.text);
|
|
32134
33042
|
let result;
|
|
33043
|
+
let target;
|
|
32135
33044
|
if (args.threadId) {
|
|
32136
33045
|
const thread = chat.thread(args.threadId);
|
|
33046
|
+
target = thread;
|
|
32137
33047
|
const sent = await postChunks(args.adapter, thread, text);
|
|
32138
33048
|
result = {
|
|
32139
33049
|
adapter: args.adapter,
|
|
32140
33050
|
threadId: thread.id,
|
|
32141
33051
|
channelId: thread.channelId,
|
|
32142
|
-
messageIds: sent.messageIds
|
|
33052
|
+
messageIds: sent.messageIds,
|
|
33053
|
+
unsentFiles: []
|
|
32143
33054
|
};
|
|
32144
33055
|
} else if (args.channelId) {
|
|
32145
33056
|
const channel = chat.channel(args.channelId);
|
|
33057
|
+
target = channel;
|
|
32146
33058
|
const sent = await postChunks(args.adapter, channel, text);
|
|
32147
33059
|
result = {
|
|
32148
33060
|
adapter: args.adapter,
|
|
32149
33061
|
threadId: sent.threadId ?? channel.id,
|
|
32150
33062
|
channelId: channel.id,
|
|
32151
|
-
messageIds: sent.messageIds
|
|
33063
|
+
messageIds: sent.messageIds,
|
|
33064
|
+
unsentFiles: []
|
|
32152
33065
|
};
|
|
32153
33066
|
} else {
|
|
32154
33067
|
throw new Error("postChatMessage needs a threadId or a channelId");
|
|
32155
33068
|
}
|
|
33069
|
+
if (args.files?.length) {
|
|
33070
|
+
const sent = await postFiles(args.adapter, target, args.files);
|
|
33071
|
+
result.messageIds.push(...sent.messageIds);
|
|
33072
|
+
result.unsentFiles = sent.unsent;
|
|
33073
|
+
if (sent.unsent.length > 0) {
|
|
33074
|
+
const note = formatUnsentFilesNote(sent.unsent);
|
|
33075
|
+
const noted = await postChunks(args.adapter, target, scrubSecrets(note));
|
|
33076
|
+
result.messageIds.push(...noted.messageIds);
|
|
33077
|
+
}
|
|
33078
|
+
}
|
|
32156
33079
|
emitChatMessageSent({
|
|
32157
33080
|
adapter: result.adapter,
|
|
32158
33081
|
channelId: result.channelId,
|
|
@@ -32218,9 +33141,19 @@ async function putChatChannelMapping(adapter, channelId, mapping) {
|
|
|
32218
33141
|
async function deleteChatChannelMapping(adapter, channelId) {
|
|
32219
33142
|
return deleteKv2(CHAT_CHANNELS_NAMESPACE, chatChannelKey(adapter, channelId));
|
|
32220
33143
|
}
|
|
33144
|
+
function hasRoutingToken(text) {
|
|
33145
|
+
return /swarm#(?:[a-f0-9-]{36}|all)/i.test(text);
|
|
33146
|
+
}
|
|
32221
33147
|
function stripRoutingTokens(text) {
|
|
32222
33148
|
return text.replace(/swarm#[a-f0-9-]{36}/gi, "").replace(/swarm#all/gi, "").trim();
|
|
32223
33149
|
}
|
|
33150
|
+
var DEFAULT_OWNER_WINDOW_MINUTES = 15;
|
|
33151
|
+
function chatOwnerWindowStart(now = Date.now()) {
|
|
33152
|
+
const raw = process.env.CHAT_SDK_OWNER_WINDOW_MIN?.trim();
|
|
33153
|
+
const value = raw ? Number(raw) : Number.NaN;
|
|
33154
|
+
const minutes = Number.isFinite(value) && value >= 0 ? value : DEFAULT_OWNER_WINDOW_MINUTES;
|
|
33155
|
+
return new Date(now - minutes * 60000).toISOString();
|
|
33156
|
+
}
|
|
32224
33157
|
async function leadMatch(reachable, matchedText) {
|
|
32225
33158
|
const lead = reachable.find((agent) => agent.isLead) ?? await getLeadAgent2();
|
|
32226
33159
|
return { agent: lead, reason: "skill", matchedText };
|
|
@@ -32262,7 +33195,7 @@ async function routeChatMessage(text, ctx) {
|
|
|
32262
33195
|
}
|
|
32263
33196
|
console.warn(scrubSecrets(`[chat-sdk] Channel mapping for ${ctx.channelId} names unknown agent ${mapping.agentId}; using the default route`));
|
|
32264
33197
|
}
|
|
32265
|
-
const owner = await getAgentWorkingOnContextKey2(chatSdkContextKey(ctx.threadId), "chat");
|
|
33198
|
+
const owner = await getAgentWorkingOnContextKey2(chatSdkContextKey(ctx.threadId), "chat", ctx.adapter === "telegram" && !ctx.isDirectMessage ? chatOwnerWindowStart() : undefined);
|
|
32266
33199
|
if (owner && await isAgentReachable(owner)) {
|
|
32267
33200
|
return {
|
|
32268
33201
|
kind: "agents",
|
|
@@ -32292,6 +33225,9 @@ async function requestChatThreadSteering(args) {
|
|
|
32292
33225
|
const task = await getLatestLeadTaskByContextKey2(args.contextKey, "chat");
|
|
32293
33226
|
if (!task || task.status !== "in_progress")
|
|
32294
33227
|
return null;
|
|
33228
|
+
const senderUserId = await args.resolveSender();
|
|
33229
|
+
if (senderUserId !== task.requestedByUserId)
|
|
33230
|
+
return null;
|
|
32295
33231
|
try {
|
|
32296
33232
|
const result = await requestSteering({
|
|
32297
33233
|
taskId: task.id,
|
|
@@ -32299,7 +33235,8 @@ async function requestChatThreadSteering(args) {
|
|
|
32299
33235
|
mode: "queue",
|
|
32300
33236
|
onUnsupported: "degrade",
|
|
32301
33237
|
source: "chat",
|
|
32302
|
-
createdByKind: "user"
|
|
33238
|
+
createdByKind: "user",
|
|
33239
|
+
createdByUserId: senderUserId
|
|
32303
33240
|
});
|
|
32304
33241
|
return { task, result };
|
|
32305
33242
|
} catch (error) {
|
|
@@ -32393,6 +33330,18 @@ registerTemplate({
|
|
|
32393
33330
|
],
|
|
32394
33331
|
category: "system"
|
|
32395
33332
|
});
|
|
33333
|
+
registerTemplate({
|
|
33334
|
+
eventType: "chat.message.header",
|
|
33335
|
+
header: "",
|
|
33336
|
+
defaultBody: "[chat] {{chat_facts}}",
|
|
33337
|
+
variables: [
|
|
33338
|
+
{
|
|
33339
|
+
name: "chat_facts",
|
|
33340
|
+
description: "Adapter, chat type and title, forum topic, sender, why the message was taken (addressed) and the replied-to snippet, joined with ' · '"
|
|
33341
|
+
}
|
|
33342
|
+
],
|
|
33343
|
+
category: "system"
|
|
33344
|
+
});
|
|
32396
33345
|
|
|
32397
33346
|
// src/integrations/chat-sdk/inbound.ts
|
|
32398
33347
|
var ChatRouteModifySchema = object2({
|
|
@@ -32437,10 +33386,24 @@ async function handleChatInbound(thread, message, kind) {
|
|
|
32437
33386
|
if (immediate)
|
|
32438
33387
|
text = text.replace(/^!now\s*/i, "").trim();
|
|
32439
33388
|
const attachments = message.attachments ?? [];
|
|
33389
|
+
const facts = readChatMessageFacts(thread, message);
|
|
33390
|
+
const isDirectMessage = kind === "dm" || thread.isDM;
|
|
33391
|
+
const mentioned = kind === "mention" || message.isMention === true;
|
|
33392
|
+
let addressed = isDirectMessage ? "dm" : facts.replyToBot ? "reply-to-bot" : mentioned ? "mention" : "none";
|
|
33393
|
+
if (addressed === "none" && (facts.chatType === "group" || facts.chatType === "supergroup")) {
|
|
33394
|
+
const unaddressed = await classifyUnaddressedGroupMessage(thread, message.author.userId, text);
|
|
33395
|
+
if (unaddressed === "chatter") {
|
|
33396
|
+
console.log(`[chat-sdk] ${thread.id}: unaddressed group message from a non-requester, ignored`);
|
|
33397
|
+
return;
|
|
33398
|
+
}
|
|
33399
|
+
if (unaddressed === "requester-follow-up")
|
|
33400
|
+
addressed = unaddressed;
|
|
33401
|
+
}
|
|
32440
33402
|
if (!immediate && attachments.length === 0 && text && !isChatThreadBuffered(thread.id)) {
|
|
32441
33403
|
const steering = await requestChatThreadSteering({
|
|
32442
33404
|
contextKey: chatSdkContextKey(thread.id),
|
|
32443
|
-
message: text
|
|
33405
|
+
message: text,
|
|
33406
|
+
resolveSender: () => resolveChatSender(adapter, message.author.userId)
|
|
32444
33407
|
});
|
|
32445
33408
|
if (steering) {
|
|
32446
33409
|
console.log(`[chat-sdk] ${adapter} message steered task ${steering.task.id} (${steering.result.outcome})`);
|
|
@@ -32469,8 +33432,10 @@ async function handleChatInbound(thread, message, kind) {
|
|
|
32469
33432
|
text,
|
|
32470
33433
|
userId: message.author.userId,
|
|
32471
33434
|
userName: message.author.userName || undefined,
|
|
32472
|
-
botMentioned:
|
|
32473
|
-
isDirectMessage
|
|
33435
|
+
botMentioned: mentioned || facts.replyToBot,
|
|
33436
|
+
isDirectMessage,
|
|
33437
|
+
addressed,
|
|
33438
|
+
facts,
|
|
32474
33439
|
attachments
|
|
32475
33440
|
});
|
|
32476
33441
|
if (kind !== "subscribed")
|
|
@@ -32479,6 +33444,47 @@ async function handleChatInbound(thread, message, kind) {
|
|
|
32479
33444
|
if (immediate)
|
|
32480
33445
|
await instantFlushChat(thread.id);
|
|
32481
33446
|
}
|
|
33447
|
+
var REQUESTER_KEY_PREFIX = "swarm:requester:";
|
|
33448
|
+
var REQUESTER_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
33449
|
+
async function rememberChatThreadRequester(threadId, userId) {
|
|
33450
|
+
try {
|
|
33451
|
+
await new SqliteChatState().set(`${REQUESTER_KEY_PREFIX}${threadId}`, userId, REQUESTER_TTL_MS);
|
|
33452
|
+
} catch (error) {
|
|
33453
|
+
console.warn(`[chat-sdk] Could not store the thread requester: ${errorMessage(error)}`);
|
|
33454
|
+
}
|
|
33455
|
+
}
|
|
33456
|
+
async function classifyUnaddressedGroupMessage(thread, senderId, text) {
|
|
33457
|
+
if (hasRoutingToken(text))
|
|
33458
|
+
return "routable";
|
|
33459
|
+
if ((await getChatChannelMapping(thread.adapter.name, thread.channelId))?.agentId) {
|
|
33460
|
+
return "routable";
|
|
33461
|
+
}
|
|
33462
|
+
const owner = await getAgentWorkingOnContextKey2(chatSdkContextKey(thread.id), "chat", chatOwnerWindowStart());
|
|
33463
|
+
if (!owner)
|
|
33464
|
+
return "chatter";
|
|
33465
|
+
const requester = await new SqliteChatState().get(`${REQUESTER_KEY_PREFIX}${thread.id}`);
|
|
33466
|
+
return requester === senderId ? "requester-follow-up" : "chatter";
|
|
33467
|
+
}
|
|
33468
|
+
async function resolveChatRequester(adapter, item) {
|
|
33469
|
+
return resolveChatSender(adapter, item.userId, {
|
|
33470
|
+
sampleEventType: "chat.message",
|
|
33471
|
+
sampleContext: `${item.facts.from}: ${item.text}`
|
|
33472
|
+
});
|
|
33473
|
+
}
|
|
33474
|
+
async function resolveChatSender(adapter, userId, sample) {
|
|
33475
|
+
if (!userId || userId.startsWith("chat:"))
|
|
33476
|
+
return;
|
|
33477
|
+
try {
|
|
33478
|
+
const resolution = await resolveIdentity(adapter, userId);
|
|
33479
|
+
if (resolution.status === "resolved")
|
|
33480
|
+
return resolution.userId;
|
|
33481
|
+
if (sample)
|
|
33482
|
+
await recordUnmappedIdentity(adapter, userId, sample);
|
|
33483
|
+
} catch (error) {
|
|
33484
|
+
console.warn(`[chat-sdk] Could not resolve the requester: ${errorMessage(error)}`);
|
|
33485
|
+
}
|
|
33486
|
+
return;
|
|
33487
|
+
}
|
|
32482
33488
|
async function getChatThreadContext(thread, exclude, since) {
|
|
32483
33489
|
try {
|
|
32484
33490
|
await thread.refresh();
|
|
@@ -32549,6 +33555,8 @@ async function flushChatThread(threadId, items, immediate) {
|
|
|
32549
33555
|
`);
|
|
32550
33556
|
const botMentioned = items.some((item) => item.botMentioned);
|
|
32551
33557
|
const isDirectMessage = items.some((item) => item.isDirectMessage);
|
|
33558
|
+
const requester = items.find((item) => item.addressed !== "none") ?? first;
|
|
33559
|
+
const otherSenders = new Set(items.map((item) => item.userId)).size - 1;
|
|
32552
33560
|
const resetAt = await getChatThreadResetAt(threadId);
|
|
32553
33561
|
const previousTask = await getLatestTaskByContextKey2(contextKey);
|
|
32554
33562
|
const mostRecentTask = previousTask && resetAt && new Date(previousTask.createdAt).getTime() <= resetAt.getTime() ? null : previousTask;
|
|
@@ -32561,6 +33569,9 @@ async function flushChatThread(threadId, items, immediate) {
|
|
|
32561
33569
|
text: rawText,
|
|
32562
33570
|
botMentioned,
|
|
32563
33571
|
isDirectMessage,
|
|
33572
|
+
...first.facts.chatType ? { chatType: first.facts.chatType } : {},
|
|
33573
|
+
...first.facts.isForum ? { isForum: true } : {},
|
|
33574
|
+
replyToBot: items.some((item) => item.facts.replyToBot),
|
|
32564
33575
|
...mostRecentTask ? { threadContext: { adapter, threadId } } : {}
|
|
32565
33576
|
}, {
|
|
32566
33577
|
validateModify: (data) => {
|
|
@@ -32611,7 +33622,16 @@ async function flushChatThread(threadId, items, immediate) {
|
|
|
32611
33622
|
const body = stripRoutingTokens(rawText);
|
|
32612
33623
|
const files = items.flatMap((item) => toChatFiles(adapter, item.messageId, item.attachments));
|
|
32613
33624
|
const inbound = __using(__stack, await fetchChatFiles(files), 1);
|
|
32614
|
-
const
|
|
33625
|
+
const tooLarge = inbound.failed.filter((failure) => failure.tooLarge);
|
|
33626
|
+
if (tooLarge.length > 0) {
|
|
33627
|
+
try {
|
|
33628
|
+
await postChatMessage({ adapter, threadId, text: formatTooLargeReply(tooLarge) });
|
|
33629
|
+
} catch (error) {
|
|
33630
|
+
console.warn(`[chat-sdk] ${threadId}: could not post the too-large reply: ${errorMessage(error)}`);
|
|
33631
|
+
}
|
|
33632
|
+
}
|
|
33633
|
+
const notes = await transcribeChatAudio(inbound.fetched);
|
|
33634
|
+
const fileText = buildChatAttachmentText(inbound.files, inbound.failed, notes);
|
|
32615
33635
|
const combined = [body, fileText].filter(Boolean).join(`
|
|
32616
33636
|
|
|
32617
33637
|
`);
|
|
@@ -32619,9 +33639,17 @@ async function flushChatThread(threadId, items, immediate) {
|
|
|
32619
33639
|
|
|
32620
33640
|
${combined}` : combined;
|
|
32621
33641
|
const threadContext = mostRecentTask && thread ? await getChatThreadContext(thread, new Set(items.map((item) => item.messageId)), resetAt) : "";
|
|
32622
|
-
const
|
|
33642
|
+
const header = resolveTemplate("chat.message.header", {
|
|
33643
|
+
chat_facts: formatChatHeaderFacts(adapter, otherSenders > 0 ? { ...requester.facts, from: `${requester.facts.from} +${otherSenders} more` } : requester.facts, requester.addressed)
|
|
33644
|
+
}).text;
|
|
33645
|
+
const description = [
|
|
33646
|
+
header,
|
|
33647
|
+
threadContext ? resolveTemplate("chat.message.thread_context", { thread_messages: threadContext }).text : "",
|
|
33648
|
+
marked
|
|
33649
|
+
].filter(Boolean).join(`
|
|
32623
33650
|
|
|
32624
|
-
|
|
33651
|
+
`);
|
|
33652
|
+
const requestedByUserId = otherSenders > 0 ? undefined : await resolveChatRequester(adapter, requester);
|
|
32625
33653
|
const latestActive = await getLatestActiveTaskByContextKey2(contextKey, "chat");
|
|
32626
33654
|
const dependsOn = !immediate && latestActive ? [latestActive.id] : undefined;
|
|
32627
33655
|
let created = 0;
|
|
@@ -32636,7 +33664,9 @@ ${marked}` : marked;
|
|
|
32636
33664
|
priority: 70,
|
|
32637
33665
|
contextKey,
|
|
32638
33666
|
dependsOn,
|
|
33667
|
+
requestedByUserId,
|
|
32639
33668
|
parentTaskId: mostRecentTask?.id,
|
|
33669
|
+
inheritParentRequester: false,
|
|
32640
33670
|
inheritParentOutputSchema: false
|
|
32641
33671
|
};
|
|
32642
33672
|
try {
|
|
@@ -32652,6 +33682,7 @@ ${marked}` : marked;
|
|
|
32652
33682
|
}
|
|
32653
33683
|
}
|
|
32654
33684
|
if (created > 0) {
|
|
33685
|
+
await rememberChatThreadRequester(threadId, requester.userId);
|
|
32655
33686
|
await subscribe(thread);
|
|
32656
33687
|
startTypingKeepalive(adapter, threadId);
|
|
32657
33688
|
} else {
|
|
@@ -32697,6 +33728,127 @@ init_db3();
|
|
|
32697
33728
|
init_context_key();
|
|
32698
33729
|
init_secret_scrubber();
|
|
32699
33730
|
init_event_bus();
|
|
33731
|
+
|
|
33732
|
+
// src/integrations/chat-sdk/outbound-files.ts
|
|
33733
|
+
init_db3();
|
|
33734
|
+
init_secret_scrubber();
|
|
33735
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
33736
|
+
async function download(scope, maxBytes, provider = getFileStorageProvider2()) {
|
|
33737
|
+
const response = await provider.download(scope);
|
|
33738
|
+
const length = Number(response.headers.get("content-length"));
|
|
33739
|
+
if (Number.isFinite(length) && length > maxBytes) {
|
|
33740
|
+
await response.body?.cancel();
|
|
33741
|
+
throw new ChatFileTooLargeError(length);
|
|
33742
|
+
}
|
|
33743
|
+
const data = new Uint8Array(await response.arrayBuffer());
|
|
33744
|
+
if (data.byteLength > maxBytes)
|
|
33745
|
+
throw new ChatFileTooLargeError(data.byteLength);
|
|
33746
|
+
return { data, mimeType: response.headers.get("content-type") ?? undefined };
|
|
33747
|
+
}
|
|
33748
|
+
function chatFileOfTaskAttachment(attachment) {
|
|
33749
|
+
if (backingProviderId(attachment) !== getFileStorageProvider2().id)
|
|
33750
|
+
return;
|
|
33751
|
+
return {
|
|
33752
|
+
name: attachment.name,
|
|
33753
|
+
mimeType: attachment.mimeType,
|
|
33754
|
+
sizeBytes: attachment.sizeBytes,
|
|
33755
|
+
load: (maxBytes) => download(scopeFromAttachment(attachment), maxBytes)
|
|
33756
|
+
};
|
|
33757
|
+
}
|
|
33758
|
+
function pathSegments(path) {
|
|
33759
|
+
return normalizeStoredKey(path).split("/").map((segment) => {
|
|
33760
|
+
let decoded = segment;
|
|
33761
|
+
try {
|
|
33762
|
+
decoded = decodeURIComponent(segment);
|
|
33763
|
+
} catch {}
|
|
33764
|
+
if (!decoded || decoded === "." || decoded === ".." || /[/\\\0]/.test(decoded)) {
|
|
33765
|
+
throw new FilesError("Provider", "Path must not contain empty, `.` or `..` segments, or encoded separators");
|
|
33766
|
+
}
|
|
33767
|
+
return decoded;
|
|
33768
|
+
});
|
|
33769
|
+
}
|
|
33770
|
+
async function callerAgentFs(agentId) {
|
|
33771
|
+
if (!agentId)
|
|
33772
|
+
return;
|
|
33773
|
+
const configs = await getResolvedConfig2(agentId);
|
|
33774
|
+
const value = (key) => configs.find((c) => c.key === key)?.value?.trim();
|
|
33775
|
+
const apiUrl = value("AGENT_FS_API_URL") || process.env.AGENT_FS_API_URL?.trim();
|
|
33776
|
+
const apiKey = value("AGENT_FS_API_KEY");
|
|
33777
|
+
const orgId = value("AGENT_FS_DEFAULT_ORG_ID");
|
|
33778
|
+
const driveId = value("AGENT_FS_DEFAULT_DRIVE_ID");
|
|
33779
|
+
return apiUrl && apiKey && orgId && driveId ? { apiUrl, apiKey, orgId, driveId } : undefined;
|
|
33780
|
+
}
|
|
33781
|
+
function chatFileOfPath(path, access) {
|
|
33782
|
+
const segments = pathSegments(path);
|
|
33783
|
+
const name = segments.at(-1);
|
|
33784
|
+
const key = segments.map(encodeURIComponent).join("/");
|
|
33785
|
+
const keyScrubber = createValueScrubber([{ value: access.apiKey, name: "AGENT_FS_API_KEY" }]);
|
|
33786
|
+
return {
|
|
33787
|
+
name,
|
|
33788
|
+
load: async (maxBytes) => {
|
|
33789
|
+
try {
|
|
33790
|
+
return await download({ taskId: "chat", name, key, orgId: access.orgId, driveId: access.driveId }, maxBytes, new AgentFsProvider(access));
|
|
33791
|
+
} catch (error) {
|
|
33792
|
+
if (error instanceof ChatFileTooLargeError)
|
|
33793
|
+
throw error;
|
|
33794
|
+
if (error instanceof FilesError && error.code === "Unauthorized") {
|
|
33795
|
+
throw new Error("your agent-fs credential cannot read this path");
|
|
33796
|
+
}
|
|
33797
|
+
throw new Error(keyScrubber.text(error instanceof Error ? error.message : String(error)));
|
|
33798
|
+
}
|
|
33799
|
+
}
|
|
33800
|
+
};
|
|
33801
|
+
}
|
|
33802
|
+
async function resolveChatAttachmentRefs(refs, taskId, agentId) {
|
|
33803
|
+
let taskAttachments;
|
|
33804
|
+
let access = null;
|
|
33805
|
+
const files = [];
|
|
33806
|
+
for (const ref of refs) {
|
|
33807
|
+
if (UUID_PATTERN.test(ref)) {
|
|
33808
|
+
if (!taskId)
|
|
33809
|
+
return { error: `Attachment ${ref}: no current task to look it up in.` };
|
|
33810
|
+
taskAttachments ??= await getTaskAttachments2(taskId);
|
|
33811
|
+
const attachment = taskAttachments.find((a) => a.id === ref);
|
|
33812
|
+
if (!attachment)
|
|
33813
|
+
return { error: `Attachment ${ref} is not an attachment of task ${taskId}.` };
|
|
33814
|
+
const file = chatFileOfTaskAttachment(attachment);
|
|
33815
|
+
if (!file) {
|
|
33816
|
+
return {
|
|
33817
|
+
error: `Attachment ${ref} (${attachment.kind}) is not stored in the swarm file provider, so it cannot be sent as a file. Post its link instead.`
|
|
33818
|
+
};
|
|
33819
|
+
}
|
|
33820
|
+
files.push(file);
|
|
33821
|
+
continue;
|
|
33822
|
+
}
|
|
33823
|
+
if (access === null)
|
|
33824
|
+
access = await callerAgentFs(agentId);
|
|
33825
|
+
if (!access) {
|
|
33826
|
+
return {
|
|
33827
|
+
error: `Path ${ref}: you have no agent-fs credential and drive to read it with. Attach the file to your task and send its attachment id.`
|
|
33828
|
+
};
|
|
33829
|
+
}
|
|
33830
|
+
try {
|
|
33831
|
+
files.push(chatFileOfPath(ref, access));
|
|
33832
|
+
} catch (error) {
|
|
33833
|
+
return { error: `Path ${ref}: ${errorMessage(error)}` };
|
|
33834
|
+
}
|
|
33835
|
+
}
|
|
33836
|
+
return { files };
|
|
33837
|
+
}
|
|
33838
|
+
var FETCHED_SLACK_FILE_INTENT = "slack-file";
|
|
33839
|
+
async function taskOutputChatFiles(taskId) {
|
|
33840
|
+
return (await getTaskAttachments2(taskId)).flatMap((attachment) => {
|
|
33841
|
+
if (attachment.agentId === null)
|
|
33842
|
+
return [];
|
|
33843
|
+
if (attachment.intent === SHARED_FILE_INTENT || attachment.intent === FETCHED_SLACK_FILE_INTENT) {
|
|
33844
|
+
return [];
|
|
33845
|
+
}
|
|
33846
|
+
const file = chatFileOfTaskAttachment(attachment);
|
|
33847
|
+
return file ? [file] : [];
|
|
33848
|
+
});
|
|
33849
|
+
}
|
|
33850
|
+
|
|
33851
|
+
// src/integrations/chat-sdk/relay.ts
|
|
32700
33852
|
var RELAY_GIVE_UP_AFTER_MS = 24 * 60 * 60 * 1000;
|
|
32701
33853
|
var SWEEP_EVERY_N_TICKS = 20;
|
|
32702
33854
|
var EARLY_TICK_DEBOUNCE_MS = 250;
|
|
@@ -32746,7 +33898,8 @@ async function processPendingChatRelays(now = Date.now(), signal) {
|
|
|
32746
33898
|
adapter: target.adapter,
|
|
32747
33899
|
threadId: target.threadId,
|
|
32748
33900
|
text: formatChatRelayText(task),
|
|
32749
|
-
taskId: task.id
|
|
33901
|
+
taskId: task.id,
|
|
33902
|
+
files: await taskOutputChatFiles(task.id)
|
|
32750
33903
|
});
|
|
32751
33904
|
stopTypingKeepalive(target.threadId);
|
|
32752
33905
|
await markChatRelayDelivered2(task.id, now);
|
|
@@ -33404,43 +34557,6 @@ Original issue: {{issue_key}} — {{issue_summary}}`,
|
|
|
33404
34557
|
// src/jira/sync.ts
|
|
33405
34558
|
init_db3();
|
|
33406
34559
|
init_oauth();
|
|
33407
|
-
|
|
33408
|
-
// src/be/unmapped-identities.ts
|
|
33409
|
-
init_db3();
|
|
33410
|
-
var TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
33411
|
-
function namespace(kind) {
|
|
33412
|
-
return `integration:unmapped:${kind}`;
|
|
33413
|
-
}
|
|
33414
|
-
async function recordUnmappedIdentity(kind, externalId, meta) {
|
|
33415
|
-
const ns = namespace(kind);
|
|
33416
|
-
const now = new Date().toISOString();
|
|
33417
|
-
const expiresAt = Date.now() + TTL_MS;
|
|
33418
|
-
const countKey = `${externalId}:count`;
|
|
33419
|
-
const countBefore = await getKv2(ns, countKey);
|
|
33420
|
-
await upsertKv2({
|
|
33421
|
-
namespace: ns,
|
|
33422
|
-
key: `${externalId}:meta`,
|
|
33423
|
-
value: {
|
|
33424
|
-
lastSeenAt: now,
|
|
33425
|
-
sampleEventType: meta.sampleEventType,
|
|
33426
|
-
sampleContext: meta.sampleContext.slice(0, 100)
|
|
33427
|
-
},
|
|
33428
|
-
valueType: "json",
|
|
33429
|
-
expiresAt
|
|
33430
|
-
});
|
|
33431
|
-
const incremented = await incrKv2(ns, countKey, 1);
|
|
33432
|
-
if (countBefore === null) {
|
|
33433
|
-
await upsertKv2({
|
|
33434
|
-
namespace: ns,
|
|
33435
|
-
key: countKey,
|
|
33436
|
-
value: Number(incremented.value),
|
|
33437
|
-
valueType: "integer",
|
|
33438
|
-
expiresAt
|
|
33439
|
-
});
|
|
33440
|
-
}
|
|
33441
|
-
}
|
|
33442
|
-
|
|
33443
|
-
// src/jira/sync.ts
|
|
33444
34560
|
init_users();
|
|
33445
34561
|
init_resolver();
|
|
33446
34562
|
init_context_key();
|
|
@@ -33524,7 +34640,7 @@ async function resolveBotAccountId() {
|
|
|
33524
34640
|
function resetBotAccountIdCache() {
|
|
33525
34641
|
setCachedBotAccountId(null);
|
|
33526
34642
|
}
|
|
33527
|
-
async function
|
|
34643
|
+
async function findLeadAgent6() {
|
|
33528
34644
|
const agents = await getAllAgents2();
|
|
33529
34645
|
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
33530
34646
|
if (onlineLead)
|
|
@@ -33728,7 +34844,7 @@ async function handleIssueDeleteEvent(event) {
|
|
|
33728
34844
|
}
|
|
33729
34845
|
}
|
|
33730
34846
|
async function createInitialJiraTask(input) {
|
|
33731
|
-
const lead = await
|
|
34847
|
+
const lead = await findLeadAgent6();
|
|
33732
34848
|
const descriptionSection = input.descriptionText ? `
|
|
33733
34849
|
Description:
|
|
33734
34850
|
${input.descriptionText}
|
|
@@ -33766,7 +34882,7 @@ ${input.descriptionText}
|
|
|
33766
34882
|
console.log(`[Jira Sync] Created ${action} task ${task.id} for ${input.issueKey} -> ${lead?.name ?? "unassigned"}`);
|
|
33767
34883
|
}
|
|
33768
34884
|
async function createCommentMentionTask(input) {
|
|
33769
|
-
const lead = await
|
|
34885
|
+
const lead = await findLeadAgent6();
|
|
33770
34886
|
const descriptionSection = input.descriptionText ? `
|
|
33771
34887
|
Description:
|
|
33772
34888
|
${input.descriptionText}
|
|
@@ -33826,7 +34942,7 @@ async function notifySlack(text) {
|
|
|
33826
34942
|
return;
|
|
33827
34943
|
}
|
|
33828
34944
|
try {
|
|
33829
|
-
const { getSlackApp } = await import("./app-
|
|
34945
|
+
const { getSlackApp } = await import("./app-0qp0a2gk.js");
|
|
33830
34946
|
const app = getSlackApp();
|
|
33831
34947
|
if (!app) {
|
|
33832
34948
|
console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
|
|
@@ -33897,7 +35013,7 @@ async function deleteJiraWebhook(webhookId) {
|
|
|
33897
35013
|
console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
|
|
33898
35014
|
}
|
|
33899
35015
|
async function overwriteWebhookIds(next) {
|
|
33900
|
-
const { getDbClient } = await import("./db-
|
|
35016
|
+
const { getDbClient } = await import("./db-7gbc53fd.js");
|
|
33901
35017
|
await getDbClient().transaction(async (tx) => {
|
|
33902
35018
|
const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
|
|
33903
35019
|
if (!row) {
|
|
@@ -34004,7 +35120,7 @@ function stopJiraWebhookKeepalive() {
|
|
|
34004
35120
|
}
|
|
34005
35121
|
|
|
34006
35122
|
// src/jira/app.ts
|
|
34007
|
-
var
|
|
35123
|
+
var initialized6 = false;
|
|
34008
35124
|
function isJiraEnabled() {
|
|
34009
35125
|
if (isEnvFlagEnabled("JIRA_DISABLE", false))
|
|
34010
35126
|
return false;
|
|
@@ -34016,12 +35132,12 @@ function resetJira() {
|
|
|
34016
35132
|
resetBotAccountIdCache();
|
|
34017
35133
|
teardownJiraOutboundSync();
|
|
34018
35134
|
stopJiraWebhookKeepalive();
|
|
34019
|
-
|
|
35135
|
+
initialized6 = false;
|
|
34020
35136
|
}
|
|
34021
35137
|
async function initJira() {
|
|
34022
|
-
if (
|
|
35138
|
+
if (initialized6)
|
|
34023
35139
|
return isJiraEnabled();
|
|
34024
|
-
|
|
35140
|
+
initialized6 = true;
|
|
34025
35141
|
if (!isJiraEnabled()) {
|
|
34026
35142
|
console.log("[Jira] Integration disabled or JIRA_CLIENT_ID not set");
|
|
34027
35143
|
return false;
|
|
@@ -34078,7 +35194,7 @@ function synthesizeDeliveryId(body, rawBody) {
|
|
|
34078
35194
|
const hash = createHash2("sha256").update(rawBody).digest("hex").slice(0, 16);
|
|
34079
35195
|
return `${event}:${ts}:${entityId}:${hash}`;
|
|
34080
35196
|
}
|
|
34081
|
-
async function
|
|
35197
|
+
async function isDuplicateDelivery2(deliveryId) {
|
|
34082
35198
|
return await hasTrackerDelivery("jira", deliveryId);
|
|
34083
35199
|
}
|
|
34084
35200
|
async function markDelivery(externalId, deliveryId) {
|
|
@@ -34101,7 +35217,7 @@ async function handleJiraWebhook(pathToken, rawBody) {
|
|
|
34101
35217
|
return { status: 200, body: { status: "ignored", reason: "invalid-json" } };
|
|
34102
35218
|
}
|
|
34103
35219
|
const deliveryId = synthesizeDeliveryId(parsed, rawBody);
|
|
34104
|
-
if (await
|
|
35220
|
+
if (await isDuplicateDelivery2(deliveryId)) {
|
|
34105
35221
|
return { status: 200, body: { status: "duplicate" } };
|
|
34106
35222
|
}
|
|
34107
35223
|
const event = String(parsed.webhookEvent ?? "");
|
|
@@ -105920,15 +107036,15 @@ async function _fetchIssueGatingInfo(issueId) {
|
|
|
105920
107036
|
const labelNames = (json.data?.issue?.labels?.nodes ?? []).map((n) => n?.name ?? "").filter((n) => n.length > 0);
|
|
105921
107037
|
return { stateType, labelNames };
|
|
105922
107038
|
}
|
|
105923
|
-
async function
|
|
107039
|
+
async function findLeadAgent7() {
|
|
105924
107040
|
const agents = await getAllAgents2();
|
|
105925
107041
|
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
105926
107042
|
if (onlineLead)
|
|
105927
107043
|
return onlineLead;
|
|
105928
107044
|
return agents.find((a) => a.isLead) ?? null;
|
|
105929
107045
|
}
|
|
105930
|
-
var
|
|
105931
|
-
var
|
|
107046
|
+
var UNMAPPED_NAMESPACE5 = "integration:unmapped:linear";
|
|
107047
|
+
var UNMAPPED_TTL_MS5 = 30 * 24 * 60 * 60 * 1000;
|
|
105932
107048
|
var LINEAR_WEBHOOK_ACTOR = { kind: "system", id: "webhook:linear" };
|
|
105933
107049
|
var APP_USER_ID_NAMESPACE = "integration:linear:bot-app-user-id";
|
|
105934
107050
|
async function getStoredAppUserId(workspaceId) {
|
|
@@ -105959,7 +107075,7 @@ async function resolveLinearActor(linearUserId, email, name, workspaceId, sample
|
|
|
105959
107075
|
return linked.id;
|
|
105960
107076
|
}
|
|
105961
107077
|
await upsertKv2({
|
|
105962
|
-
namespace:
|
|
107078
|
+
namespace: UNMAPPED_NAMESPACE5,
|
|
105963
107079
|
key: `${linearUserId}:meta`,
|
|
105964
107080
|
value: {
|
|
105965
107081
|
lastSeenAt: new Date().toISOString(),
|
|
@@ -105967,9 +107083,9 @@ async function resolveLinearActor(linearUserId, email, name, workspaceId, sample
|
|
|
105967
107083
|
sampleContext: sampleContext ? sampleContext.slice(0, 100) : null
|
|
105968
107084
|
},
|
|
105969
107085
|
valueType: "json",
|
|
105970
|
-
expiresAt: Date.now() +
|
|
107086
|
+
expiresAt: Date.now() + UNMAPPED_TTL_MS5
|
|
105971
107087
|
});
|
|
105972
|
-
await incrKv2(
|
|
107088
|
+
await incrKv2(UNMAPPED_NAMESPACE5, `${linearUserId}:count`, 1);
|
|
105973
107089
|
return;
|
|
105974
107090
|
}
|
|
105975
107091
|
var REQUEST_SECTION_LABEL = "Request (comment that opened this session)";
|
|
@@ -106081,7 +107197,7 @@ async function handleAgentSessionEvent(event) {
|
|
|
106081
107197
|
}
|
|
106082
107198
|
return;
|
|
106083
107199
|
}
|
|
106084
|
-
const lead = await
|
|
107200
|
+
const lead = await findLeadAgent7();
|
|
106085
107201
|
const sessionSection = sessionUrl ? `
|
|
106086
107202
|
Session: ${sessionUrl}` : "";
|
|
106087
107203
|
const requestSection = buildSessionRequestSection(event, actorName);
|
|
@@ -106285,7 +107401,7 @@ async function handleAgentSessionPrompted(event) {
|
|
|
106285
107401
|
return;
|
|
106286
107402
|
}
|
|
106287
107403
|
}
|
|
106288
|
-
const lead = await
|
|
107404
|
+
const lead = await findLeadAgent7();
|
|
106289
107405
|
const activity = event.agentActivity;
|
|
106290
107406
|
const promptUser = activity?.user;
|
|
106291
107407
|
const promptedActorLinearId = promptUser ? String(promptUser.id ?? "") : "";
|
|
@@ -106567,7 +107683,7 @@ function shouldSkipForLoopPrevention2(sync) {
|
|
|
106567
107683
|
}
|
|
106568
107684
|
|
|
106569
107685
|
// src/linear/app.ts
|
|
106570
|
-
var
|
|
107686
|
+
var initialized7 = false;
|
|
106571
107687
|
var unsubscribeRefresh = null;
|
|
106572
107688
|
function isLinearEnabled() {
|
|
106573
107689
|
if (isEnvFlagEnabled("LINEAR_DISABLE", false))
|
|
@@ -106582,12 +107698,12 @@ function resetLinear() {
|
|
|
106582
107698
|
unsubscribeRefresh();
|
|
106583
107699
|
unsubscribeRefresh = null;
|
|
106584
107700
|
}
|
|
106585
|
-
|
|
107701
|
+
initialized7 = false;
|
|
106586
107702
|
}
|
|
106587
107703
|
async function initLinear() {
|
|
106588
|
-
if (
|
|
107704
|
+
if (initialized7)
|
|
106589
107705
|
return isLinearEnabled();
|
|
106590
|
-
|
|
107706
|
+
initialized7 = true;
|
|
106591
107707
|
if (!isLinearEnabled()) {
|
|
106592
107708
|
console.log("[Linear] Integration disabled or LINEAR_CLIENT_ID not set");
|
|
106593
107709
|
return false;
|
|
@@ -106997,11 +108113,34 @@ function parseCookieHeader(cookieHeader, name) {
|
|
|
106997
108113
|
const match = header.match(re);
|
|
106998
108114
|
return match ? match[1] : undefined;
|
|
106999
108115
|
}
|
|
107000
|
-
|
|
107001
|
-
|
|
107002
|
-
|
|
108116
|
+
var LEGACY_PAGE_SESSION_COOKIE = "page_session";
|
|
108117
|
+
var COOKIE_SAFE_PAGE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
108118
|
+
function isCookieSafePageId(pageId) {
|
|
108119
|
+
return COOKIE_SAFE_PAGE_ID.test(pageId);
|
|
108120
|
+
}
|
|
108121
|
+
function pageSessionCookieName(pageId) {
|
|
108122
|
+
return `${LEGACY_PAGE_SESSION_COOKIE}_${pageId}`;
|
|
108123
|
+
}
|
|
108124
|
+
async function verifyNamedCookie(req, name) {
|
|
108125
|
+
const token = parseCookieHeader(req.headers.cookie, name);
|
|
108126
|
+
const payload = await verifyPageSession(token);
|
|
108127
|
+
return payload && token ? { token, payload } : null;
|
|
108128
|
+
}
|
|
108129
|
+
async function extractPageSession(req, pageId) {
|
|
108130
|
+
if (!isCookieSafePageId(pageId))
|
|
107003
108131
|
return null;
|
|
107004
|
-
|
|
108132
|
+
for (const name of [pageSessionCookieName(pageId), LEGACY_PAGE_SESSION_COOKIE]) {
|
|
108133
|
+
const session = await verifyNamedCookie(req, name);
|
|
108134
|
+
if (session?.payload.pageId === pageId)
|
|
108135
|
+
return session;
|
|
108136
|
+
}
|
|
108137
|
+
return null;
|
|
108138
|
+
}
|
|
108139
|
+
async function extractLegacyPageSession(req) {
|
|
108140
|
+
return verifyNamedCookie(req, LEGACY_PAGE_SESSION_COOKIE);
|
|
108141
|
+
}
|
|
108142
|
+
async function extractAndVerifyCookie(req, pageId) {
|
|
108143
|
+
return (await extractPageSession(req, pageId))?.payload ?? null;
|
|
107005
108144
|
}
|
|
107006
108145
|
var PAGE_SESSION_TTL_SECONDS = 3600;
|
|
107007
108146
|
async function issuePageSessionCookie(pageId, opts) {
|
|
@@ -107013,13 +108152,11 @@ async function issuePageSessionCookie(pageId, opts) {
|
|
|
107013
108152
|
...opts.name ? { name: opts.name } : {},
|
|
107014
108153
|
...opts.op ? { op: true } : {}
|
|
107015
108154
|
});
|
|
107016
|
-
|
|
107017
|
-
|
|
107018
|
-
|
|
107019
|
-
|
|
107020
|
-
|
|
107021
|
-
];
|
|
107022
|
-
if (opts.dev) {
|
|
108155
|
+
return buildCookie(pageSessionCookieName(pageId), token, PAGE_SESSION_TTL_SECONDS, opts.dev);
|
|
108156
|
+
}
|
|
108157
|
+
function buildCookie(name, value, maxAge, dev) {
|
|
108158
|
+
const attrs = [`${name}=${value}`, "HttpOnly", "Path=/", `Max-Age=${maxAge}`];
|
|
108159
|
+
if (dev) {
|
|
107023
108160
|
attrs.push("SameSite=Lax");
|
|
107024
108161
|
} else {
|
|
107025
108162
|
attrs.push("SameSite=None");
|
|
@@ -107027,6 +108164,30 @@ async function issuePageSessionCookie(pageId, opts) {
|
|
|
107027
108164
|
}
|
|
107028
108165
|
return attrs.join("; ");
|
|
107029
108166
|
}
|
|
108167
|
+
var MAX_PAGE_SESSION_COOKIES = 20;
|
|
108168
|
+
var PAGE_SESSION_COOKIE_RE = new RegExp(`(?:^|;\\s*)(${LEGACY_PAGE_SESSION_COOKIE}_[A-Za-z0-9_-]{1,64})=([^;]*)`, "g");
|
|
108169
|
+
async function pageSessionSetCookies(req, pageId, opts) {
|
|
108170
|
+
const issued = await issuePageSessionCookie(pageId, opts);
|
|
108171
|
+
const header = Array.isArray(req.headers.cookie) ? req.headers.cookie.join("; ") : req.headers.cookie ?? "";
|
|
108172
|
+
const keep = [];
|
|
108173
|
+
const evict = new Set;
|
|
108174
|
+
const seen = new Set([pageSessionCookieName(pageId)]);
|
|
108175
|
+
for (const [, name, token] of header.matchAll(PAGE_SESSION_COOKIE_RE)) {
|
|
108176
|
+
if (!name || seen.has(name))
|
|
108177
|
+
continue;
|
|
108178
|
+
seen.add(name);
|
|
108179
|
+
const payload = await verifyPageSession(token);
|
|
108180
|
+
if (payload && name === pageSessionCookieName(payload.pageId)) {
|
|
108181
|
+
keep.push({ name, exp: payload.exp, order: keep.length });
|
|
108182
|
+
} else {
|
|
108183
|
+
evict.add(name);
|
|
108184
|
+
}
|
|
108185
|
+
}
|
|
108186
|
+
keep.sort((a, b) => b.exp - a.exp || b.order - a.order);
|
|
108187
|
+
for (const { name } of keep.slice(MAX_PAGE_SESSION_COOKIES - 1))
|
|
108188
|
+
evict.add(name);
|
|
108189
|
+
return [issued, ...[...evict].map((name) => buildCookie(name, "", 0, opts.dev))];
|
|
108190
|
+
}
|
|
107030
108191
|
|
|
107031
108192
|
// src/http/auth.ts
|
|
107032
108193
|
function extractBearer(req) {
|
|
@@ -107247,14 +108408,14 @@ async function reloadGlobalConfigsAndIntegrations() {
|
|
|
107247
108408
|
return runWithoutRequestAuth(() => reloadGlobalConfigsAndIntegrationsInner());
|
|
107248
108409
|
}
|
|
107249
108410
|
async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
107250
|
-
const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-
|
|
108411
|
+
const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-sepja052.js");
|
|
107251
108412
|
const wasEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
|
|
107252
108413
|
const updated = await loadGlobalConfigsIntoEnv(true);
|
|
107253
108414
|
await syncTelemetryEnabled("settings").catch((err) => {
|
|
107254
108415
|
console.error("[config-reload] telemetry re-init failed (non-fatal):", err);
|
|
107255
108416
|
});
|
|
107256
108417
|
await stopSlackApp2();
|
|
107257
|
-
const { resetFileStorageProvider } = await import("./registry-
|
|
108418
|
+
const { resetFileStorageProvider } = await import("./registry-ajhexe44.js");
|
|
107258
108419
|
resetFileStorageProvider();
|
|
107259
108420
|
resetEmbeddingProvider();
|
|
107260
108421
|
const isEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
|
|
@@ -107263,10 +108424,10 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
|
107263
108424
|
integrations.push("embeddings");
|
|
107264
108425
|
}
|
|
107265
108426
|
if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
|
|
107266
|
-
import("./boot-reembed-
|
|
108427
|
+
import("./boot-reembed-n4wq5dd2.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
|
|
107267
108428
|
console.error("[config-reload] memory backfill failed (non-fatal):", err);
|
|
107268
108429
|
});
|
|
107269
|
-
import("./boot-reembed-
|
|
108430
|
+
import("./boot-reembed-4xwq5tg0.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
|
|
107270
108431
|
console.error("[config-reload] script backfill failed (non-fatal):", err);
|
|
107271
108432
|
});
|
|
107272
108433
|
}
|
|
@@ -107288,6 +108449,11 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
|
|
|
107288
108449
|
teardownAzureDevOpsOutbound();
|
|
107289
108450
|
if (isAzureDevOpsEnabled())
|
|
107290
108451
|
initAzureDevOpsOutbound();
|
|
108452
|
+
resetBitbucket();
|
|
108453
|
+
resetBitbucketBotCache();
|
|
108454
|
+
initBitbucket();
|
|
108455
|
+
if (isBitbucketEnabled())
|
|
108456
|
+
integrations.push("bitbucket");
|
|
107291
108457
|
resetLinear();
|
|
107292
108458
|
if (await initLinear())
|
|
107293
108459
|
integrations.push("linear");
|
|
@@ -107678,6 +108844,10 @@ async function handleCore(req, res, myAgentId, apiKey) {
|
|
|
107678
108844
|
return false;
|
|
107679
108845
|
}
|
|
107680
108846
|
|
|
108847
|
+
// src/mcp-limits.ts
|
|
108848
|
+
var MCP_MAX_TOOL_INPUT_ELEMENTS = 25000;
|
|
108849
|
+
var MCP_MAX_REQUEST_BODY_BYTES = 4 * 1024 * 1024;
|
|
108850
|
+
|
|
107681
108851
|
// src/server.ts
|
|
107682
108852
|
init_resolver();
|
|
107683
108853
|
init_rbac();
|
|
@@ -112726,9 +113896,11 @@ var registerCancelTaskTool = (server) => {
|
|
|
112726
113896
|
init_zod();
|
|
112727
113897
|
|
|
112728
113898
|
// src/tools/chat-access.ts
|
|
113899
|
+
init_zod();
|
|
112729
113900
|
init_db3();
|
|
112730
113901
|
init_rbac();
|
|
112731
113902
|
init_context_key();
|
|
113903
|
+
var chatAttachmentsSchema = array2(string2().min(1)).max(10).optional().describe("Files to send after the text, up to 10: attachment ids of your current task (from get-task-details) or file paths in your agent-fs drive, such as thoughts/<agent-id>/report.pdf, read with your own agent-fs credential. Telegram shows JPEG and PNG as photos, MP4 as video, MP3 and M4A as audio, and anything else as a document. A file over the platform upload limit (Telegram 50 MB, Discord 10 MB) is not sent, and the thread gets a note naming it.");
|
|
112732
113904
|
async function callerChatThread(requestInfo) {
|
|
112733
113905
|
if (!requestInfo.agentId)
|
|
112734
113906
|
return null;
|
|
@@ -112809,16 +113981,18 @@ var registerChatPostTool = (server) => {
|
|
|
112809
113981
|
adapter: _enum2(CHAT_SDK_ADAPTER_NAMES).describe("Chat SDK adapter name."),
|
|
112810
113982
|
threadId: string2().min(1).optional().describe("Full SDK thread id, such as telegram:12345 or slack:C123:1700000000.000100."),
|
|
112811
113983
|
channelId: string2().min(1).optional().describe("Full SDK channel id, such as slack:C123. Ignored when threadId is set."),
|
|
112812
|
-
text: string2().min(1).max(20000).describe("Markdown text to post.")
|
|
113984
|
+
text: string2().min(1).max(20000).describe("Markdown text to post."),
|
|
113985
|
+
attachments: chatAttachmentsSchema
|
|
112813
113986
|
}),
|
|
112814
113987
|
outputSchema: swarmToolOutputSchema({
|
|
112815
113988
|
yourAgentId: string2().optional(),
|
|
112816
113989
|
messageId: string2().optional(),
|
|
112817
113990
|
adapter: string2().optional(),
|
|
112818
113991
|
threadId: string2().optional(),
|
|
112819
|
-
channelId: string2().optional()
|
|
113992
|
+
channelId: string2().optional(),
|
|
113993
|
+
unsentFiles: array2(looseObject({ name: string2().optional(), reason: string2().optional() })).optional()
|
|
112820
113994
|
})
|
|
112821
|
-
}, async ({ adapter, threadId, channelId, text }, requestInfo) => {
|
|
113995
|
+
}, async ({ adapter, threadId, channelId, text, attachments }, requestInfo) => {
|
|
112822
113996
|
const data = { yourAgentId: requestInfo.agentId };
|
|
112823
113997
|
const target = threadId ?? channelId;
|
|
112824
113998
|
if (!target)
|
|
@@ -112829,20 +114003,25 @@ var registerChatPostTool = (server) => {
|
|
|
112829
114003
|
if (!await canUseChatVerb(requestInfo, "integration.chat.post")) {
|
|
112830
114004
|
return toolErr("Permission denied. Only the lead can post outside the thread of its task. Use chat-reply for the thread of your current task.", { data });
|
|
112831
114005
|
}
|
|
114006
|
+
const resolved = await resolveChatAttachmentRefs(attachments ?? [], requestInfo.sourceTaskId, requestInfo.agentId);
|
|
114007
|
+
if ("error" in resolved)
|
|
114008
|
+
return toolErr(resolved.error, { data });
|
|
112832
114009
|
try {
|
|
112833
114010
|
const sent = await postChatMessage({
|
|
112834
114011
|
adapter,
|
|
112835
114012
|
...threadId ? { threadId } : { channelId },
|
|
112836
114013
|
text,
|
|
112837
|
-
taskId: requestInfo.sourceTaskId
|
|
114014
|
+
taskId: requestInfo.sourceTaskId,
|
|
114015
|
+
files: resolved.files
|
|
112838
114016
|
});
|
|
112839
|
-
return toolOk(`Posted to ${adapter} ${threadId ? "thread" : "channel"} ${target}
|
|
114017
|
+
return toolOk(`Posted to ${adapter} ${threadId ? "thread" : "channel"} ${target}.${unsentFilesSummary(sent.unsentFiles)}`, {
|
|
112840
114018
|
data: {
|
|
112841
114019
|
...data,
|
|
112842
114020
|
messageId: sent.messageIds.at(-1),
|
|
112843
114021
|
adapter: sent.adapter,
|
|
112844
114022
|
threadId: sent.threadId,
|
|
112845
|
-
channelId: sent.channelId
|
|
114023
|
+
channelId: sent.channelId,
|
|
114024
|
+
unsentFiles: sent.unsentFiles
|
|
112846
114025
|
}
|
|
112847
114026
|
});
|
|
112848
114027
|
} catch (error) {
|
|
@@ -112923,18 +114102,20 @@ init_context_key();
|
|
|
112923
114102
|
var registerChatReplyTool = (server) => {
|
|
112924
114103
|
createToolRegistrar(server)("chat-reply", {
|
|
112925
114104
|
title: "Reply in the chat thread of this task",
|
|
112926
|
-
description: "Post a message to the Telegram, Slack, Discord or Teams thread your current task came from. Works only on a task whose contextKey starts with task:chat-sdk:. The task's final output is posted to the thread automatically when the task ends, so use this only for a question to the user
|
|
114105
|
+
description: "Post a message to the Telegram, Slack, Discord or Teams thread your current task came from. Works only on a task whose contextKey starts with task:chat-sdk:. The task's final output is posted to the thread automatically when the task ends, so use this only for a question to the user, a short progress note on long work, or to send files (attachments). Markdown is supported; long text is split into several messages. When the final output of a task is posted, the files attached to that task go with it.",
|
|
112927
114106
|
annotations: { openWorldHint: true },
|
|
112928
114107
|
inputSchema: object2({
|
|
112929
|
-
text: string2().min(1).max(20000).describe("Markdown text to post to the thread.")
|
|
114108
|
+
text: string2().min(1).max(20000).describe("Markdown text to post to the thread."),
|
|
114109
|
+
attachments: chatAttachmentsSchema
|
|
112930
114110
|
}),
|
|
112931
114111
|
outputSchema: swarmToolOutputSchema({
|
|
112932
114112
|
yourAgentId: string2().optional(),
|
|
112933
114113
|
messageId: string2().optional(),
|
|
112934
114114
|
adapter: string2().optional(),
|
|
112935
|
-
threadId: string2().optional()
|
|
114115
|
+
threadId: string2().optional(),
|
|
114116
|
+
unsentFiles: array2(looseObject({ name: string2().optional(), reason: string2().optional() })).optional()
|
|
112936
114117
|
})
|
|
112937
|
-
}, async ({ text }, requestInfo) => {
|
|
114118
|
+
}, async ({ text, attachments }, requestInfo) => {
|
|
112938
114119
|
if (!requestInfo.agentId)
|
|
112939
114120
|
return toolErr("Agent ID not found.");
|
|
112940
114121
|
const data = { yourAgentId: requestInfo.agentId };
|
|
@@ -112948,19 +114129,24 @@ var registerChatReplyTool = (server) => {
|
|
|
112948
114129
|
if (!thread) {
|
|
112949
114130
|
return toolErr(`Task ${task.id} did not come from a chat thread (no task:chat-sdk contextKey). Use the tool of the channel the task came from.`, { data });
|
|
112950
114131
|
}
|
|
114132
|
+
const resolved = await resolveChatAttachmentRefs(attachments ?? [], task.id, requestInfo.agentId);
|
|
114133
|
+
if ("error" in resolved)
|
|
114134
|
+
return toolErr(resolved.error, { data });
|
|
112951
114135
|
try {
|
|
112952
114136
|
const sent = await postChatMessage({
|
|
112953
114137
|
adapter: thread.adapter,
|
|
112954
114138
|
threadId: thread.threadId,
|
|
112955
114139
|
text,
|
|
112956
|
-
taskId: task.id
|
|
114140
|
+
taskId: task.id,
|
|
114141
|
+
files: resolved.files
|
|
112957
114142
|
});
|
|
112958
|
-
return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}
|
|
114143
|
+
return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}.${unsentFilesSummary(sent.unsentFiles)}`, {
|
|
112959
114144
|
data: {
|
|
112960
114145
|
...data,
|
|
112961
114146
|
messageId: sent.messageIds.at(-1),
|
|
112962
114147
|
adapter: sent.adapter,
|
|
112963
|
-
threadId: sent.threadId
|
|
114148
|
+
threadId: sent.threadId,
|
|
114149
|
+
unsentFiles: sent.unsentFiles
|
|
112964
114150
|
}
|
|
112965
114151
|
});
|
|
112966
114152
|
} catch (error) {
|
|
@@ -114448,8 +115634,523 @@ init_db3();
|
|
|
114448
115634
|
|
|
114449
115635
|
// src/tasks/task-terminal-effects.ts
|
|
114450
115636
|
init_db3();
|
|
115637
|
+
|
|
115638
|
+
// src/be/chunking.ts
|
|
115639
|
+
var MAX_CHUNK_SIZE = 2000;
|
|
115640
|
+
var CHUNK_OVERLAP = 100;
|
|
115641
|
+
var MIN_CHUNK_SIZE = 50;
|
|
115642
|
+
function chunkContent(text) {
|
|
115643
|
+
const trimmed = text.trim();
|
|
115644
|
+
if (!trimmed || trimmed.length < MIN_CHUNK_SIZE) {
|
|
115645
|
+
return [];
|
|
115646
|
+
}
|
|
115647
|
+
if (trimmed.length <= MAX_CHUNK_SIZE) {
|
|
115648
|
+
return [{ content: trimmed, chunkIndex: 0, totalChunks: 1, headings: [] }];
|
|
115649
|
+
}
|
|
115650
|
+
const sections = splitByHeaders(trimmed);
|
|
115651
|
+
const rawChunks = [];
|
|
115652
|
+
for (const section of sections) {
|
|
115653
|
+
if (section.content.length <= MAX_CHUNK_SIZE) {
|
|
115654
|
+
rawChunks.push(section);
|
|
115655
|
+
} else {
|
|
115656
|
+
const subChunks = recursiveSplit(section.content);
|
|
115657
|
+
for (const sub of subChunks) {
|
|
115658
|
+
rawChunks.push({ content: sub, headings: section.headings });
|
|
115659
|
+
}
|
|
115660
|
+
}
|
|
115661
|
+
}
|
|
115662
|
+
const packed = packSmallSections(rawChunks);
|
|
115663
|
+
return packed.map((c, i) => ({
|
|
115664
|
+
content: c.content,
|
|
115665
|
+
chunkIndex: i,
|
|
115666
|
+
totalChunks: packed.length,
|
|
115667
|
+
headings: c.headings
|
|
115668
|
+
}));
|
|
115669
|
+
}
|
|
115670
|
+
function renderSection(section) {
|
|
115671
|
+
return section.headings.length > 0 ? `${section.headings.join(" > ")}
|
|
115672
|
+
|
|
115673
|
+
${section.content}` : section.content;
|
|
115674
|
+
}
|
|
115675
|
+
function packSmallSections(sections) {
|
|
115676
|
+
const out = [];
|
|
115677
|
+
let pending = null;
|
|
115678
|
+
const flush = () => {
|
|
115679
|
+
if (pending)
|
|
115680
|
+
out.push({ content: pending.parts.join(`
|
|
115681
|
+
|
|
115682
|
+
`), headings: pending.headings });
|
|
115683
|
+
pending = null;
|
|
115684
|
+
};
|
|
115685
|
+
for (const section of sections) {
|
|
115686
|
+
const rendered = renderSection(section);
|
|
115687
|
+
if (section.content.trim().length >= MIN_CHUNK_SIZE) {
|
|
115688
|
+
flush();
|
|
115689
|
+
out.push({ content: rendered, headings: section.headings });
|
|
115690
|
+
continue;
|
|
115691
|
+
}
|
|
115692
|
+
if (pending && pending.length + 2 + rendered.length > MAX_CHUNK_SIZE)
|
|
115693
|
+
flush();
|
|
115694
|
+
if (pending) {
|
|
115695
|
+
pending.parts.push(rendered);
|
|
115696
|
+
pending.length += 2 + rendered.length;
|
|
115697
|
+
} else {
|
|
115698
|
+
pending = { parts: [rendered], length: rendered.length, headings: section.headings };
|
|
115699
|
+
}
|
|
115700
|
+
}
|
|
115701
|
+
flush();
|
|
115702
|
+
return out;
|
|
115703
|
+
}
|
|
115704
|
+
function splitByHeaders(text) {
|
|
115705
|
+
const lines = text.split(`
|
|
115706
|
+
`);
|
|
115707
|
+
const sections = [];
|
|
115708
|
+
let currentContent = [];
|
|
115709
|
+
const headingStack = [];
|
|
115710
|
+
for (const line of lines) {
|
|
115711
|
+
const headingMatch = line.match(/^(#{1,3})\s+(.+)$/);
|
|
115712
|
+
if (headingMatch) {
|
|
115713
|
+
if (currentContent.length > 0) {
|
|
115714
|
+
const content = currentContent.join(`
|
|
115715
|
+
`).trim();
|
|
115716
|
+
if (content) {
|
|
115717
|
+
sections.push({ content, headings: [...headingStack] });
|
|
115718
|
+
}
|
|
115719
|
+
currentContent = [];
|
|
115720
|
+
}
|
|
115721
|
+
const level = headingMatch[1].length;
|
|
115722
|
+
const title = headingMatch[2].trim();
|
|
115723
|
+
while (headingStack.length >= level) {
|
|
115724
|
+
headingStack.pop();
|
|
115725
|
+
}
|
|
115726
|
+
headingStack.push(`${"#".repeat(level)} ${title}`);
|
|
115727
|
+
} else {
|
|
115728
|
+
currentContent.push(line);
|
|
115729
|
+
}
|
|
115730
|
+
}
|
|
115731
|
+
if (currentContent.length > 0) {
|
|
115732
|
+
const content = currentContent.join(`
|
|
115733
|
+
`).trim();
|
|
115734
|
+
if (content) {
|
|
115735
|
+
sections.push({ content, headings: [...headingStack] });
|
|
115736
|
+
}
|
|
115737
|
+
}
|
|
115738
|
+
if (sections.length === 0) {
|
|
115739
|
+
return [{ content: text, headings: [] }];
|
|
115740
|
+
}
|
|
115741
|
+
return sections;
|
|
115742
|
+
}
|
|
115743
|
+
var SEPARATORS = [`
|
|
115744
|
+
|
|
115745
|
+
`, `
|
|
115746
|
+
`, ". ", " "];
|
|
115747
|
+
function recursiveSplit(text) {
|
|
115748
|
+
return recursiveSplitWithSeparators(text, 0);
|
|
115749
|
+
}
|
|
115750
|
+
function recursiveSplitWithSeparators(text, separatorIndex) {
|
|
115751
|
+
if (text.length <= MAX_CHUNK_SIZE) {
|
|
115752
|
+
return [text.trim()].filter((s) => s.length > 0);
|
|
115753
|
+
}
|
|
115754
|
+
if (separatorIndex >= SEPARATORS.length) {
|
|
115755
|
+
return hardSplit(text);
|
|
115756
|
+
}
|
|
115757
|
+
const separator = SEPARATORS[separatorIndex];
|
|
115758
|
+
const parts = text.split(separator);
|
|
115759
|
+
if (parts.length <= 1) {
|
|
115760
|
+
return recursiveSplitWithSeparators(text, separatorIndex + 1);
|
|
115761
|
+
}
|
|
115762
|
+
const chunks = [];
|
|
115763
|
+
let current = "";
|
|
115764
|
+
for (const part of parts) {
|
|
115765
|
+
const candidate = current ? current + separator + part : part;
|
|
115766
|
+
if (candidate.length <= MAX_CHUNK_SIZE) {
|
|
115767
|
+
current = candidate;
|
|
115768
|
+
} else {
|
|
115769
|
+
if (current) {
|
|
115770
|
+
chunks.push(current.trim());
|
|
115771
|
+
}
|
|
115772
|
+
if (part.length > MAX_CHUNK_SIZE) {
|
|
115773
|
+
chunks.push(...recursiveSplitWithSeparators(part, separatorIndex + 1));
|
|
115774
|
+
current = "";
|
|
115775
|
+
} else {
|
|
115776
|
+
current = part;
|
|
115777
|
+
}
|
|
115778
|
+
}
|
|
115779
|
+
}
|
|
115780
|
+
if (current.trim()) {
|
|
115781
|
+
chunks.push(current.trim());
|
|
115782
|
+
}
|
|
115783
|
+
return addOverlap(chunks, text);
|
|
115784
|
+
}
|
|
115785
|
+
function hardSplit(text) {
|
|
115786
|
+
const chunks = [];
|
|
115787
|
+
let start = 0;
|
|
115788
|
+
while (start < text.length) {
|
|
115789
|
+
const end = Math.min(start + MAX_CHUNK_SIZE, text.length);
|
|
115790
|
+
chunks.push(text.slice(start, end).trim());
|
|
115791
|
+
if (end === text.length)
|
|
115792
|
+
break;
|
|
115793
|
+
start = end - CHUNK_OVERLAP;
|
|
115794
|
+
}
|
|
115795
|
+
return chunks.filter((c) => c.length > 0);
|
|
115796
|
+
}
|
|
115797
|
+
function addOverlap(chunks, _originalText) {
|
|
115798
|
+
if (chunks.length <= 1)
|
|
115799
|
+
return chunks;
|
|
115800
|
+
const result = [chunks[0]];
|
|
115801
|
+
for (let i = 1;i < chunks.length; i++) {
|
|
115802
|
+
const prevChunk = chunks[i - 1];
|
|
115803
|
+
const chunk = chunks[i];
|
|
115804
|
+
const overlapText = prevChunk.slice(-CHUNK_OVERLAP);
|
|
115805
|
+
if (overlapText.length + chunk.length <= MAX_CHUNK_SIZE + CHUNK_OVERLAP) {
|
|
115806
|
+
result.push(overlapText + chunk);
|
|
115807
|
+
} else {
|
|
115808
|
+
result.push(chunk);
|
|
115809
|
+
}
|
|
115810
|
+
}
|
|
115811
|
+
return result;
|
|
115812
|
+
}
|
|
115813
|
+
|
|
115814
|
+
// src/be/memory/index-content.ts
|
|
114451
115815
|
init_memory();
|
|
114452
115816
|
|
|
115817
|
+
// src/be/memory/key-guard.ts
|
|
115818
|
+
init_rbac();
|
|
115819
|
+
init_key_paths();
|
|
115820
|
+
|
|
115821
|
+
class MemoryKeyError extends Error {
|
|
115822
|
+
reason;
|
|
115823
|
+
constructor(message, reason) {
|
|
115824
|
+
super(message);
|
|
115825
|
+
this.reason = reason;
|
|
115826
|
+
this.name = "MemoryKeyError";
|
|
115827
|
+
}
|
|
115828
|
+
}
|
|
115829
|
+
var NO_AUTHORITY = {
|
|
115830
|
+
principal: { kind: "agent", agentId: "", isLead: false },
|
|
115831
|
+
source: "http"
|
|
115832
|
+
};
|
|
115833
|
+
function shapeError(key, origin) {
|
|
115834
|
+
if (key.length <= MEMORY_KEY_MAX_LENGTH && MEMORY_KEY_PATTERN.test(key))
|
|
115835
|
+
return null;
|
|
115836
|
+
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.`;
|
|
115837
|
+
return `${subject} ${MEMORY_KEY_PATTERN_MESSAGE}`;
|
|
115838
|
+
}
|
|
115839
|
+
function assertKeyWritable(key, origin, writer) {
|
|
115840
|
+
if (origin === "sourcePath" && !isLongtermKey(key))
|
|
115841
|
+
return;
|
|
115842
|
+
const shape = shapeError(key, origin);
|
|
115843
|
+
if (shape)
|
|
115844
|
+
throw new MemoryKeyError(shape, "invalid");
|
|
115845
|
+
const pathError = longtermKeyError(key);
|
|
115846
|
+
if (pathError)
|
|
115847
|
+
throw new MemoryKeyError(pathError, "invalid");
|
|
115848
|
+
if (!isConsolidatedKey(key))
|
|
115849
|
+
return;
|
|
115850
|
+
const { principal, source } = writer ?? NO_AUTHORITY;
|
|
115851
|
+
const decision = can({
|
|
115852
|
+
principal,
|
|
115853
|
+
verb: "memory.write.consolidated",
|
|
115854
|
+
resource: { kind: "none" },
|
|
115855
|
+
source
|
|
115856
|
+
});
|
|
115857
|
+
if (!decision.allow)
|
|
115858
|
+
throw new MemoryKeyError(consolidatedKeyMessage(key), "forbidden");
|
|
115859
|
+
}
|
|
115860
|
+
|
|
115861
|
+
// src/be/memory/link-resolver.ts
|
|
115862
|
+
init_db3();
|
|
115863
|
+
init_constants2();
|
|
115864
|
+
var WIKILINK_RE = /\[\[([^\]]+)\]\]/g;
|
|
115865
|
+
var PR_HASH_RE = /(?:^|[\s(])#(\d{1,5})(?=[\s,.)!?]|$)/gm;
|
|
115866
|
+
var PR_PREFIX_RE = /\bPR\s*#(\d{1,5})\b/gi;
|
|
115867
|
+
var GITHUB_PR_URL_RE = /https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+)\/pull\/(\d+)/g;
|
|
115868
|
+
var AGENT_FS_LIVE_HOSTS = String.raw`agent-fs|live\.agent-fs\.dev`;
|
|
115869
|
+
var AGENT_FS_FILE_ROUTE = String.raw`\/file\/~\/([a-f0-9-]+)\/([a-f0-9-]+)\/([\w/.%-]+)`;
|
|
115870
|
+
var AGENT_UI_PAGE_RE = /(?:app\.[^/]+|localhost:\d+)\/pages\/([a-f0-9-]+)/g;
|
|
115871
|
+
var AGENT_UI_TASK_RE = /(?:app\.[^/]+|localhost:\d+)\/tasks\/([a-f0-9-]+)/g;
|
|
115872
|
+
var wikilinkMatcher = (content) => {
|
|
115873
|
+
const results = [];
|
|
115874
|
+
for (const match of content.matchAll(WIKILINK_RE)) {
|
|
115875
|
+
const name = match[1].trim();
|
|
115876
|
+
if (!name)
|
|
115877
|
+
continue;
|
|
115878
|
+
results.push({
|
|
115879
|
+
linkType: "wikilink",
|
|
115880
|
+
targetKind: "memory",
|
|
115881
|
+
targetId: name,
|
|
115882
|
+
sourceText: match[0],
|
|
115883
|
+
resolver: "wikilink"
|
|
115884
|
+
});
|
|
115885
|
+
}
|
|
115886
|
+
return results;
|
|
115887
|
+
};
|
|
115888
|
+
var prMatcher = (content) => {
|
|
115889
|
+
const results = [];
|
|
115890
|
+
const seen = new Set;
|
|
115891
|
+
for (const match of content.matchAll(GITHUB_PR_URL_RE)) {
|
|
115892
|
+
const id = `github:${match[1]}/${match[2]}#${match[3]}`;
|
|
115893
|
+
if (seen.has(id))
|
|
115894
|
+
continue;
|
|
115895
|
+
seen.add(id);
|
|
115896
|
+
results.push({
|
|
115897
|
+
linkType: "pr",
|
|
115898
|
+
targetKind: "pr",
|
|
115899
|
+
targetId: id,
|
|
115900
|
+
sourceText: match[0],
|
|
115901
|
+
resolver: "pr-url",
|
|
115902
|
+
metadata: { owner: match[1], repo: match[2], number: Number(match[3]) }
|
|
115903
|
+
});
|
|
115904
|
+
}
|
|
115905
|
+
for (const match of content.matchAll(PR_PREFIX_RE)) {
|
|
115906
|
+
const id = `pr:${match[1]}`;
|
|
115907
|
+
if (seen.has(id))
|
|
115908
|
+
continue;
|
|
115909
|
+
seen.add(id);
|
|
115910
|
+
results.push({
|
|
115911
|
+
linkType: "pr",
|
|
115912
|
+
targetKind: "pr",
|
|
115913
|
+
targetId: id,
|
|
115914
|
+
sourceText: match[0].trim(),
|
|
115915
|
+
resolver: "pr-prefix",
|
|
115916
|
+
metadata: { number: Number(match[1]) }
|
|
115917
|
+
});
|
|
115918
|
+
}
|
|
115919
|
+
for (const match of content.matchAll(PR_HASH_RE)) {
|
|
115920
|
+
const id = `pr:${match[1]}`;
|
|
115921
|
+
if (seen.has(id))
|
|
115922
|
+
continue;
|
|
115923
|
+
seen.add(id);
|
|
115924
|
+
results.push({
|
|
115925
|
+
linkType: "pr",
|
|
115926
|
+
targetKind: "pr",
|
|
115927
|
+
targetId: id,
|
|
115928
|
+
sourceText: `#${match[1]}`,
|
|
115929
|
+
resolver: "pr-hash",
|
|
115930
|
+
metadata: { number: Number(match[1]) }
|
|
115931
|
+
});
|
|
115932
|
+
}
|
|
115933
|
+
return results;
|
|
115934
|
+
};
|
|
115935
|
+
function escapeRegExp3(value) {
|
|
115936
|
+
return value.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
115937
|
+
}
|
|
115938
|
+
function agentFsPathRegex() {
|
|
115939
|
+
const appHosts = getConfiguredAppUrls().flatMap((value) => {
|
|
115940
|
+
try {
|
|
115941
|
+
const url = new URL(value);
|
|
115942
|
+
return [escapeRegExp3(`${url.host}${url.pathname.replace(/\/+$/, "")}`)];
|
|
115943
|
+
} catch {
|
|
115944
|
+
return [];
|
|
115945
|
+
}
|
|
115946
|
+
});
|
|
115947
|
+
const hosts = [AGENT_FS_LIVE_HOSTS, ...appHosts, String.raw`localhost:\d+`].join("|");
|
|
115948
|
+
return new RegExp(`(?<![\\w.-])(?:${hosts})${AGENT_FS_FILE_ROUTE}`, "gi");
|
|
115949
|
+
}
|
|
115950
|
+
var agentFsMatcher = (content) => {
|
|
115951
|
+
const results = [];
|
|
115952
|
+
for (const match of content.matchAll(agentFsPathRegex())) {
|
|
115953
|
+
const orgId = match[1];
|
|
115954
|
+
const driveId = match[2];
|
|
115955
|
+
const path = match[3];
|
|
115956
|
+
results.push({
|
|
115957
|
+
linkType: "agent-fs-file",
|
|
115958
|
+
targetKind: "agent-fs-file",
|
|
115959
|
+
targetId: `${orgId}/${driveId}/${path}`,
|
|
115960
|
+
sourceText: match[0],
|
|
115961
|
+
resolver: "agent-fs-path",
|
|
115962
|
+
metadata: { orgId, driveId, path }
|
|
115963
|
+
});
|
|
115964
|
+
}
|
|
115965
|
+
return results;
|
|
115966
|
+
};
|
|
115967
|
+
var agentUiMatcher = (content) => {
|
|
115968
|
+
const results = [];
|
|
115969
|
+
for (const match of content.matchAll(AGENT_UI_PAGE_RE)) {
|
|
115970
|
+
results.push({
|
|
115971
|
+
linkType: "agent-ui",
|
|
115972
|
+
targetKind: "agent-ui",
|
|
115973
|
+
targetId: `page:${match[1]}`,
|
|
115974
|
+
sourceText: match[0],
|
|
115975
|
+
resolver: "agent-ui-page"
|
|
115976
|
+
});
|
|
115977
|
+
}
|
|
115978
|
+
for (const match of content.matchAll(AGENT_UI_TASK_RE)) {
|
|
115979
|
+
results.push({
|
|
115980
|
+
linkType: "agent-ui",
|
|
115981
|
+
targetKind: "agent-ui",
|
|
115982
|
+
targetId: `task:${match[1]}`,
|
|
115983
|
+
sourceText: match[0],
|
|
115984
|
+
resolver: "agent-ui-task"
|
|
115985
|
+
});
|
|
115986
|
+
}
|
|
115987
|
+
return results;
|
|
115988
|
+
};
|
|
115989
|
+
var MATCHERS = [wikilinkMatcher, prMatcher, agentFsMatcher, agentUiMatcher];
|
|
115990
|
+
function resolveLinks(content) {
|
|
115991
|
+
const results = [];
|
|
115992
|
+
for (const matcher of MATCHERS) {
|
|
115993
|
+
for (const link of matcher(content)) {
|
|
115994
|
+
results.push({ ...link, strength: 1 });
|
|
115995
|
+
}
|
|
115996
|
+
}
|
|
115997
|
+
return results;
|
|
115998
|
+
}
|
|
115999
|
+
async function resolveWikilinksToMemoryIds(agentId, links) {
|
|
116000
|
+
const db = getDbClient2();
|
|
116001
|
+
const resolved = [];
|
|
116002
|
+
for (const link of links) {
|
|
116003
|
+
if (link.linkType !== "wikilink") {
|
|
116004
|
+
resolved.push(link);
|
|
116005
|
+
continue;
|
|
116006
|
+
}
|
|
116007
|
+
const row = await db.get("SELECT id FROM agent_memory WHERE name = ? AND (agentId = ? OR scope = 'swarm') LIMIT 1", [link.targetId, agentId]);
|
|
116008
|
+
resolved.push(row ? { ...link, targetId: row.id } : link);
|
|
116009
|
+
}
|
|
116010
|
+
return resolved;
|
|
116011
|
+
}
|
|
116012
|
+
var INSERT_LINK_SQL = `INSERT OR IGNORE INTO memory_link
|
|
116013
|
+
(id, from_memory_id, linkType, targetKind, targetId, strength, resolver, sourceText, metadata, createdAt, updatedAt)
|
|
116014
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
116015
|
+
function insertLinkArgs(memoryId, link, now) {
|
|
116016
|
+
return [
|
|
116017
|
+
crypto.randomUUID(),
|
|
116018
|
+
memoryId,
|
|
116019
|
+
link.linkType,
|
|
116020
|
+
link.targetKind,
|
|
116021
|
+
link.targetId,
|
|
116022
|
+
link.strength,
|
|
116023
|
+
link.resolver,
|
|
116024
|
+
link.sourceText,
|
|
116025
|
+
link.metadata ? JSON.stringify(link.metadata) : null,
|
|
116026
|
+
now,
|
|
116027
|
+
now
|
|
116028
|
+
];
|
|
116029
|
+
}
|
|
116030
|
+
async function storeLinks(memoryId, agentId, content) {
|
|
116031
|
+
const links = resolveLinks(content);
|
|
116032
|
+
if (links.length === 0)
|
|
116033
|
+
return;
|
|
116034
|
+
const resolved = await resolveWikilinksToMemoryIds(agentId, links);
|
|
116035
|
+
const now = new Date().toISOString();
|
|
116036
|
+
await getDbClient2().transaction(async (tx) => {
|
|
116037
|
+
for (const link of resolved) {
|
|
116038
|
+
await tx.run(INSERT_LINK_SQL, insertLinkArgs(memoryId, link, now));
|
|
116039
|
+
}
|
|
116040
|
+
});
|
|
116041
|
+
}
|
|
116042
|
+
function linkIdentity2(link) {
|
|
116043
|
+
return JSON.stringify([link.linkType, link.targetKind, link.targetId, link.sourceText ?? null]);
|
|
116044
|
+
}
|
|
116045
|
+
async function refreshLinks(memoryId, agentId, content) {
|
|
116046
|
+
const resolved = await resolveWikilinksToMemoryIds(agentId, resolveLinks(content));
|
|
116047
|
+
const nextIdentities = new Set(resolved.map((link) => linkIdentity2(link)));
|
|
116048
|
+
const now = new Date().toISOString();
|
|
116049
|
+
await getDbClient2().transaction(async (tx) => {
|
|
116050
|
+
const existing = await tx.query(`SELECT id, linkType, targetKind, targetId, sourceText
|
|
116051
|
+
FROM memory_link
|
|
116052
|
+
WHERE from_memory_id = ? AND linkType != 'sequel'`, [memoryId]);
|
|
116053
|
+
for (const row of existing) {
|
|
116054
|
+
if (!nextIdentities.has(linkIdentity2(row))) {
|
|
116055
|
+
await tx.run("DELETE FROM memory_link WHERE id = ?", [row.id]);
|
|
116056
|
+
}
|
|
116057
|
+
}
|
|
116058
|
+
for (const link of resolved) {
|
|
116059
|
+
await tx.run(INSERT_LINK_SQL, insertLinkArgs(memoryId, link, now));
|
|
116060
|
+
}
|
|
116061
|
+
});
|
|
116062
|
+
}
|
|
116063
|
+
|
|
116064
|
+
// src/be/memory/index-content.ts
|
|
116065
|
+
init_secret_scrubber();
|
|
116066
|
+
function taskCompletionMemoryKey(taskId) {
|
|
116067
|
+
return `/task-completions/${taskId.toLowerCase().replace(/[^a-z0-9._-]/g, "-")}`;
|
|
116068
|
+
}
|
|
116069
|
+
async function indexMemoryContent(params) {
|
|
116070
|
+
const { agentId, content, name, scope, source, sourceTaskId, sourcePath, tags } = params;
|
|
116071
|
+
const rowKey = params.key ?? (sourcePath || null);
|
|
116072
|
+
if (rowKey)
|
|
116073
|
+
assertKeyWritable(rowKey, params.key != null ? "key" : "sourcePath", params.writer);
|
|
116074
|
+
const contentChunks = chunkContent(content);
|
|
116075
|
+
if (contentChunks.length === 0) {
|
|
116076
|
+
contentChunks.push({
|
|
116077
|
+
content: content.trim(),
|
|
116078
|
+
chunkIndex: 0,
|
|
116079
|
+
totalChunks: 1,
|
|
116080
|
+
headings: []
|
|
116081
|
+
});
|
|
116082
|
+
}
|
|
116083
|
+
const store = getMemoryStore2();
|
|
116084
|
+
const provider = getEmbeddingProvider2();
|
|
116085
|
+
if (sourcePath && agentId && contentChunks.length === 1) {
|
|
116086
|
+
const existing = (await store.list(agentId, {
|
|
116087
|
+
scope,
|
|
116088
|
+
limit: 2,
|
|
116089
|
+
ownerAgentId: agentId,
|
|
116090
|
+
sourcePath
|
|
116091
|
+
})).filter((memory) => memory.sourcePath === sourcePath);
|
|
116092
|
+
if (existing.length === 1 && existing[0]?.totalChunks === 1) {
|
|
116093
|
+
const result = await store.edit({
|
|
116094
|
+
id: existing[0].id,
|
|
116095
|
+
mode: "replace",
|
|
116096
|
+
content: contentChunks[0].content,
|
|
116097
|
+
intent: "re-index memory source path",
|
|
116098
|
+
changedByAgentId: agentId
|
|
116099
|
+
});
|
|
116100
|
+
const embedding = await provider.embed(result.memory.content);
|
|
116101
|
+
if (embedding)
|
|
116102
|
+
await store.updateEmbedding(result.memory.id, embedding, provider.name);
|
|
116103
|
+
try {
|
|
116104
|
+
await refreshLinks(result.memory.id, agentId, result.memory.content);
|
|
116105
|
+
} catch (err) {
|
|
116106
|
+
console.error(`[memory] Link resolution failed for ${result.memory.id}:`, err.message);
|
|
116107
|
+
}
|
|
116108
|
+
return { queued: false, memoryIds: [result.memory.id], edited: result.changed, chunks: 1 };
|
|
116109
|
+
}
|
|
116110
|
+
}
|
|
116111
|
+
if (sourcePath && agentId) {
|
|
116112
|
+
await store.deleteBySourcePath(sourcePath, agentId);
|
|
116113
|
+
}
|
|
116114
|
+
const inputs = contentChunks.map((chunk) => ({
|
|
116115
|
+
agentId: agentId || null,
|
|
116116
|
+
content: chunk.content,
|
|
116117
|
+
name,
|
|
116118
|
+
scope,
|
|
116119
|
+
source,
|
|
116120
|
+
sourcePath: sourcePath || null,
|
|
116121
|
+
sourceTaskId: sourceTaskId || null,
|
|
116122
|
+
chunkIndex: chunk.chunkIndex,
|
|
116123
|
+
totalChunks: chunk.totalChunks,
|
|
116124
|
+
tags: tags || [],
|
|
116125
|
+
contextKey: params.contextKey ?? null,
|
|
116126
|
+
intent: params.intent ?? "index memory content",
|
|
116127
|
+
key: rowKey
|
|
116128
|
+
}));
|
|
116129
|
+
const memories = params.replaceExisting && params.key ? await store.replaceDocument({ key: params.key, scope, agentId: agentId || null, source }, inputs) : await store.storeBatch(inputs);
|
|
116130
|
+
if (agentId) {
|
|
116131
|
+
for (const memory of memories) {
|
|
116132
|
+
try {
|
|
116133
|
+
await storeLinks(memory.id, agentId, memory.content);
|
|
116134
|
+
} catch (err) {
|
|
116135
|
+
console.error(`[memory] Link resolution failed for ${memory.id}:`, err.message);
|
|
116136
|
+
}
|
|
116137
|
+
}
|
|
116138
|
+
}
|
|
116139
|
+
(async () => {
|
|
116140
|
+
try {
|
|
116141
|
+
const embeddings = await provider.embedBatch(memories.map((m) => m.content));
|
|
116142
|
+
for (let i = 0;i < embeddings.length; i++) {
|
|
116143
|
+
if (embeddings[i]) {
|
|
116144
|
+
await store.updateEmbedding(memories[i].id, embeddings[i], provider.name);
|
|
116145
|
+
}
|
|
116146
|
+
}
|
|
116147
|
+
} catch (err) {
|
|
116148
|
+
console.error("[memory] Batch embedding failed:", err.message);
|
|
116149
|
+
}
|
|
116150
|
+
})().catch((err) => console.error("[memory] batch embed failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
116151
|
+
return { queued: true, memoryIds: memories.map((m) => m.id), chunks: contentChunks.length };
|
|
116152
|
+
}
|
|
116153
|
+
|
|
114453
116154
|
// src/be/memory/raters/retrieval.ts
|
|
114454
116155
|
init_db3();
|
|
114455
116156
|
function dedupeMemoryDocumentIds(memories) {
|
|
@@ -115205,40 +116906,39 @@ ${safeFailureReason || "No reason provided"}
|
|
|
115205
116906
|
This task failed. Learn from this to avoid repeating the mistake.`;
|
|
115206
116907
|
if (taskContent.length < 30)
|
|
115207
116908
|
return;
|
|
115208
|
-
const
|
|
115209
|
-
|
|
115210
|
-
const memory = await store.store({
|
|
116909
|
+
const key = taskCompletionMemoryKey(taskId);
|
|
116910
|
+
await indexMemoryContent({
|
|
115211
116911
|
agentId: agentId ?? null,
|
|
115212
116912
|
content: taskContent,
|
|
115213
116913
|
name: `Task: ${safeTask.slice(0, 80)}`,
|
|
115214
116914
|
scope: "agent",
|
|
115215
116915
|
source: "task_completion",
|
|
115216
|
-
sourceTaskId: taskId
|
|
116916
|
+
sourceTaskId: taskId,
|
|
116917
|
+
key,
|
|
116918
|
+
intent: "task completion memory",
|
|
116919
|
+
replaceExisting: true
|
|
115217
116920
|
});
|
|
115218
|
-
const embedding = await provider.embed(taskContent);
|
|
115219
|
-
if (embedding) {
|
|
115220
|
-
await store.updateEmbedding(memory.id, embedding, provider.name);
|
|
115221
|
-
}
|
|
115222
116921
|
const shouldShareWithSwarm = status === "completed" && (task.taskType === "research" || task.tags?.includes("knowledge") || task.tags?.includes("shared"));
|
|
115223
116922
|
if (shouldShareWithSwarm) {
|
|
115224
116923
|
try {
|
|
115225
|
-
|
|
116924
|
+
await indexMemoryContent({
|
|
115226
116925
|
agentId: agentId ?? null,
|
|
115227
|
-
scope: "swarm",
|
|
115228
|
-
name: `Shared: ${safeTask.slice(0, 80)}`,
|
|
115229
116926
|
content: `Task completed by agent ${agentId}:
|
|
115230
116927
|
|
|
115231
116928
|
${taskContent}`,
|
|
116929
|
+
name: `Shared: ${safeTask.slice(0, 80)}`,
|
|
116930
|
+
scope: "swarm",
|
|
115232
116931
|
source: "task_completion",
|
|
115233
|
-
sourceTaskId: taskId
|
|
116932
|
+
sourceTaskId: taskId,
|
|
116933
|
+
key,
|
|
116934
|
+
intent: "task completion memory",
|
|
116935
|
+
replaceExisting: true
|
|
115234
116936
|
});
|
|
115235
|
-
const swarmEmbedding = await provider.embed(taskContent);
|
|
115236
|
-
if (swarmEmbedding) {
|
|
115237
|
-
await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
|
|
115238
|
-
}
|
|
115239
116937
|
} catch {}
|
|
115240
116938
|
}
|
|
115241
|
-
} catch {
|
|
116939
|
+
} catch (err) {
|
|
116940
|
+
console.error("[task-terminal-effects] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err)));
|
|
116941
|
+
}
|
|
115242
116942
|
})().catch((err) => console.error("[task-terminal-effects] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
115243
116943
|
}
|
|
115244
116944
|
(async () => {
|
|
@@ -117929,258 +119629,7 @@ var registerMemoryDeleteTool = (server) => {
|
|
|
117929
119629
|
init_zod();
|
|
117930
119630
|
init_db3();
|
|
117931
119631
|
init_memory();
|
|
117932
|
-
|
|
117933
|
-
// src/be/memory/key-guard.ts
|
|
117934
|
-
init_rbac();
|
|
117935
119632
|
init_key_paths();
|
|
117936
|
-
|
|
117937
|
-
class MemoryKeyError extends Error {
|
|
117938
|
-
reason;
|
|
117939
|
-
constructor(message, reason) {
|
|
117940
|
-
super(message);
|
|
117941
|
-
this.reason = reason;
|
|
117942
|
-
this.name = "MemoryKeyError";
|
|
117943
|
-
}
|
|
117944
|
-
}
|
|
117945
|
-
var NO_AUTHORITY = {
|
|
117946
|
-
principal: { kind: "agent", agentId: "", isLead: false },
|
|
117947
|
-
source: "http"
|
|
117948
|
-
};
|
|
117949
|
-
function shapeError(key, origin) {
|
|
117950
|
-
if (key.length <= MEMORY_KEY_MAX_LENGTH && MEMORY_KEY_PATTERN.test(key))
|
|
117951
|
-
return null;
|
|
117952
|
-
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.`;
|
|
117953
|
-
return `${subject} ${MEMORY_KEY_PATTERN_MESSAGE}`;
|
|
117954
|
-
}
|
|
117955
|
-
function assertKeyWritable(key, origin, writer) {
|
|
117956
|
-
if (origin === "sourcePath" && !isLongtermKey(key))
|
|
117957
|
-
return;
|
|
117958
|
-
const shape = shapeError(key, origin);
|
|
117959
|
-
if (shape)
|
|
117960
|
-
throw new MemoryKeyError(shape, "invalid");
|
|
117961
|
-
const pathError = longtermKeyError(key);
|
|
117962
|
-
if (pathError)
|
|
117963
|
-
throw new MemoryKeyError(pathError, "invalid");
|
|
117964
|
-
if (!isConsolidatedKey(key))
|
|
117965
|
-
return;
|
|
117966
|
-
const { principal, source } = writer ?? NO_AUTHORITY;
|
|
117967
|
-
const decision = can({
|
|
117968
|
-
principal,
|
|
117969
|
-
verb: "memory.write.consolidated",
|
|
117970
|
-
resource: { kind: "none" },
|
|
117971
|
-
source
|
|
117972
|
-
});
|
|
117973
|
-
if (!decision.allow)
|
|
117974
|
-
throw new MemoryKeyError(consolidatedKeyMessage(key), "forbidden");
|
|
117975
|
-
}
|
|
117976
|
-
|
|
117977
|
-
// src/tools/memory-edit.ts
|
|
117978
|
-
init_key_paths();
|
|
117979
|
-
|
|
117980
|
-
// src/be/memory/link-resolver.ts
|
|
117981
|
-
init_db3();
|
|
117982
|
-
init_constants2();
|
|
117983
|
-
var WIKILINK_RE = /\[\[([^\]]+)\]\]/g;
|
|
117984
|
-
var PR_HASH_RE = /(?:^|[\s(])#(\d{1,5})(?=[\s,.)!?]|$)/gm;
|
|
117985
|
-
var PR_PREFIX_RE = /\bPR\s*#(\d{1,5})\b/gi;
|
|
117986
|
-
var GITHUB_PR_URL_RE = /https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+)\/pull\/(\d+)/g;
|
|
117987
|
-
var AGENT_FS_LIVE_HOSTS = String.raw`agent-fs|live\.agent-fs\.dev`;
|
|
117988
|
-
var AGENT_FS_FILE_ROUTE = String.raw`\/file\/~\/([a-f0-9-]+)\/([a-f0-9-]+)\/([\w/.%-]+)`;
|
|
117989
|
-
var AGENT_UI_PAGE_RE = /(?:app\.[^/]+|localhost:\d+)\/pages\/([a-f0-9-]+)/g;
|
|
117990
|
-
var AGENT_UI_TASK_RE = /(?:app\.[^/]+|localhost:\d+)\/tasks\/([a-f0-9-]+)/g;
|
|
117991
|
-
var wikilinkMatcher = (content) => {
|
|
117992
|
-
const results = [];
|
|
117993
|
-
for (const match of content.matchAll(WIKILINK_RE)) {
|
|
117994
|
-
const name = match[1].trim();
|
|
117995
|
-
if (!name)
|
|
117996
|
-
continue;
|
|
117997
|
-
results.push({
|
|
117998
|
-
linkType: "wikilink",
|
|
117999
|
-
targetKind: "memory",
|
|
118000
|
-
targetId: name,
|
|
118001
|
-
sourceText: match[0],
|
|
118002
|
-
resolver: "wikilink"
|
|
118003
|
-
});
|
|
118004
|
-
}
|
|
118005
|
-
return results;
|
|
118006
|
-
};
|
|
118007
|
-
var prMatcher = (content) => {
|
|
118008
|
-
const results = [];
|
|
118009
|
-
const seen = new Set;
|
|
118010
|
-
for (const match of content.matchAll(GITHUB_PR_URL_RE)) {
|
|
118011
|
-
const id = `github:${match[1]}/${match[2]}#${match[3]}`;
|
|
118012
|
-
if (seen.has(id))
|
|
118013
|
-
continue;
|
|
118014
|
-
seen.add(id);
|
|
118015
|
-
results.push({
|
|
118016
|
-
linkType: "pr",
|
|
118017
|
-
targetKind: "pr",
|
|
118018
|
-
targetId: id,
|
|
118019
|
-
sourceText: match[0],
|
|
118020
|
-
resolver: "pr-url",
|
|
118021
|
-
metadata: { owner: match[1], repo: match[2], number: Number(match[3]) }
|
|
118022
|
-
});
|
|
118023
|
-
}
|
|
118024
|
-
for (const match of content.matchAll(PR_PREFIX_RE)) {
|
|
118025
|
-
const id = `pr:${match[1]}`;
|
|
118026
|
-
if (seen.has(id))
|
|
118027
|
-
continue;
|
|
118028
|
-
seen.add(id);
|
|
118029
|
-
results.push({
|
|
118030
|
-
linkType: "pr",
|
|
118031
|
-
targetKind: "pr",
|
|
118032
|
-
targetId: id,
|
|
118033
|
-
sourceText: match[0].trim(),
|
|
118034
|
-
resolver: "pr-prefix",
|
|
118035
|
-
metadata: { number: Number(match[1]) }
|
|
118036
|
-
});
|
|
118037
|
-
}
|
|
118038
|
-
for (const match of content.matchAll(PR_HASH_RE)) {
|
|
118039
|
-
const id = `pr:${match[1]}`;
|
|
118040
|
-
if (seen.has(id))
|
|
118041
|
-
continue;
|
|
118042
|
-
seen.add(id);
|
|
118043
|
-
results.push({
|
|
118044
|
-
linkType: "pr",
|
|
118045
|
-
targetKind: "pr",
|
|
118046
|
-
targetId: id,
|
|
118047
|
-
sourceText: `#${match[1]}`,
|
|
118048
|
-
resolver: "pr-hash",
|
|
118049
|
-
metadata: { number: Number(match[1]) }
|
|
118050
|
-
});
|
|
118051
|
-
}
|
|
118052
|
-
return results;
|
|
118053
|
-
};
|
|
118054
|
-
function escapeRegExp2(value) {
|
|
118055
|
-
return value.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
118056
|
-
}
|
|
118057
|
-
function agentFsPathRegex() {
|
|
118058
|
-
const appHosts = getConfiguredAppUrls().flatMap((value) => {
|
|
118059
|
-
try {
|
|
118060
|
-
const url = new URL(value);
|
|
118061
|
-
return [escapeRegExp2(`${url.host}${url.pathname.replace(/\/+$/, "")}`)];
|
|
118062
|
-
} catch {
|
|
118063
|
-
return [];
|
|
118064
|
-
}
|
|
118065
|
-
});
|
|
118066
|
-
const hosts = [AGENT_FS_LIVE_HOSTS, ...appHosts, String.raw`localhost:\d+`].join("|");
|
|
118067
|
-
return new RegExp(`(?<![\\w.-])(?:${hosts})${AGENT_FS_FILE_ROUTE}`, "gi");
|
|
118068
|
-
}
|
|
118069
|
-
var agentFsMatcher = (content) => {
|
|
118070
|
-
const results = [];
|
|
118071
|
-
for (const match of content.matchAll(agentFsPathRegex())) {
|
|
118072
|
-
const orgId = match[1];
|
|
118073
|
-
const driveId = match[2];
|
|
118074
|
-
const path = match[3];
|
|
118075
|
-
results.push({
|
|
118076
|
-
linkType: "agent-fs-file",
|
|
118077
|
-
targetKind: "agent-fs-file",
|
|
118078
|
-
targetId: `${orgId}/${driveId}/${path}`,
|
|
118079
|
-
sourceText: match[0],
|
|
118080
|
-
resolver: "agent-fs-path",
|
|
118081
|
-
metadata: { orgId, driveId, path }
|
|
118082
|
-
});
|
|
118083
|
-
}
|
|
118084
|
-
return results;
|
|
118085
|
-
};
|
|
118086
|
-
var agentUiMatcher = (content) => {
|
|
118087
|
-
const results = [];
|
|
118088
|
-
for (const match of content.matchAll(AGENT_UI_PAGE_RE)) {
|
|
118089
|
-
results.push({
|
|
118090
|
-
linkType: "agent-ui",
|
|
118091
|
-
targetKind: "agent-ui",
|
|
118092
|
-
targetId: `page:${match[1]}`,
|
|
118093
|
-
sourceText: match[0],
|
|
118094
|
-
resolver: "agent-ui-page"
|
|
118095
|
-
});
|
|
118096
|
-
}
|
|
118097
|
-
for (const match of content.matchAll(AGENT_UI_TASK_RE)) {
|
|
118098
|
-
results.push({
|
|
118099
|
-
linkType: "agent-ui",
|
|
118100
|
-
targetKind: "agent-ui",
|
|
118101
|
-
targetId: `task:${match[1]}`,
|
|
118102
|
-
sourceText: match[0],
|
|
118103
|
-
resolver: "agent-ui-task"
|
|
118104
|
-
});
|
|
118105
|
-
}
|
|
118106
|
-
return results;
|
|
118107
|
-
};
|
|
118108
|
-
var MATCHERS = [wikilinkMatcher, prMatcher, agentFsMatcher, agentUiMatcher];
|
|
118109
|
-
function resolveLinks(content) {
|
|
118110
|
-
const results = [];
|
|
118111
|
-
for (const matcher of MATCHERS) {
|
|
118112
|
-
for (const link of matcher(content)) {
|
|
118113
|
-
results.push({ ...link, strength: 1 });
|
|
118114
|
-
}
|
|
118115
|
-
}
|
|
118116
|
-
return results;
|
|
118117
|
-
}
|
|
118118
|
-
async function resolveWikilinksToMemoryIds(agentId, links) {
|
|
118119
|
-
const db = getDbClient2();
|
|
118120
|
-
const resolved = [];
|
|
118121
|
-
for (const link of links) {
|
|
118122
|
-
if (link.linkType !== "wikilink") {
|
|
118123
|
-
resolved.push(link);
|
|
118124
|
-
continue;
|
|
118125
|
-
}
|
|
118126
|
-
const row = await db.get("SELECT id FROM agent_memory WHERE name = ? AND (agentId = ? OR scope = 'swarm') LIMIT 1", [link.targetId, agentId]);
|
|
118127
|
-
resolved.push(row ? { ...link, targetId: row.id } : link);
|
|
118128
|
-
}
|
|
118129
|
-
return resolved;
|
|
118130
|
-
}
|
|
118131
|
-
var INSERT_LINK_SQL = `INSERT OR IGNORE INTO memory_link
|
|
118132
|
-
(id, from_memory_id, linkType, targetKind, targetId, strength, resolver, sourceText, metadata, createdAt, updatedAt)
|
|
118133
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
118134
|
-
function insertLinkArgs(memoryId, link, now) {
|
|
118135
|
-
return [
|
|
118136
|
-
crypto.randomUUID(),
|
|
118137
|
-
memoryId,
|
|
118138
|
-
link.linkType,
|
|
118139
|
-
link.targetKind,
|
|
118140
|
-
link.targetId,
|
|
118141
|
-
link.strength,
|
|
118142
|
-
link.resolver,
|
|
118143
|
-
link.sourceText,
|
|
118144
|
-
link.metadata ? JSON.stringify(link.metadata) : null,
|
|
118145
|
-
now,
|
|
118146
|
-
now
|
|
118147
|
-
];
|
|
118148
|
-
}
|
|
118149
|
-
async function storeLinks(memoryId, agentId, content) {
|
|
118150
|
-
const links = resolveLinks(content);
|
|
118151
|
-
if (links.length === 0)
|
|
118152
|
-
return;
|
|
118153
|
-
const resolved = await resolveWikilinksToMemoryIds(agentId, links);
|
|
118154
|
-
const now = new Date().toISOString();
|
|
118155
|
-
await getDbClient2().transaction(async (tx) => {
|
|
118156
|
-
for (const link of resolved) {
|
|
118157
|
-
await tx.run(INSERT_LINK_SQL, insertLinkArgs(memoryId, link, now));
|
|
118158
|
-
}
|
|
118159
|
-
});
|
|
118160
|
-
}
|
|
118161
|
-
function linkIdentity2(link) {
|
|
118162
|
-
return JSON.stringify([link.linkType, link.targetKind, link.targetId, link.sourceText ?? null]);
|
|
118163
|
-
}
|
|
118164
|
-
async function refreshLinks(memoryId, agentId, content) {
|
|
118165
|
-
const resolved = await resolveWikilinksToMemoryIds(agentId, resolveLinks(content));
|
|
118166
|
-
const nextIdentities = new Set(resolved.map((link) => linkIdentity2(link)));
|
|
118167
|
-
const now = new Date().toISOString();
|
|
118168
|
-
await getDbClient2().transaction(async (tx) => {
|
|
118169
|
-
const existing = await tx.query(`SELECT id, linkType, targetKind, targetId, sourceText
|
|
118170
|
-
FROM memory_link
|
|
118171
|
-
WHERE from_memory_id = ? AND linkType != 'sequel'`, [memoryId]);
|
|
118172
|
-
for (const row of existing) {
|
|
118173
|
-
if (!nextIdentities.has(linkIdentity2(row))) {
|
|
118174
|
-
await tx.run("DELETE FROM memory_link WHERE id = ?", [row.id]);
|
|
118175
|
-
}
|
|
118176
|
-
}
|
|
118177
|
-
for (const link of resolved) {
|
|
118178
|
-
await tx.run(INSERT_LINK_SQL, insertLinkArgs(memoryId, link, now));
|
|
118179
|
-
}
|
|
118180
|
-
});
|
|
118181
|
-
}
|
|
118182
|
-
|
|
118183
|
-
// src/tools/memory-edit.ts
|
|
118184
119633
|
init_rbac();
|
|
118185
119634
|
init_types();
|
|
118186
119635
|
var agentMemoryOutputSchema = looseObject({
|
|
@@ -118744,6 +120193,7 @@ async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
|
|
|
118744
120193
|
// src/tools/memory-search.ts
|
|
118745
120194
|
init_key_paths();
|
|
118746
120195
|
init_reranker();
|
|
120196
|
+
init_search_candidates();
|
|
118747
120197
|
init_types();
|
|
118748
120198
|
var NUDGE_ELIGIBLE_SOURCES2 = new Set(["manual", "file_index"]);
|
|
118749
120199
|
function rateHintFor(memoryId) {
|
|
@@ -118799,7 +120249,7 @@ var registerMemorySearchTool = (server) => {
|
|
|
118799
120249
|
const store = getMemoryStore2();
|
|
118800
120250
|
const queryEmbedding = await provider.embed(query);
|
|
118801
120251
|
const candidateLimit = limit * CANDIDATE_SET_MULTIPLIER;
|
|
118802
|
-
const candidates = await store
|
|
120252
|
+
const candidates = await searchMemoryCandidates(store, queryEmbedding ?? new Float32Array(0), requestInfo.agentId, {
|
|
118803
120253
|
scope,
|
|
118804
120254
|
limit: candidateLimit,
|
|
118805
120255
|
source,
|
|
@@ -118887,242 +120337,6 @@ var registerMemorySearchTool = (server) => {
|
|
|
118887
120337
|
// src/tools/memory-store.ts
|
|
118888
120338
|
init_zod();
|
|
118889
120339
|
init_db3();
|
|
118890
|
-
|
|
118891
|
-
// src/be/chunking.ts
|
|
118892
|
-
var MAX_CHUNK_SIZE = 2000;
|
|
118893
|
-
var CHUNK_OVERLAP = 100;
|
|
118894
|
-
var MIN_CHUNK_SIZE = 50;
|
|
118895
|
-
function chunkContent(text) {
|
|
118896
|
-
const trimmed = text.trim();
|
|
118897
|
-
if (!trimmed || trimmed.length < MIN_CHUNK_SIZE) {
|
|
118898
|
-
return [];
|
|
118899
|
-
}
|
|
118900
|
-
if (trimmed.length <= MAX_CHUNK_SIZE) {
|
|
118901
|
-
return [{ content: trimmed, chunkIndex: 0, totalChunks: 1, headings: [] }];
|
|
118902
|
-
}
|
|
118903
|
-
const sections = splitByHeaders(trimmed);
|
|
118904
|
-
const rawChunks = [];
|
|
118905
|
-
for (const section of sections) {
|
|
118906
|
-
if (section.content.length <= MAX_CHUNK_SIZE) {
|
|
118907
|
-
rawChunks.push(section);
|
|
118908
|
-
} else {
|
|
118909
|
-
const subChunks = recursiveSplit(section.content);
|
|
118910
|
-
for (const sub of subChunks) {
|
|
118911
|
-
rawChunks.push({ content: sub, headings: section.headings });
|
|
118912
|
-
}
|
|
118913
|
-
}
|
|
118914
|
-
}
|
|
118915
|
-
const filtered = rawChunks.filter((c) => c.content.trim().length >= MIN_CHUNK_SIZE);
|
|
118916
|
-
if (filtered.length === 0) {
|
|
118917
|
-
return [{ content: trimmed, chunkIndex: 0, totalChunks: 1, headings: [] }];
|
|
118918
|
-
}
|
|
118919
|
-
return filtered.map((c, i) => ({
|
|
118920
|
-
content: c.headings.length > 0 ? `${c.headings.join(" > ")}
|
|
118921
|
-
|
|
118922
|
-
${c.content}` : c.content,
|
|
118923
|
-
chunkIndex: i,
|
|
118924
|
-
totalChunks: filtered.length,
|
|
118925
|
-
headings: c.headings
|
|
118926
|
-
}));
|
|
118927
|
-
}
|
|
118928
|
-
function splitByHeaders(text) {
|
|
118929
|
-
const lines = text.split(`
|
|
118930
|
-
`);
|
|
118931
|
-
const sections = [];
|
|
118932
|
-
let currentContent = [];
|
|
118933
|
-
const headingStack = [];
|
|
118934
|
-
for (const line of lines) {
|
|
118935
|
-
const headingMatch = line.match(/^(#{1,3})\s+(.+)$/);
|
|
118936
|
-
if (headingMatch) {
|
|
118937
|
-
if (currentContent.length > 0) {
|
|
118938
|
-
const content = currentContent.join(`
|
|
118939
|
-
`).trim();
|
|
118940
|
-
if (content) {
|
|
118941
|
-
sections.push({ content, headings: [...headingStack] });
|
|
118942
|
-
}
|
|
118943
|
-
currentContent = [];
|
|
118944
|
-
}
|
|
118945
|
-
const level = headingMatch[1].length;
|
|
118946
|
-
const title = headingMatch[2].trim();
|
|
118947
|
-
while (headingStack.length >= level) {
|
|
118948
|
-
headingStack.pop();
|
|
118949
|
-
}
|
|
118950
|
-
headingStack.push(`${"#".repeat(level)} ${title}`);
|
|
118951
|
-
} else {
|
|
118952
|
-
currentContent.push(line);
|
|
118953
|
-
}
|
|
118954
|
-
}
|
|
118955
|
-
if (currentContent.length > 0) {
|
|
118956
|
-
const content = currentContent.join(`
|
|
118957
|
-
`).trim();
|
|
118958
|
-
if (content) {
|
|
118959
|
-
sections.push({ content, headings: [...headingStack] });
|
|
118960
|
-
}
|
|
118961
|
-
}
|
|
118962
|
-
if (sections.length === 0) {
|
|
118963
|
-
return [{ content: text, headings: [] }];
|
|
118964
|
-
}
|
|
118965
|
-
return sections;
|
|
118966
|
-
}
|
|
118967
|
-
var SEPARATORS = [`
|
|
118968
|
-
|
|
118969
|
-
`, `
|
|
118970
|
-
`, ". ", " "];
|
|
118971
|
-
function recursiveSplit(text) {
|
|
118972
|
-
return recursiveSplitWithSeparators(text, 0);
|
|
118973
|
-
}
|
|
118974
|
-
function recursiveSplitWithSeparators(text, separatorIndex) {
|
|
118975
|
-
if (text.length <= MAX_CHUNK_SIZE) {
|
|
118976
|
-
return [text.trim()].filter((s) => s.length > 0);
|
|
118977
|
-
}
|
|
118978
|
-
if (separatorIndex >= SEPARATORS.length) {
|
|
118979
|
-
return hardSplit(text);
|
|
118980
|
-
}
|
|
118981
|
-
const separator = SEPARATORS[separatorIndex];
|
|
118982
|
-
const parts = text.split(separator);
|
|
118983
|
-
if (parts.length <= 1) {
|
|
118984
|
-
return recursiveSplitWithSeparators(text, separatorIndex + 1);
|
|
118985
|
-
}
|
|
118986
|
-
const chunks = [];
|
|
118987
|
-
let current = "";
|
|
118988
|
-
for (const part of parts) {
|
|
118989
|
-
const candidate = current ? current + separator + part : part;
|
|
118990
|
-
if (candidate.length <= MAX_CHUNK_SIZE) {
|
|
118991
|
-
current = candidate;
|
|
118992
|
-
} else {
|
|
118993
|
-
if (current) {
|
|
118994
|
-
chunks.push(current.trim());
|
|
118995
|
-
}
|
|
118996
|
-
if (part.length > MAX_CHUNK_SIZE) {
|
|
118997
|
-
chunks.push(...recursiveSplitWithSeparators(part, separatorIndex + 1));
|
|
118998
|
-
current = "";
|
|
118999
|
-
} else {
|
|
119000
|
-
current = part;
|
|
119001
|
-
}
|
|
119002
|
-
}
|
|
119003
|
-
}
|
|
119004
|
-
if (current.trim()) {
|
|
119005
|
-
chunks.push(current.trim());
|
|
119006
|
-
}
|
|
119007
|
-
return addOverlap(chunks, text);
|
|
119008
|
-
}
|
|
119009
|
-
function hardSplit(text) {
|
|
119010
|
-
const chunks = [];
|
|
119011
|
-
let start = 0;
|
|
119012
|
-
while (start < text.length) {
|
|
119013
|
-
const end = Math.min(start + MAX_CHUNK_SIZE, text.length);
|
|
119014
|
-
chunks.push(text.slice(start, end).trim());
|
|
119015
|
-
if (end === text.length)
|
|
119016
|
-
break;
|
|
119017
|
-
start = end - CHUNK_OVERLAP;
|
|
119018
|
-
}
|
|
119019
|
-
return chunks.filter((c) => c.length > 0);
|
|
119020
|
-
}
|
|
119021
|
-
function addOverlap(chunks, _originalText) {
|
|
119022
|
-
if (chunks.length <= 1)
|
|
119023
|
-
return chunks;
|
|
119024
|
-
const result = [chunks[0]];
|
|
119025
|
-
for (let i = 1;i < chunks.length; i++) {
|
|
119026
|
-
const prevChunk = chunks[i - 1];
|
|
119027
|
-
const chunk = chunks[i];
|
|
119028
|
-
const overlapText = prevChunk.slice(-CHUNK_OVERLAP);
|
|
119029
|
-
if (overlapText.length + chunk.length <= MAX_CHUNK_SIZE + CHUNK_OVERLAP) {
|
|
119030
|
-
result.push(overlapText + chunk);
|
|
119031
|
-
} else {
|
|
119032
|
-
result.push(chunk);
|
|
119033
|
-
}
|
|
119034
|
-
}
|
|
119035
|
-
return result;
|
|
119036
|
-
}
|
|
119037
|
-
|
|
119038
|
-
// src/be/memory/index-content.ts
|
|
119039
|
-
init_memory();
|
|
119040
|
-
init_secret_scrubber();
|
|
119041
|
-
async function indexMemoryContent(params) {
|
|
119042
|
-
const { agentId, content, name, scope, source, sourceTaskId, sourcePath, tags } = params;
|
|
119043
|
-
const rowKey = params.key ?? (sourcePath || null);
|
|
119044
|
-
if (rowKey)
|
|
119045
|
-
assertKeyWritable(rowKey, params.key != null ? "key" : "sourcePath", params.writer);
|
|
119046
|
-
const contentChunks = chunkContent(content);
|
|
119047
|
-
if (contentChunks.length === 0) {
|
|
119048
|
-
contentChunks.push({
|
|
119049
|
-
content: content.trim(),
|
|
119050
|
-
chunkIndex: 0,
|
|
119051
|
-
totalChunks: 1,
|
|
119052
|
-
headings: []
|
|
119053
|
-
});
|
|
119054
|
-
}
|
|
119055
|
-
const store = getMemoryStore2();
|
|
119056
|
-
const provider = getEmbeddingProvider2();
|
|
119057
|
-
if (sourcePath && agentId && contentChunks.length === 1) {
|
|
119058
|
-
const existing = (await store.list(agentId, {
|
|
119059
|
-
scope,
|
|
119060
|
-
limit: 2,
|
|
119061
|
-
ownerAgentId: agentId,
|
|
119062
|
-
sourcePath
|
|
119063
|
-
})).filter((memory) => memory.sourcePath === sourcePath);
|
|
119064
|
-
if (existing.length === 1 && existing[0]?.totalChunks === 1) {
|
|
119065
|
-
const result = await store.edit({
|
|
119066
|
-
id: existing[0].id,
|
|
119067
|
-
mode: "replace",
|
|
119068
|
-
content: contentChunks[0].content,
|
|
119069
|
-
intent: "re-index memory source path",
|
|
119070
|
-
changedByAgentId: agentId
|
|
119071
|
-
});
|
|
119072
|
-
const embedding = await provider.embed(result.memory.content);
|
|
119073
|
-
if (embedding)
|
|
119074
|
-
await store.updateEmbedding(result.memory.id, embedding, provider.name);
|
|
119075
|
-
try {
|
|
119076
|
-
await refreshLinks(result.memory.id, agentId, result.memory.content);
|
|
119077
|
-
} catch (err) {
|
|
119078
|
-
console.error(`[memory] Link resolution failed for ${result.memory.id}:`, err.message);
|
|
119079
|
-
}
|
|
119080
|
-
return { queued: false, memoryIds: [result.memory.id], edited: result.changed, chunks: 1 };
|
|
119081
|
-
}
|
|
119082
|
-
}
|
|
119083
|
-
if (sourcePath && agentId) {
|
|
119084
|
-
await store.deleteBySourcePath(sourcePath, agentId);
|
|
119085
|
-
}
|
|
119086
|
-
const memories = await store.storeBatch(contentChunks.map((chunk) => ({
|
|
119087
|
-
agentId: agentId || null,
|
|
119088
|
-
content: chunk.content,
|
|
119089
|
-
name,
|
|
119090
|
-
scope,
|
|
119091
|
-
source,
|
|
119092
|
-
sourcePath: sourcePath || null,
|
|
119093
|
-
sourceTaskId: sourceTaskId || null,
|
|
119094
|
-
chunkIndex: chunk.chunkIndex,
|
|
119095
|
-
totalChunks: chunk.totalChunks,
|
|
119096
|
-
tags: tags || [],
|
|
119097
|
-
contextKey: params.contextKey ?? null,
|
|
119098
|
-
intent: params.intent ?? "index memory content",
|
|
119099
|
-
key: rowKey
|
|
119100
|
-
})));
|
|
119101
|
-
if (agentId) {
|
|
119102
|
-
for (const memory of memories) {
|
|
119103
|
-
try {
|
|
119104
|
-
await storeLinks(memory.id, agentId, memory.content);
|
|
119105
|
-
} catch (err) {
|
|
119106
|
-
console.error(`[memory] Link resolution failed for ${memory.id}:`, err.message);
|
|
119107
|
-
}
|
|
119108
|
-
}
|
|
119109
|
-
}
|
|
119110
|
-
(async () => {
|
|
119111
|
-
try {
|
|
119112
|
-
const embeddings = await provider.embedBatch(memories.map((m) => m.content));
|
|
119113
|
-
for (let i = 0;i < embeddings.length; i++) {
|
|
119114
|
-
if (embeddings[i]) {
|
|
119115
|
-
await store.updateEmbedding(memories[i].id, embeddings[i], provider.name);
|
|
119116
|
-
}
|
|
119117
|
-
}
|
|
119118
|
-
} catch (err) {
|
|
119119
|
-
console.error("[memory] Batch embedding failed:", err.message);
|
|
119120
|
-
}
|
|
119121
|
-
})().catch((err) => console.error("[memory] batch embed failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
|
|
119122
|
-
return { queued: true, memoryIds: memories.map((m) => m.id), chunks: contentChunks.length };
|
|
119123
|
-
}
|
|
119124
|
-
|
|
119125
|
-
// src/tools/memory-store.ts
|
|
119126
120340
|
init_key_paths();
|
|
119127
120341
|
init_types();
|
|
119128
120342
|
var registerMemoryStoreTool = (server) => {
|
|
@@ -129545,7 +130759,7 @@ var registerScriptConnectionsTool = (server) => {
|
|
|
129545
130759
|
};
|
|
129546
130760
|
// src/tools/script-delete.ts
|
|
129547
130761
|
init_zod();
|
|
129548
|
-
var SCRIPT_DELETE_DESCRIPTION = "
|
|
130762
|
+
var SCRIPT_DELETE_DESCRIPTION = "Permanently remove a swarm-shared script and all its versions from the catalog. This cannot be undone.";
|
|
129549
130763
|
var registerScriptDeleteTool = (server) => {
|
|
129550
130764
|
createToolRegistrar(server)("script-delete", {
|
|
129551
130765
|
title: "Script Delete",
|
|
@@ -131658,33 +132872,35 @@ function formatFileSize2(bytes) {
|
|
|
131658
132872
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
131659
132873
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
131660
132874
|
}
|
|
131661
|
-
function buildAttachmentText(files, failed = []) {
|
|
132875
|
+
function buildAttachmentText(files, failed = [], notes = new Map) {
|
|
131662
132876
|
const reasons = new Map(failed.map((f) => [f.file.id, f.reason]));
|
|
131663
132877
|
return files.map((f) => {
|
|
131664
132878
|
const size = typeof f.size === "number" ? formatFileSize2(f.size) : "unknown size";
|
|
131665
132879
|
const line = `[File: ${f.name ?? f.id} (${f.mimetype ?? "unknown type"}, ${size}) id=${f.id}]`;
|
|
131666
132880
|
const reason = reasons.get(f.id);
|
|
131667
|
-
|
|
132881
|
+
const note = notes.get(f.id);
|
|
132882
|
+
return [reason ? `${line} (not attached: ${reason})` : line, note].filter(Boolean).join(`
|
|
132883
|
+
`);
|
|
131668
132884
|
}).join(`
|
|
131669
132885
|
`);
|
|
131670
132886
|
}
|
|
131671
|
-
function buildEffectiveText(text, files, failed) {
|
|
132887
|
+
function buildEffectiveText(text, files, failed, notes) {
|
|
131672
132888
|
const hasText = !!text?.trim();
|
|
131673
132889
|
const hasFiles = files && files.length > 0;
|
|
131674
132890
|
if (hasText && hasFiles) {
|
|
131675
132891
|
return `${text}
|
|
131676
132892
|
|
|
131677
|
-
${buildAttachmentText(files, failed)}`;
|
|
132893
|
+
${buildAttachmentText(files, failed, notes)}`;
|
|
131678
132894
|
}
|
|
131679
132895
|
if (hasFiles) {
|
|
131680
|
-
return buildAttachmentText(files, failed);
|
|
132896
|
+
return buildAttachmentText(files, failed, notes);
|
|
131681
132897
|
}
|
|
131682
132898
|
return text || "";
|
|
131683
132899
|
}
|
|
131684
132900
|
function bufferedFileFailures(files) {
|
|
131685
132901
|
return (files ?? []).map((file) => ({ file, reason: BUFFERED_REASON }));
|
|
131686
132902
|
}
|
|
131687
|
-
async function fetchSlackFiles(client, files) {
|
|
132903
|
+
async function fetchSlackFiles(client, files, options = {}) {
|
|
131688
132904
|
let dir;
|
|
131689
132905
|
const result = {
|
|
131690
132906
|
files: [],
|
|
@@ -131710,8 +132926,19 @@ async function fetchSlackFiles(client, files) {
|
|
|
131710
132926
|
result.fetched.push({ file, ...outcome });
|
|
131711
132927
|
}
|
|
131712
132928
|
}
|
|
132929
|
+
if (options.transcribe) {
|
|
132930
|
+
result.notes = await transcribeAudioNotes(result.fetched.filter(({ file }) => isSlackAudio(file)).map(({ file, path }) => ({
|
|
132931
|
+
key: file.id,
|
|
132932
|
+
name: file.name ?? file.id,
|
|
132933
|
+
data: Bun.file(path),
|
|
132934
|
+
mimeType: file.mimetype
|
|
132935
|
+
})), "[Slack]");
|
|
132936
|
+
}
|
|
131713
132937
|
return result;
|
|
131714
132938
|
}
|
|
132939
|
+
function isSlackAudio(file) {
|
|
132940
|
+
return file.subtype === "slack_audio" || Boolean(file.mimetype?.startsWith("audio/"));
|
|
132941
|
+
}
|
|
131715
132942
|
function looksLikeSignIn(head) {
|
|
131716
132943
|
const joined = new Uint8Array(head.reduce((total, part) => total + part.byteLength, 0));
|
|
131717
132944
|
let offset = 0;
|
|
@@ -133925,9 +135152,9 @@ var registerSystemOneDecideTool = (server) => {
|
|
|
133925
135152
|
createToolRegistrar(server)("system-one-decide", {
|
|
133926
135153
|
title: "Ask a SystemOne decision model",
|
|
133927
135154
|
annotations: { destructiveHint: false, openWorldHint: true },
|
|
133928
|
-
description: "Send a state and typed questions (noul, choice, score) to a SystemOne decision host such as Jev, and return the validated answers. " + "Same request, provider list, credentials and validation as the `system-one-decision` workflow node, without its human review band. " + "The provider credential is a global secret that stays on the server; this tool never returns it.",
|
|
135155
|
+
description: "Send a state and typed questions (noul, choice, score) to a SystemOne decision host such as Jev or Clef, and return the validated answers. " + "Same request, provider list, credentials and validation as the `system-one-decision` workflow node, without its human review band. " + "The provider credential is a global secret that stays on the server; this tool never returns it.",
|
|
133929
135156
|
inputSchema: object2({
|
|
133930
|
-
provider: _enum2(SYSTEM_ONE_PROVIDER_IDS).optional().describe("Decision host (default typesafe)"),
|
|
135157
|
+
provider: _enum2(SYSTEM_ONE_PROVIDER_IDS).optional().describe("Decision host (default: the SYSTEM_ONE_DEFAULT_PROVIDER global config, typesafe when unset)"),
|
|
133931
135158
|
model: string2().min(1).optional().describe("Provider model id (default: the provider's)"),
|
|
133932
135159
|
state: union2([string2(), array2(string2()), record2(string2(), unknown())]).describe("The state to decide on"),
|
|
133933
135160
|
questions: record2(string2(), record2(string2(), unknown())).describe("Questions by id, each `{ type: 'noul' | 'choice' | 'score', instructions, criteria }`"),
|
|
@@ -133938,7 +135165,8 @@ var registerSystemOneDecideTool = (server) => {
|
|
|
133938
135165
|
model: string2().optional(),
|
|
133939
135166
|
answers: record2(string2(), unknown()).optional(),
|
|
133940
135167
|
usage: record2(string2(), unknown()).optional(),
|
|
133941
|
-
requestId: string2().optional()
|
|
135168
|
+
requestId: string2().optional(),
|
|
135169
|
+
providerUnavailable: boolean().optional().describe("On an error: true when this deployment refuses the provider (e.g. OpenRouter behind a gateway) and no request was sent, so a caller choosing automatically can try its next provider")
|
|
133942
135170
|
})
|
|
133943
135171
|
}, async ({ provider, model, state, questions, timeoutMs, maxRetries }, requestInfo) => {
|
|
133944
135172
|
if (!requestInfo.agentId) {
|
|
@@ -133963,8 +135191,9 @@ var registerSystemOneDecideTool = (server) => {
|
|
|
133963
135191
|
return toolErr("The system-one-decision executor is not available");
|
|
133964
135192
|
}
|
|
133965
135193
|
const decided = await executor.decide(parsed.data);
|
|
133966
|
-
if (!decided.ok)
|
|
133967
|
-
return toolErr(decided.error);
|
|
135194
|
+
if (!decided.ok) {
|
|
135195
|
+
return toolErr(decided.error, decided.deploymentRefused ? { data: { providerUnavailable: true } } : {});
|
|
135196
|
+
}
|
|
133968
135197
|
const { output } = decided;
|
|
133969
135198
|
return toolOk(`Decision from ${output.model}`, {
|
|
133970
135199
|
data: {
|
|
@@ -134099,7 +135328,7 @@ async function emitBudgetRefusalSideEffects(ctx, inserted) {
|
|
|
134099
135328
|
console.warn(`[budget-refusal-notify] Failed to create follow-up task for budget refusal (task=${ctx.task.id.slice(0, 8)}): ${err}`);
|
|
134100
135329
|
}
|
|
134101
135330
|
}
|
|
134102
|
-
import("./event-bus-
|
|
135331
|
+
import("./event-bus-3z78ep5n.js").then(({ workflowEventBus }) => {
|
|
134103
135332
|
workflowEventBus.emit("task.budget_refused", {
|
|
134104
135333
|
taskId: ctx.task.id,
|
|
134105
135334
|
agentId: ctx.agentId,
|
|
@@ -135150,7 +136379,7 @@ var registerCreateWorkflowTool = (server) => {
|
|
|
135150
136379
|
` + "- CROSS-NODE DATA: To use output from an upstream node, you MUST declare an 'inputs' mapping on the downstream node. " + 'Example: inputs: { "cityData": "generate-city" } → then use {{cityData.taskOutput.field}} in config templates. ' + "Without 'inputs', built-in trigger/input/workflow/swarm/run context remains available, but upstream outputs do not. " + "Agent-task templates may interpolate trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not: " + "inline script source allows only input/workflow/swarm/run values, while named swarm-script source is not workflow-interpolated. " + `Pass dynamic trigger or upstream values through config.args (argv for inline scripts; the args object for swarm-script).
|
|
135151
136380
|
` + "- STRUCTURED OUTPUT: For agent-task nodes, put outputSchema inside 'config' to validate the agent's raw JSON output. " + `Node-level outputSchema validates the executor's return ({taskId, taskOutput}), which is different.
|
|
135152
136381
|
` + `- Agent-task config: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }.
|
|
135153
|
-
` + "- FOREACH NODE: type 'foreach'
|
|
136382
|
+
` + "- FOREACH NODE: type 'foreach' runs its body once per item. Config: " + "{ over: <array or exact {{input}} token>, itemKey: <property name>, body: { type: <any executor except foreach>, config: {...} }, " + "concurrency?: <integer >= 1, items in flight; unbounded when absent>, failurePolicy?: 'fail-fast' | 'collect-outcomes' }. " + "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. " + "failurePolicy defaults from onNodeFailure ('continue' = collect-outcomes, else fail-fast); fail-fast cancels queued items. " + `retry-workflow-run on a failed fan-out reruns only failed and cancelled items.
|
|
135154
136383
|
` + "- 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.
|
|
135155
136384
|
` + "- 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 } }.
|
|
135156
136385
|
` + "- 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.",
|
|
@@ -135961,7 +137190,8 @@ async function createServer(opts = {}) {
|
|
|
135961
137190
|
...opts.preloadedTools?.length ? { instructions: resolveTemplate("system.agent.tool_preload", {}).text } : {},
|
|
135962
137191
|
capabilities: {
|
|
135963
137192
|
logging: {}
|
|
135964
|
-
}
|
|
137193
|
+
},
|
|
137194
|
+
maxToolInputElements: MCP_MAX_TOOL_INPUT_ELEMENTS
|
|
135965
137195
|
});
|
|
135966
137196
|
if (opts.preloadedTools?.length)
|
|
135967
137197
|
setPreloadedTools(server, opts.preloadedTools);
|
|
@@ -136196,4 +137426,4 @@ async function createServer(opts = {}) {
|
|
|
136196
137426
|
return server;
|
|
136197
137427
|
}
|
|
136198
137428
|
|
|
136199
|
-
export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, resolveIdentity, renderIdentity, createAdditiveBuffer, taskModelPin, resumedTaskModelSelection, 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, isRuntimePoolWakeable, isAgentReachable, hasOtherUserMention, broadcastMatches, routeMessage, extractTaskFromMessage, extractSlackMessageText, recoverIncompleteRuns, handleWebhookTrigger, verifyHmacSignature, WebhookError, snapshotAndUpdateWorkflow, RawLlmConfigSchema, RawLlmOutputSchema, executeRawLlm, getExecutorRegistry2, initWorkflows2, dispatchScheduleTarget, calculateNextRun2, startScheduler2, stopScheduler2, runScheduleNow2, ExtensionAssetConflictError, ExtensionOwnershipError, getExtensionFiles, getExtensionById, getExtensionByName, listExtensions, listExtensionVersions, updateExtensionMeta, listExtensionRuns, SDK_ALLOWLIST, mcpToolNameForSdkMethod, mcpOverflowAuthError, hasKvViewArgs, resolveKvView, toolErr, createToolRegistrar, handleMcpBridge, Redacted, SCRIPT_SDK_RESPONSE_LIMIT_BYTES, readScriptSdkJsonResponse, ExtensionConfigError, ExtensionLifecycleError, setExtensionLoopbackBaseUrl, enableExtension, disableExtension, activateVersion, ExtensionAssetsInvalidError, installExtensionWithAssets, uninstallExtension, reloadExtension, loadEnabledExtensions, stopExtensionRuntime, ExtensionAbortedError2, isRegistered2, isExtensionAgentId2, getExtensionBridgeToken2, resolveBridgeCallOrigin2, extensionIdForAgent2, runContext2, registerLoaded2, unregister2, listRegistered2, dispatchPre2, dispatchPost2, stripSiblingBlock, createTaskWithSiblingAwareness, isInboxAllowed, isSenderAllowed, handleMessageReceived, isAzureDevOpsEnabled, initAzureDevOps, verifyAzureDevOpsWebhook, repointTrackerSyncBySwarmId, isAzureDevOpsUrl, canonicalAzureDevOpsRepoUrl, parseAzureDevOpsRepoUrl, createdPullRequestOf, commentedPayloadOf, handlePullRequestCreated, handlePullRequestCommented, handleWorkItemCreated, handleWorkItemUpdated, handleWorkItemCommented, handleWorkItemDeleted, handleWorkItemRestored, initAzureDevOpsOutbound, AGENT_MAX_TASKS_CONFIG_KEY, reconcileAgentMaxTasksPolicy, resetAgentMaxTasksMirror, upsertSwarmConfigWithPolicyMirror, runtimeStaleThresholdMinutes, upsertRuntimeInstance, getRuntimeInstanceById, insertProvisioningRuntime, markRuntimeTerminated, touchRuntimeInstance, countActiveRuntimeInstancesForAgent, listRuntimeInstancesForAgent, setRuntimeCredentialReady, reconcileAgentStatusFromRuntimes, agentsWithLiveRuntime, expireStaleRuntimeInstances, listRuntimeInstancesForPool, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, getTelemetryIngestAnchor, initApiTelemetry, syncTelemetryEnabled, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2, handleNote, handlePipeline, isChatSdkEnabled, getChatSdkConfig, errorMessage, resolveAdapterApiUrl, trackBackground, TelegramBotApiError, callTelegramBotApi, isTrustedTeamsServiceUrl, isChatSdkStopping, startChatSdk, getChatInstance, isChatAdapterConfigured, getChatSdkHealth, stopChatSdk, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear,
|
|
137429
|
+
export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, resolveIdentity, renderIdentity, createAdditiveBuffer, taskModelPin, resumedTaskModelSelection, listHarnessModelSupport, recordHarnessModelSupport, agentRanModel, getAgentHarnessCliVersion, setAgentHarnessCliVersion, sanitizeModelTierOverrides, parseModelTierOverridesHeader, setAgentModelTierOverrides, previewModelTiers, recordClaimModelResolution, harnessModelErrorFor, poolTaskRunsOnHarness, explicitModelError, explicitModelErrorForAgent, referencedBundlePaths, skillDirs, TaskCreationBlockedError, recordUnmappedIdentity, MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload, scopeFromAttachment, backingProviderId, transcribeAudioNotes, buildEffectiveText, bufferedFileFailures, fetchSlackFiles, createSlackTaskWithFiles, notifySlackFileFailures, isRuntimePoolWakeable, isAgentReachable, hasOtherUserMention, broadcastMatches, routeMessage, extractTaskFromMessage, extractSlackMessageText, recoverIncompleteRuns, handleWebhookTrigger, verifyHmacSignature, WebhookError, snapshotAndUpdateWorkflow, RawLlmConfigSchema, RawLlmOutputSchema, executeRawLlm, getExecutorRegistry2, initWorkflows2, dispatchScheduleTarget, calculateNextRun2, startScheduler2, stopScheduler2, runScheduleNow2, ExtensionAssetConflictError, ExtensionOwnershipError, getExtensionFiles, getExtensionById, getExtensionByName, listExtensions, listExtensionVersions, updateExtensionMeta, listExtensionRuns, SDK_ALLOWLIST, mcpToolNameForSdkMethod, mcpOverflowAuthError, hasKvViewArgs, resolveKvView, toolErr, createToolRegistrar, handleMcpBridge, Redacted, SCRIPT_SDK_RESPONSE_LIMIT_BYTES, readScriptSdkJsonResponse, ExtensionConfigError, ExtensionLifecycleError, setExtensionLoopbackBaseUrl, enableExtension, disableExtension, activateVersion, ExtensionAssetsInvalidError, installExtensionWithAssets, uninstallExtension, reloadExtension, loadEnabledExtensions, stopExtensionRuntime, ExtensionAbortedError2, isRegistered2, isExtensionAgentId2, getExtensionBridgeToken2, resolveBridgeCallOrigin2, extensionIdForAgent2, runContext2, registerLoaded2, unregister2, listRegistered2, dispatchPre2, dispatchPost2, stripSiblingBlock, createTaskWithSiblingAwareness, isInboxAllowed, isSenderAllowed, handleMessageReceived, isAzureDevOpsEnabled, initAzureDevOps, verifyAzureDevOpsWebhook, repointTrackerSyncBySwarmId, isAzureDevOpsUrl, canonicalAzureDevOpsRepoUrl, parseAzureDevOpsRepoUrl, createdPullRequestOf, commentedPayloadOf, handlePullRequestCreated, handlePullRequestCommented, handleWorkItemCreated, handleWorkItemUpdated, handleWorkItemCommented, handleWorkItemDeleted, handleWorkItemRestored, initAzureDevOpsOutbound, AGENT_MAX_TASKS_CONFIG_KEY, reconcileAgentMaxTasksPolicy, resetAgentMaxTasksMirror, upsertSwarmConfigWithPolicyMirror, runtimeStaleThresholdMinutes, upsertRuntimeInstance, getRuntimeInstanceById, insertProvisioningRuntime, markRuntimeTerminated, touchRuntimeInstance, countActiveRuntimeInstancesForAgent, listRuntimeInstancesForAgent, setRuntimeCredentialReady, reconcileAgentStatusFromRuntimes, agentsWithLiveRuntime, expireStaleRuntimeInstances, listRuntimeInstancesForPool, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, getTelemetryIngestAnchor, initApiTelemetry, syncTelemetryEnabled, isBitbucketEnabled, initBitbucket, verifyBitbucketWebhook, isDuplicateDelivery, markDeliveryProcessed, pullRequestEventOf, pullRequestCommentEventOf, handlePullRequestCreated2, handlePullRequestCommentCreated, handlePullRequestClosed, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2, handleNote, handlePipeline, isChatSdkEnabled, getChatSdkConfig, errorMessage, resolveAdapterApiUrl, trackBackground, TelegramBotApiError, callTelegramBotApi, isTrustedTeamsServiceUrl, isChatSdkStopping, startChatSdk, getChatInstance, isChatAdapterConfigured, getChatSdkHealth, stopChatSdk, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, isCookieSafePageId, extractPageSession, extractLegacyPageSession, extractAndVerifyCookie, pageSessionSetCookies, resolveHttpRequestAuth, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, MCP_MAX_TOOL_INPUT_ELEMENTS, MCP_MAX_REQUEST_BODY_BYTES, userCtx, requestPrincipal, agentFirstPrincipal, rejectGuest, handleApps, cancelApprovalRequest, cancelApprovalRequestAndRun, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, getPageEditCounter, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, MemoryKeyError, refreshLinks, indexMemoryContent, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, REBOOT_RETRY_PIN_TAG, getPinCandidateAgent, resolveLeadOnlyRecoveryAssignment, getResumeGeneration, getNextResumeGeneration, inheritedModelSelection, createWorkerTaskFollowUp, createResumeFollowUp, createRerouteDecisionTask, createPoolStarvationDecisionTask, guardTerminalTaskResultWrite, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, updateMcpServerChecked, updateTouchesStdioExecution, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, isApiDraining, drainApi, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, changesAllowMerge, updateSwarmRepoChecked, getCombConfig, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, sessionAccessTopic, sessionPresenceRoot, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, MEMORY_KEYS_DEFAULT_PREFIX, MEMORY_KEYS_MAX_LIMIT, estimateTokens, posteriorMean, listMemoryKeys, checkChunkIntegrity, getMemoryChunks, getPosteriorsByIds, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, canClaim, emitBudgetRefusalSideEffects, workflowModelErrors, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer };
|