@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.
Files changed (382) hide show
  1. package/README.md +4 -2
  2. package/dist/{acp-adapter-thq04adh.js → acp-adapter-11gp67nr.js} +8 -6
  3. package/dist/{actions-j6ywh6x5.js → actions-8p2kze8j.js} +24 -22
  4. package/dist/{amp-adapter-k8b5xmj8.js → amp-adapter-z4qvhacj.js} +2 -2
  5. package/dist/{anthropic-messages-g6pqmqk4.js → anthropic-messages-txs190dd.js} +17 -20
  6. package/dist/{app-rb7vc02s.js → app-0qp0a2gk.js} +3 -3
  7. package/dist/{assistant-ftta1zjf.js → assistant-jedd3ktm.js} +27 -25
  8. package/dist/{azure-openai-responses-9dbmj346.js → azure-openai-responses-9kfwhmn7.js} +18 -13
  9. package/dist/{boot-reembed-xns7h5h9.js → boot-reembed-4xwq5tg0.js} +1 -1
  10. package/dist/{boot-reembed-srp6v6af.js → boot-reembed-n4wq5dd2.js} +1 -1
  11. package/dist/{boot-scrub-sweep-3qqrh2mz.js → boot-scrub-sweep-69h90xcq.js} +4 -4
  12. package/dist/{boot-seeds-9ks8hce7.js → boot-seeds-3vn0m9sg.js} +4 -4
  13. package/dist/{claude-adapter-k5ksyres.js → claude-adapter-221mvad5.js} +8 -6
  14. package/dist/{claude-managed-adapter-h2y889ge.js → claude-managed-adapter-gt6pa35d.js} +2 -2
  15. package/dist/{claude-managed-setup-n5a5eqks.js → claude-managed-setup-c3hp36ph.js} +4 -4
  16. package/dist/{claude-sdk-session-2j3j4kwn.js → claude-sdk-session-8thjsk5e.js} +9729 -9628
  17. package/dist/{cli-b9fcxxev.js → cli-007cnhm1.js} +50 -4
  18. package/dist/{cli-j4rqdf2n.js → cli-03vpq45j.js} +2 -2
  19. package/dist/{cli-amyhm3gj.js → cli-0y6f0ckq.js} +1 -1
  20. package/dist/{cli-4dg55wsk.js → cli-0z3vjrpm.js} +1 -1
  21. package/dist/{cli-pccfmtb5.js → cli-179xcyky.js} +11 -11
  22. package/dist/{cli-3r8samv3.js → cli-1f0gp9vz.js} +3 -2
  23. package/dist/{cli-hj3debgw.js → cli-1pr672hz.js} +3 -3
  24. package/dist/{cli-0bqteszy.js → cli-2nf3b08t.js} +328 -25
  25. package/dist/{cli-t7cyef5g.js → cli-36j4jnk3.js} +4 -4
  26. package/dist/{cli-er83cjbn.js → cli-3qv8naq8.js} +527 -231
  27. package/dist/cli-3zwye9sn.js +1193 -0
  28. package/dist/{cli-60cgh1rv.js → cli-459fk97x.js} +7 -7
  29. package/dist/{cli-xj0re5tm.js → cli-4w24f7z3.js} +1 -1
  30. package/dist/{cli-v3yr2gbg.js → cli-5kzk3472.js} +2198 -968
  31. package/dist/{cli-h7gc0b4r.js → cli-5m84zd2k.js} +55 -18
  32. package/dist/{cli-w6nadkh4.js → cli-5rvg1ddk.js} +5 -5
  33. package/dist/{cli-dvkmp9bt.js → cli-6ctwrf1z.js} +20 -10
  34. package/dist/{cli-9qtjfd60.js → cli-6rg2jn2y.js} +3 -2
  35. package/dist/{cli-2v045xyf.js → cli-7bwtc6yx.js} +3 -3
  36. package/dist/{cli-3cgngyd8.js → cli-7g40g8hq.js} +35 -17
  37. package/dist/{cli-q6r7t299.js → cli-92mqenkc.js} +2379 -154
  38. package/dist/{cli-cynvc9fj.js → cli-9ce2xw98.js} +8 -8
  39. package/dist/{cli-gqvh8d8a.js → cli-bgdtv62r.js} +36 -22
  40. package/dist/{cli-wxbn3yfx.js → cli-cz5nmdxt.js} +2 -2
  41. package/dist/{cli-wt645v7q.js → cli-dabehxhp.js} +1 -1
  42. package/dist/{cli-vfha21c9.js → cli-e5bxnjps.js} +2 -2
  43. package/dist/{cli-p20r8w42.js → cli-fcc5qe3f.js} +763 -268
  44. package/dist/{cli-1ephgwnq.js → cli-fes51ya2.js} +3 -3
  45. package/dist/{cli-1d70crsy.js → cli-ftmq4nvk.js} +2 -2
  46. package/dist/{cli-qkhc5aqy.js → cli-fy1jyyym.js} +13 -13
  47. package/dist/{cli-s95dknxh.js → cli-g1cw7xtt.js} +1 -1
  48. package/dist/{cli-qje9k2nh.js → cli-g9ypd5en.js} +12 -2
  49. package/dist/{cli-74c1wpm0.js → cli-gpv60278.js} +1 -1
  50. package/dist/{cli-pemywhfq.js → cli-ha9rmwgq.js} +2 -1
  51. package/dist/{cli-bnz0r3kc.js → cli-j1eghqfm.js} +5 -5
  52. package/dist/{cli-2zqpkvtt.js → cli-jpxsrxcb.js} +1 -1
  53. package/dist/{cli-ejs3m1sx.js → cli-kxpfx2xr.js} +1 -1
  54. package/dist/{cli-37yb7307.js → cli-mbfj11fq.js} +1 -1
  55. package/dist/{cli-pnp2j5zg.js → cli-mmhj8vd7.js} +2 -2
  56. package/dist/{cli-xf234ws8.js → cli-n4c8e3s5.js} +2 -0
  57. package/dist/{cli-a0kcty51.js → cli-n6kmqngw.js} +2 -2
  58. package/dist/{cli-te6b5wvg.js → cli-nnvjb17s.js} +3 -3
  59. package/dist/{cli-1dmcq2eh.js → cli-nzfnt2gs.js} +1 -1
  60. package/dist/{cli-625tb7aq.js → cli-p859hcc8.js} +2 -2
  61. package/dist/{cli-smvcw9z5.js → cli-pasyvjmm.js} +1 -1
  62. package/dist/cli-pkaqk57w.js +128 -0
  63. package/dist/{cli-8nyhf7za.js → cli-qqzmjxkf.js} +129 -105
  64. package/dist/{cli-zrwpctp4.js → cli-r25qpaxt.js} +161 -63
  65. package/dist/{cli-nc35pxb7.js → cli-rh5smt8t.js} +19 -4
  66. package/dist/{cli-qwkcwjdn.js → cli-rycdaj0a.js} +1 -1
  67. package/dist/{cli-esxerzg7.js → cli-s4sntwt4.js} +2 -2
  68. package/dist/{cli-b8k7epj1.js → cli-segs7hx9.js} +8 -8
  69. package/dist/{cli-36ckw0wx.js → cli-stxdrqs2.js} +2 -2
  70. package/dist/{cli-vdm20wej.js → cli-sy8f9705.js} +4 -4
  71. package/dist/{cli-1m17dc9d.js → cli-ta8bd7th.js} +2 -2
  72. package/dist/{cli-2y91wnbh.js → cli-we0ra057.js} +222 -10
  73. package/dist/{cli-55qmbp6z.js → cli-x21dqn18.js} +5 -5
  74. package/dist/{cli-dqb4n629.js → cli-x6vf4sad.js} +11 -11
  75. package/dist/{cli-d2mb5s8a.js → cli-x77gen2p.js} +680 -440
  76. package/dist/{cli-vq97g1jq.js → cli-xawhpgc9.js} +95 -195
  77. package/dist/{cli-82d3nkc3.js → cli-xd4eqtr2.js} +2 -2
  78. package/dist/{cli-9fhkkpj5.js → cli-xt768r5m.js} +2 -2
  79. package/dist/{cli-zrk6jxv8.js → cli-y4x8ww6s.js} +2 -2
  80. package/dist/{cli-xc27fwzg.js → cli-y9jvxfhk.js} +3 -3
  81. package/dist/{cli-44159k28.js → cli-z63a269p.js} +2 -2
  82. package/dist/{cli-sm8rses9.js → cli-zfdp01hn.js} +8 -5
  83. package/dist/cli.js +31 -29
  84. package/dist/{cloudflare-workers-ai-system-one-ch2wxfcp.js → cloudflare-workers-ai-system-one-43v9qkjk.js} +7 -2
  85. package/dist/{codex-adapter-968xwfy7.js → codex-adapter-tcg1q3jk.js} +6 -4
  86. package/dist/{codex-login-m819c41r.js → codex-login-rn7c5gxt.js} +1 -1
  87. package/dist/{codex-session-runner-ht4z99fa.js → codex-session-runner-xfx4wd9x.js} +7 -5
  88. package/dist/{commands-pcymaeg9.js → commands-ew83nj70.js} +2 -2
  89. package/dist/{controller-fpjyk46r.js → controller-gnq1k1mf.js} +4 -4
  90. package/dist/{controllers-connect-mwzx1fh6.js → controllers-connect-tw1dan9r.js} +26 -24
  91. package/dist/{cursor-adapter-cp4s2e2f.js → cursor-adapter-yq5xgfcg.js} +1 -1
  92. package/dist/{db-xsjg9jqq.js → db-7gbc53fd.js} +14 -2
  93. package/dist/{db-sgd12bt9.js → db-t86xrnes.js} +3 -3
  94. package/dist/{devin-adapter-zgqadvnm.js → devin-adapter-4ycy4vrf.js} +1 -1
  95. package/dist/{dispatcher-x0jfw2c9.js → dispatcher-64bdyhps.js} +23 -21
  96. package/dist/{docker-fkgtr75t.js → docker-nfy2gc8t.js} +2 -2
  97. package/dist/{dsh-adapter-jrq7ma7h.js → dsh-adapter-tvhc4k2d.js} +1 -1
  98. package/dist/{e2b-16d6ch39.js → e2b-9gkdhm3c.js} +2 -2
  99. package/dist/{e2b-zn0b4w5w.js → e2b-cjtf8k1z.js} +2 -2
  100. package/dist/{easter-egg-3d-5cgynaja.js → easter-egg-3d-e4qv8dxj.js} +1 -1
  101. package/dist/{event-bus-9vpk8gmq.js → event-bus-3z78ep5n.js} +1 -1
  102. package/dist/{execute-t4e6m3rw.js → execute-0xpz8950.js} +85 -23
  103. package/dist/{external-channel-8njj4h3b.js → external-channel-e9nw24zv.js} +2 -2
  104. package/dist/{google-generative-ai-bmq8gkf3.js → google-generative-ai-mk9vcpe1.js} +15 -15
  105. package/dist/{google-vertex-b1rvp52s.js → google-vertex-q580kz8k.js} +20 -20
  106. package/dist/{grok-adapter-kkr97v2f.js → grok-adapter-v82srhrx.js} +9 -7
  107. package/dist/handlers-c9ajzhbn.js +41 -0
  108. package/dist/{heartbeat-wd03zhn0.js → heartbeat-2vqs1319.js} +26 -24
  109. package/dist/{hook-xzj2ts2p.js → hook-01nk13wx.js} +7 -5
  110. package/dist/{hook-f0vghj42.js → hook-jzpheegg.js} +9 -7
  111. package/dist/{http-4hwxv62p.js → http-fc1k6ec8.js} +859 -252
  112. package/dist/index-07ef7nkm.js +42 -0
  113. package/dist/{index-g6tbb6ve.js → index-31ceyf42.js} +1 -1
  114. package/dist/index-7yts8n9s.js +43 -0
  115. package/dist/{index-c4ykd0f1.js → index-dr94zbnh.js} +13348 -11611
  116. package/dist/index-q3t40ryv.js +46 -0
  117. package/dist/{index-ww2vznkp.js → index-sepja052.js} +1 -1
  118. package/dist/{index-97q4xn03.js → index-zdycv3ja.js} +135 -79
  119. package/dist/{index-g216q6jr.js → index-zsyx51ap.js} +1 -4
  120. package/dist/{keepalive-hrh7xnr9.js → keepalive-5nh2rhmr.js} +4 -4
  121. package/dist/lead-aayq64jn.js +79 -0
  122. package/dist/{llama-cpp-classify-vv43gswy.js → llama-cpp-classify-ee7vmd7q.js} +4 -1
  123. package/dist/{maintenance-e8wnwnqx.js → maintenance-hjhzdt3k.js} +1 -1
  124. package/dist/{mistral-conversations-1medfwv7.js → mistral-conversations-sd0xf1tn.js} +13 -13
  125. package/dist/{node-3v3f08f7.js → node-jzjj7r9x.js} +10 -9
  126. package/dist/{oauth-refresh-sweep-zm0yj4sj.js → oauth-refresh-sweep-y3n1knmd.js} +3 -3
  127. package/dist/{onboard-dtwcq603.js → onboard-1zq3m7db.js} +2 -2
  128. package/dist/{openai-codex-responses-de9pvs4d.js → openai-codex-responses-79s8xnbh.js} +29 -23
  129. package/dist/{openai-completions-mtqge3nf.js → openai-completions-tdbyts0x.js} +21 -20
  130. package/dist/{openai-decisions-ygk4kkxd.js → openai-decisions-bqhnjyfz.js} +2 -1
  131. package/dist/{openai-responses-dkyng71g.js → openai-responses-dm3t5vqp.js} +26 -17
  132. package/dist/{opencode-adapter-x4tqzhkh.js → opencode-adapter-e56086m1.js} +7 -5
  133. package/dist/{openrouter-images-wvv7camj.js → openrouter-images-ssttr1y4.js} +6 -3
  134. package/dist/{otel-impl-w3fbhpn0.js → otel-impl-h9yyza47.js} +2 -2
  135. package/dist/{pi-messages-nhh1pkz2.js → pi-messages-3nf8bq1a.js} +6 -4
  136. package/dist/{pi-mono-adapter-mcfkn9vf.js → pi-mono-adapter-tzps8f38.js} +9 -37
  137. package/dist/{pricing-refresh-j38dehfs.js → pricing-refresh-nevhat8h.js} +3 -3
  138. package/dist/{rbac-roles-ae8yttq4.js → rbac-roles-4y6ngvzq.js} +1 -1
  139. package/dist/{rbac-roles-ejxx9b35.js → rbac-roles-exbg8xb6.js} +2 -2
  140. package/dist/{registry-rxw10xzg.js → registry-ajhexe44.js} +1 -1
  141. package/dist/{render-v2-n16n0phe.js → render-v2-cfsh13z3.js} +3 -3
  142. package/dist/{resume-z0fgjc38.js → resume-5s2t0dbs.js} +10 -8
  143. package/dist/{runtime-xe3aqy4x.js → runtime-bt5pkpm1.js} +1 -1
  144. package/dist/{session-access-cv3mq6mc.js → session-access-dnbyp3cn.js} +6 -4
  145. package/dist/{setup-mafhj3yt.js → setup-1wj1y77j.js} +1 -1
  146. package/dist/{typesafe-system-one-2hgpayzy.js → typesafe-system-one-bre38hvs.js} +4 -2
  147. package/dist/{virtual-modules-4r3zkc20.js → virtual-modules-mnfbh5mr.js} +8 -2
  148. package/dist/{work-objects-8b86mgjp.js → work-objects-7mg6216g.js} +26 -24
  149. package/dist/worker-nwb789mg.js +79 -0
  150. package/dist/{x-y45mthwn.js → x-pbpezr0s.js} +2 -2
  151. package/openapi.json +793 -6
  152. package/package.json +11 -11
  153. package/src/apps/catalog.generated.json +206 -4
  154. package/src/apps/page-validator.ts +13 -1
  155. package/src/assets/key.ts +17 -0
  156. package/src/azure-devops/handlers.ts +1 -1
  157. package/src/be/chunking.ts +42 -9
  158. package/src/be/db/approvals.ts +18 -0
  159. package/src/be/db/session-moves.ts +164 -0
  160. package/src/be/db/session-tree.ts +384 -0
  161. package/src/be/db/tasks/draft-text.ts +15 -0
  162. package/src/be/db/tasks/read.ts +54 -5
  163. package/src/be/db/workflow-runs.ts +96 -0
  164. package/src/be/db.ts +85 -237
  165. package/src/be/memory/index-content.ts +36 -17
  166. package/src/be/memory/providers/openai-embedding.ts +115 -61
  167. package/src/be/memory/providers/sqlite-store.ts +69 -23
  168. package/src/be/memory/reranker.ts +31 -1
  169. package/src/be/memory/search-candidates.ts +47 -0
  170. package/src/be/memory/types.ts +14 -0
  171. package/src/be/onboarding.ts +3 -0
  172. package/src/be/scripts/typecheck.ts +2 -0
  173. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +106 -54
  174. package/src/be/seed-scripts/index.ts +2 -2
  175. package/src/be/skill-sync.ts +43 -2
  176. package/src/be/swarm-config-guard.ts +25 -1
  177. package/src/be/task-attachment-store.ts +30 -0
  178. package/src/bitbucket/api.ts +81 -0
  179. package/src/bitbucket/auth.ts +64 -0
  180. package/src/bitbucket/handlers.ts +434 -0
  181. package/src/bitbucket/index.ts +28 -0
  182. package/src/bitbucket/templates.ts +134 -0
  183. package/src/bitbucket/types.ts +65 -0
  184. package/src/commands/runner.ts +55 -3
  185. package/src/e2b/env.ts +1 -0
  186. package/src/extensions/catalog.generated.json +4 -4
  187. package/src/extensions/contract-types.generated.ts +1 -1
  188. package/src/extensions/contract.ts +9 -2
  189. package/src/extensions/post-bridge.ts +1 -0
  190. package/src/fs/provider.ts +13 -1
  191. package/src/github/handlers.ts +6 -6
  192. package/src/gitlab/handlers.ts +5 -5
  193. package/src/heartbeat/heartbeat.ts +31 -11
  194. package/src/http/assets.ts +14 -2
  195. package/src/http/core.ts +12 -0
  196. package/src/http/fs.ts +54 -34
  197. package/src/http/index.ts +4 -0
  198. package/src/http/mcp-body.ts +37 -0
  199. package/src/http/mcp-user.ts +3 -5
  200. package/src/http/mcp.ts +6 -7
  201. package/src/http/memory.ts +26 -15
  202. package/src/http/onboarding.ts +1 -0
  203. package/src/http/page-proxy.ts +61 -5
  204. package/src/http/pages-public.ts +27 -44
  205. package/src/http/pages.ts +4 -4
  206. package/src/http/script-runs.ts +2 -0
  207. package/src/http/sessions.ts +366 -12
  208. package/src/http/skills.ts +48 -1
  209. package/src/http/tasks.ts +1 -1
  210. package/src/http/users.ts +13 -1
  211. package/src/http/webhooks.ts +141 -0
  212. package/src/integrations/chat-sdk/adapters.ts +24 -4
  213. package/src/integrations/chat-sdk/attachments.ts +90 -12
  214. package/src/integrations/chat-sdk/facts.ts +138 -0
  215. package/src/integrations/chat-sdk/inbound.ts +156 -8
  216. package/src/integrations/chat-sdk/limits.ts +24 -0
  217. package/src/integrations/chat-sdk/outbound-files.ts +186 -0
  218. package/src/integrations/chat-sdk/outbound.ts +272 -5
  219. package/src/integrations/chat-sdk/relay.ts +4 -1
  220. package/src/integrations/chat-sdk/router.ts +28 -2
  221. package/src/integrations/chat-sdk/steering.ts +9 -0
  222. package/src/integrations/chat-sdk/templates.ts +14 -0
  223. package/src/integrations/chat-sdk/thread-buffer.ts +4 -0
  224. package/src/mcp-limits.ts +20 -0
  225. package/src/pages/browser-sdk.ts +8 -3
  226. package/src/pages/feedback-overlay.ts +1 -1
  227. package/src/providers/acp-targets.ts +1 -1
  228. package/src/providers/amp-adapter.ts +1 -1
  229. package/src/providers/codex-adapter.ts +106 -119
  230. package/src/providers/codex-agents-md.ts +35 -229
  231. package/src/providers/cursor-adapter.ts +1 -1
  232. package/src/providers/pi-mono-adapter.ts +5 -53
  233. package/src/realtime/transport.ts +1 -2
  234. package/src/script-workflows/workflow-ctx.ts +1 -0
  235. package/src/scripts-runtime/types/stdlib.d.ts +2 -0
  236. package/src/scripts-runtime/types/swarm-extension.d.ts +14 -4
  237. package/src/scripts-runtime/types/swarm-sdk.d.ts +2 -0
  238. package/src/server-user.ts +2 -0
  239. package/src/server.ts +2 -0
  240. package/src/slack/assistant.ts +2 -2
  241. package/src/slack/files.ts +2 -0
  242. package/src/slack/handlers.test.ts +158 -0
  243. package/src/slack/handlers.ts +23 -32
  244. package/src/slack/inbound-files.ts +39 -6
  245. package/src/slack/thread-buffer.ts +2 -1
  246. package/src/tasks/context-key.ts +61 -1
  247. package/src/tasks/task-terminal-effects.ts +21 -17
  248. package/src/tests/apps-card-grid.test.ts +197 -0
  249. package/src/tests/apps-catalog-additions.test.ts +120 -0
  250. package/src/tests/apps-tree.test.ts +129 -0
  251. package/src/tests/bitbucket-auth.test.ts +156 -0
  252. package/src/tests/bitbucket-handlers.test.ts +425 -0
  253. package/src/tests/bitbucket-webhook.test.ts +220 -0
  254. package/src/tests/chat-sdk-attachments-reply.test.ts +52 -0
  255. package/src/tests/chat-sdk-config.test.ts +11 -0
  256. package/src/tests/chat-sdk-facts.test.ts +23 -0
  257. package/src/tests/chat-sdk-inbound.test.ts +597 -4
  258. package/src/tests/chat-sdk-outbound-files.test.ts +652 -0
  259. package/src/tests/chat-sdk-telegram-markdown.test.ts +92 -0
  260. package/src/tests/codex-adapter.test.ts +167 -242
  261. package/src/tests/config-api-only-keys.test.ts +9 -0
  262. package/src/tests/context-key.test.ts +50 -0
  263. package/src/tests/core-auth.test.ts +5 -0
  264. package/src/tests/cors-allowlist.test.ts +1 -1
  265. package/src/tests/db-task-read-contract.test.ts +7 -0
  266. package/src/tests/db-task-write-contract.test.ts +6 -0
  267. package/src/tests/docs-index-footprint.test.js +3 -3
  268. package/src/tests/extensions-example-slack-reply-gate.test.ts +262 -91
  269. package/src/tests/fixtures/bitbucket/pullrequest-comment-created-inline.json +174 -0
  270. package/src/tests/fixtures/bitbucket/pullrequest-comment-created.json +170 -0
  271. package/src/tests/fixtures/bitbucket/pullrequest-created-mention.json +132 -0
  272. package/src/tests/fixtures/bitbucket/pullrequest-created-reviewer.json +140 -0
  273. package/src/tests/fixtures/bitbucket/pullrequest-fulfilled.json +134 -0
  274. package/src/tests/fixtures/bitbucket/pullrequest-rejected.json +133 -0
  275. package/src/tests/generate-mcp-docs.test.ts +101 -0
  276. package/src/tests/gitlab-handlers.test.ts +3 -3
  277. package/src/tests/gitlab-vcs-db.test.ts +4 -4
  278. package/src/tests/heartbeat-checklist.test.ts +33 -0
  279. package/src/tests/heartbeat-jev-gate-credentials.test.ts +44 -0
  280. package/src/tests/heartbeat-jev-gate.test.ts +242 -1
  281. package/src/tests/integration-disable-flags.test.ts +36 -0
  282. package/src/tests/kv-page-proxy.test.ts +91 -5
  283. package/src/tests/launch-password-rejection.test.ts +2 -2
  284. package/src/tests/mcp-input-caps.test.ts +294 -0
  285. package/src/tests/mcp-tools.test.ts +1 -1
  286. package/src/tests/memory-chunked-search-starvation.test.ts +200 -0
  287. package/src/tests/memory-embedding-input-cap.test.ts +114 -0
  288. package/src/tests/memory.test.ts +14 -0
  289. package/src/tests/onboarding.test.ts +12 -0
  290. package/src/tests/page-guest-session.test.ts +19 -8
  291. package/src/tests/page-proxy-authed.test.ts +1 -1
  292. package/src/tests/page-proxy.test.ts +17 -10
  293. package/src/tests/page-session.test.ts +102 -1
  294. package/src/tests/pages-authed-mode.test.ts +82 -12
  295. package/src/tests/pages-password-mode.test.ts +5 -5
  296. package/src/tests/pi-codemode.test.ts +8 -2
  297. package/src/tests/preload-env.test.ts +57 -0
  298. package/src/tests/preload.ts +21 -0
  299. package/src/tests/prompt-template-remaining.test.ts +38 -0
  300. package/src/tests/realtime-transport.test.ts +13 -7
  301. package/src/tests/run-root-coverage.test.ts +39 -0
  302. package/src/tests/runner-bitbucket-vcs.test.ts +191 -0
  303. package/src/tests/runner-skills-refresh.test.ts +58 -0
  304. package/src/tests/script-runs-http.test.ts +84 -0
  305. package/src/tests/scripts-http.test.ts +10 -1
  306. package/src/tests/secret-scrubber.test.ts +15 -0
  307. package/src/tests/sessions-move.test.ts +576 -0
  308. package/src/tests/sessions-tree.test.ts +493 -0
  309. package/src/tests/skill-files-http.test.ts +50 -0
  310. package/src/tests/skills-bundle.test.ts +99 -0
  311. package/src/tests/swarm-config-export-to-env.test.ts +23 -3
  312. package/src/tests/task-audio-transcription.test.ts +299 -0
  313. package/src/tests/task-completion-memory-chunking.test.ts +434 -0
  314. package/src/tests/task-terminal-secret-scrub.test.ts +6 -1
  315. package/src/tests/transcription.test.ts +299 -0
  316. package/src/tests/vcs-bitbucket.test.ts +91 -0
  317. package/src/tests/vcs-provider-isolation.test.ts +123 -0
  318. package/src/tests/vcs-provider.test.ts +16 -1
  319. package/src/tests/vcs-tracking.test.ts +3 -3
  320. package/src/tests/workflow-foreach-bodies.test.ts +637 -0
  321. package/src/tests/workflow-foreach-concurrency.test.ts +342 -0
  322. package/src/tests/workflow-foreach-retry.test.ts +537 -0
  323. package/src/tests/workflow-foreach.test.ts +44 -23
  324. package/src/tests/workflow-step-claims.test.ts +6 -6
  325. package/src/tests/workflow-system-one-decision-providers.test.ts +98 -1
  326. package/src/tests/workflow-system-one-decision.test.ts +2 -1
  327. package/src/tests/workflow-tla-races.test.ts +2 -2
  328. package/src/tools/chat-access.ts +10 -0
  329. package/src/tools/chat-post.ts +31 -11
  330. package/src/tools/chat-reply.ts +32 -10
  331. package/src/tools/memory-search.ts +3 -1
  332. package/src/tools/script-delete.ts +1 -1
  333. package/src/tools/system-one-decide.ts +17 -4
  334. package/src/tools/workflows/create-workflow.ts +5 -3
  335. package/src/types.ts +9 -2
  336. package/src/utils/config-env-export.ts +4 -1
  337. package/src/utils/page-session.ts +133 -20
  338. package/src/utils/secret-scrubber.ts +4 -0
  339. package/src/utils/skills-refresh.ts +83 -43
  340. package/src/utils/transcription.ts +246 -0
  341. package/src/vcs/bitbucket.ts +58 -0
  342. package/src/vcs/index.ts +2 -0
  343. package/src/vcs/types.ts +2 -2
  344. package/src/workflows/approval-resolution.ts +4 -1
  345. package/src/workflows/checkpoint.ts +9 -1
  346. package/src/workflows/constants.ts +3 -0
  347. package/src/workflows/definition.ts +48 -17
  348. package/src/workflows/engine.ts +25 -15
  349. package/src/workflows/executors/foreach.ts +45 -99
  350. package/src/workflows/executors/system-one-decision.ts +28 -7
  351. package/src/workflows/executors/system-one-providers.ts +39 -4
  352. package/src/workflows/foreach-body.ts +146 -0
  353. package/src/workflows/foreach-driver.ts +552 -0
  354. package/src/workflows/foreach-join.ts +206 -7
  355. package/src/workflows/node-timeout.ts +21 -0
  356. package/src/workflows/recovery.ts +68 -3
  357. package/src/workflows/resume.ts +221 -43
  358. package/src/workflows/retry-poller.ts +39 -24
  359. package/src/workflows/step-input.ts +59 -0
  360. package/src/workflows/task-step-routing.ts +114 -56
  361. package/templates/extensions/slack-reply-gate/README.md +24 -22
  362. package/templates/extensions/slack-reply-gate/hooks.ts +146 -95
  363. package/templates/extensions/slack-reply-gate/manifest.json +2 -2
  364. package/templates/skills/apps/SKILL.md +28 -6
  365. package/templates/skills/apps/content.md +28 -6
  366. package/templates/skills/chat-sdk/content.md +6 -2
  367. package/templates/skills/code-quality/content.md +2 -1
  368. package/templates/skills/heartbeat-runbook/content.md +5 -5
  369. package/templates/skills/pages/content.md +6 -4
  370. package/templates/skills/slack-interaction/content.md +5 -0
  371. package/templates/skills/swarm-scripts/SKILL.md +2 -2
  372. package/templates/skills/swarm-scripts/content.md +2 -2
  373. package/templates/skills/work-on-task/SKILL.md +1 -1
  374. package/templates/skills/work-on-task/content.md +1 -1
  375. package/dist/cli-51y09c6p.js +0 -2657
  376. package/dist/cli-yw91rnmw.js +0 -13
  377. package/dist/handlers-0pvee9nw.js +0 -39
  378. package/dist/index-gdh8jrdm.js +0 -43
  379. package/dist/index-hg0x2cdv.js +0 -40
  380. package/dist/index-thm0y6a8.js +0 -41
  381. package/dist/lead-ee8vazz2.js +0 -77
  382. 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-p20r8w42.js";
339
+ } from "./cli-fcc5qe3f.js";
336
340
  import {
337
341
  getUserGrant2,
338
342
  init_rbac_roles
339
- } from "./cli-4dg55wsk.js";
343
+ } from "./cli-0z3vjrpm.js";
340
344
  import {
341
345
  ensurePricingSeeded2,
342
346
  ensureRbacSeeded2,
343
347
  ensureModelProfilesSeeded2
344
- } from "./cli-t7cyef5g.js";
348
+ } from "./cli-36j4jnk3.js";
345
349
  import {
346
350
  loadModelsDevCache
347
- } from "./cli-amyhm3gj.js";
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-xc27fwzg.js";
361
+ } from "./cli-y9jvxfhk.js";
358
362
  import {
359
363
  ampPinProviderError,
360
364
  ampPinCatalogError,
361
365
  ampModelError
362
- } from "./cli-2zqpkvtt.js";
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
- FOREACH_TERMINAL_STEP_STATUSES,
375
- parseSyntheticNodeId,
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
- buildNodeInterpolationCtx,
412
- interpolateNodeConfig,
413
- scriptBodyInterpolationError
414
- } from "./cli-51y09c6p.js";
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-2y91wnbh.js";
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-esxerzg7.js";
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-qkhc5aqy.js";
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-1d70crsy.js";
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-wt645v7q.js";
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-cynvc9fj.js";
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-qje9k2nh.js";
581
+ } from "./cli-g9ypd5en.js";
576
582
  import {
577
583
  getRuntimePool2,
578
584
  init_db
579
- } from "./cli-w6nadkh4.js";
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-smvcw9z5.js";
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-625tb7aq.js";
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-9fhkkpj5.js";
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-nc35pxb7.js";
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-74c1wpm0.js";
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-pccfmtb5.js";
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-xf234ws8.js";
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 && this._taskMessageQueue) {
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.onNodeFailure ?? "fail") === "fail") {
20234
+ if (!taskCompleted && stepFailureMode(workflow.definition, stuck.nodeId) === "fail") {
20167
20235
  const reason = stuck.taskStatus === "failed" ? "Task failed (recovered)" : "Task cancelled (recovered)";
20168
- const claimed = await failStepAndRunIfWaiting(stuck.stepId, stuck.runId, reason, stuck.taskId);
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 ctx = run.context ?? {};
20307
- if (!("run" in ctx))
20308
- ctx.run = { id: run.id };
20309
- await rehydrateCompletedStepOutputs(workflow.definition, run.id, ctx, registry);
20310
- const inputCtx = buildNodeInterpolationCtx(node, ctx);
20311
- const { value: interpolatedValue, scriptBodyUnresolved } = interpolateNodeConfig(node, inputCtx);
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-rb7vc02s.js");
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-x0jfw2c9.js");
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 detectMention2(text) {
29575
+ function detectMention3(text) {
29155
29576
  if (!text)
29156
29577
  return false;
29157
29578
  return MENTION_PATTERN.test(text);
29158
29579
  }
29159
- function extractMentionContext2(text) {
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 processedEvents3 = new Map;
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 isDuplicate3(eventKey) {
30067
+ function isDuplicate4(eventKey) {
29647
30068
  const now = Date.now();
29648
- for (const [key, timestamp] of processedEvents3) {
30069
+ for (const [key, timestamp] of processedEvents4) {
29649
30070
  if (now - timestamp > EVENT_TTL2) {
29650
- processedEvents3.delete(key);
30071
+ processedEvents4.delete(key);
29651
30072
  }
29652
30073
  }
29653
- if (processedEvents3.has(eventKey)) {
30074
+ if (processedEvents4.has(eventKey)) {
29654
30075
  return true;
29655
30076
  }
29656
- processedEvents3.set(eventKey, now);
30077
+ processedEvents4.set(eventKey, now);
29657
30078
  return false;
29658
30079
  }
29659
- async function findLeadAgent3() {
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 UNMAPPED_NAMESPACE2 = "integration:unmapped:github";
29667
- var UNMAPPED_TTL_MS2 = 30 * 24 * 60 * 60 * 1000;
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: UNMAPPED_NAMESPACE2,
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() + UNMAPPED_TTL_MS2
30102
+ expiresAt: Date.now() + UNMAPPED_TTL_MS3
29682
30103
  });
29683
- await incrKv2(UNMAPPED_NAMESPACE2, `${login}:count`, 1);
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 (isDuplicate3(eventKey)) {
30123
+ if (isDuplicate4(eventKey)) {
29703
30124
  return { created: false };
29704
30125
  }
29705
- const lead = await findLeadAgent3();
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 (isDuplicate3(eventKey)) {
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 findLeadAgent3();
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 (isDuplicate3(eventKey)) {
30263
+ if (isDuplicate4(eventKey)) {
29843
30264
  return { created: false };
29844
30265
  }
29845
- const lead = await findLeadAgent3();
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 = detectMention2(pr.title) || detectMention2(pr.body);
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 (isDuplicate3(eventKey)) {
30321
+ if (isDuplicate4(eventKey)) {
29901
30322
  return { created: false };
29902
30323
  }
29903
- const lead = await findLeadAgent3();
29904
- const context = extractMentionContext2(pr.body) || pr.title;
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 (isDuplicate3(eventKey)) {
30371
+ if (isDuplicate4(eventKey)) {
29951
30372
  return { created: false };
29952
30373
  }
29953
- const lead = await findLeadAgent3();
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 (isDuplicate3(eventKey)) {
30437
+ if (isDuplicate4(eventKey)) {
30017
30438
  return { created: false };
30018
30439
  }
30019
- const lead = await findLeadAgent3();
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 = detectMention2(issue.title) || detectMention2(issue.body);
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 (isDuplicate3(eventKey)) {
30485
+ if (isDuplicate4(eventKey)) {
30065
30486
  return { created: false };
30066
30487
  }
30067
- const lead = await findLeadAgent3();
30068
- const context = extractMentionContext2(issue.body) || issue.title;
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 (!detectMention2(comment.body)) {
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 (isDuplicate3(eventKey)) {
30539
+ if (isDuplicate4(eventKey)) {
30119
30540
  return skip("duplicate delivery");
30120
30541
  }
30121
- const lead = await findLeadAgent3();
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 = extractMentionContext2(comment.body);
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 (isDuplicate3(eventKey)) {
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 findLeadAgent3();
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 initialized4 = false;
30460
- var webhookSecret4 = null;
30461
- var apiToken2 = null;
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 (initialized4)
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
- webhookSecret4 = process.env.GITLAB_WEBHOOK_SECRET;
30474
- apiToken2 = process.env.GITLAB_TOKEN ?? null;
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
- initialized4 = true;
30897
+ initialized5 = true;
30477
30898
  console.log(`[GitLab] Integration initialized (url: ${gitlabUrl})`);
30478
30899
  }
30479
30900
  function verifyGitLabWebhook(tokenHeader) {
30480
- if (!webhookSecret4)
30901
+ if (!webhookSecret5)
30481
30902
  return false;
30482
30903
  if (!tokenHeader)
30483
30904
  return false;
30484
- if (tokenHeader.length !== webhookSecret4.length)
30905
+ if (tokenHeader.length !== webhookSecret5.length)
30485
30906
  return false;
30486
- return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(webhookSecret4));
30907
+ return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(webhookSecret5));
30487
30908
  }
30488
30909
  function getGitLabToken() {
30489
- return apiToken2;
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
- initialized4 = false;
30497
- webhookSecret4 = null;
30498
- apiToken2 = null;
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 headers3() {
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: headers3(),
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: headers3(),
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 processedEvents4 = new Map;
30670
- var DEDUP_TTL_MS2 = 60000;
30671
- function isDuplicate4(key) {
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 processedEvents4) {
30674
- if (now - ts > DEDUP_TTL_MS2)
30675
- processedEvents4.delete(k);
31094
+ for (const [k, ts] of processedEvents5) {
31095
+ if (now - ts > DEDUP_TTL_MS3)
31096
+ processedEvents5.delete(k);
30676
31097
  }
30677
- if (processedEvents4.has(key))
31098
+ if (processedEvents5.has(key))
30678
31099
  return true;
30679
- processedEvents4.set(key, now);
31100
+ processedEvents5.set(key, now);
30680
31101
  return false;
30681
31102
  }
30682
- function detectMention3(text) {
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 extractMentionContext3(text) {
31108
+ function extractMentionContext4(text) {
30688
31109
  return text.replace(new RegExp(`@${GITLAB_BOT_NAME}\\b`, "gi"), "").trim();
30689
31110
  }
30690
- async function findLeadAgent4() {
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 UNMAPPED_NAMESPACE3 = "integration:unmapped:gitlab";
30695
- var UNMAPPED_TTL_MS3 = 30 * 24 * 60 * 60 * 1000;
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: UNMAPPED_NAMESPACE3,
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() + UNMAPPED_TTL_MS3
31137
+ expiresAt: Date.now() + UNMAPPED_TTL_MS4
30717
31138
  });
30718
- await incrKv2(UNMAPPED_NAMESPACE3, `${user.username}:count`, 1);
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 (isDuplicate4(dedupKey)) {
31152
+ if (isDuplicate5(dedupKey)) {
30732
31153
  console.log(`[GitLab] Skipping duplicate MR event`);
30733
31154
  return { created: false };
30734
31155
  }
30735
- const lead = await findLeadAgent4();
31156
+ const lead = await findLeadAgent5();
30736
31157
  switch (action) {
30737
31158
  case "open": {
30738
- const hasMention = detectMention3(mr.description);
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 ? extractMentionContext3(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 (isDuplicate4(dedupKey)) {
31236
+ if (isDuplicate5(dedupKey)) {
30816
31237
  return { created: false };
30817
31238
  }
30818
- const lead = await findLeadAgent4();
31239
+ const lead = await findLeadAgent5();
30819
31240
  switch (action) {
30820
31241
  case "open": {
30821
- const hasMention = detectMention3(issue.description);
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 ? extractMentionContext3(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 (!detectMention3(note.note)) {
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 (isDuplicate4(dedupKey)) {
31311
+ if (isDuplicate5(dedupKey)) {
30891
31312
  return { created: false };
30892
31313
  }
30893
- const lead = await findLeadAgent4();
30894
- const context = extractMentionContext3(note.note);
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 (isDuplicate4(dedupKey)) {
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 findLeadAgent4();
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 { createTelegramAdapter } = await import("./index-g216q6jr.js");
31271
- return createTelegramAdapter({ ...base, allowUnverifiedWebhooks: false });
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
- return reason ? `${line} (not attached: ${reason})` : line;
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 limit = `larger than the ${MAX_TASK_ATTACHMENT_BYTES / (1024 * 1024)} MB limit`;
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 > MAX_TASK_ATTACHMENT_BYTES) {
31982
- result.failed.push({ file, reason: limit });
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 > MAX_TASK_ATTACHMENT_BYTES) {
31988
- result.failed.push({ file, reason: limit });
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 sent = await target.post({ markdown: chunk });
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: kind === "mention" || message.isMention === true,
32473
- isDirectMessage: kind === "dm" || thread.isDM,
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 fileText = buildChatAttachmentText(inbound.files, inbound.failed);
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 description = threadContext ? `${resolveTemplate("chat.message.thread_context", { thread_messages: threadContext }).text}
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
- ${marked}` : marked;
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 findLeadAgent5() {
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 findLeadAgent5();
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 findLeadAgent5();
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-rb7vc02s.js");
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-xsjg9jqq.js");
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 initialized5 = false;
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
- initialized5 = false;
35135
+ initialized6 = false;
34020
35136
  }
34021
35137
  async function initJira() {
34022
- if (initialized5)
35138
+ if (initialized6)
34023
35139
  return isJiraEnabled();
34024
- initialized5 = true;
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 isDuplicateDelivery(deliveryId) {
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 isDuplicateDelivery(deliveryId)) {
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 findLeadAgent6() {
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 UNMAPPED_NAMESPACE4 = "integration:unmapped:linear";
105931
- var UNMAPPED_TTL_MS4 = 30 * 24 * 60 * 60 * 1000;
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: UNMAPPED_NAMESPACE4,
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() + UNMAPPED_TTL_MS4
107086
+ expiresAt: Date.now() + UNMAPPED_TTL_MS5
105971
107087
  });
105972
- await incrKv2(UNMAPPED_NAMESPACE4, `${linearUserId}:count`, 1);
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 findLeadAgent6();
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 findLeadAgent6();
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 initialized6 = false;
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
- initialized6 = false;
107701
+ initialized7 = false;
106586
107702
  }
106587
107703
  async function initLinear() {
106588
- if (initialized6)
107704
+ if (initialized7)
106589
107705
  return isLinearEnabled();
106590
- initialized6 = true;
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
- async function extractAndVerifyCookie(req) {
107001
- const token = parseCookieHeader(req.headers.cookie, "page_session");
107002
- if (!token)
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
- return verifyPageSession(token);
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
- const attrs = [
107017
- `page_session=${token}`,
107018
- "HttpOnly",
107019
- "Path=/",
107020
- `Max-Age=${PAGE_SESSION_TTL_SECONDS}`
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-ww2vznkp.js");
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-rxw10xzg.js");
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-srp6v6af.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
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-xns7h5h9.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
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 or a short progress note on long work. Markdown is supported; long text is split into several messages.",
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 store = getMemoryStore2();
115209
- const provider = getEmbeddingProvider2();
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
- const swarmMemory = await store.store({
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.search(queryEmbedding ?? new Float32Array(0), requestInfo.agentId, {
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 = "Remove a swarm-shared script from the catalog. Versions table preserves history.";
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
- return reason ? `${line} (not attached: ${reason})` : line;
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-9vpk8gmq.js").then(({ workflowEventBus }) => {
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' fans out one agent-task per item. Config: " + "{ over: <array or exact {{input}} token>, itemKey: <property name>, body: { type: 'agent-task', config: {...} } }. " + "The body config is interpolated once per item with {{item.*}} and {{index}}. Child steps use synthetic IDs " + "'<foreachNodeId>#<itemKey>'; the parent waits for every child and exposes one aggregate result to successors. " + `concurrency is not supported in v1; use definition-level onNodeFailure: 'continue' to aggregate failed children.
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, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, 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, 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, MemoryKeyError, refreshLinks, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, indexMemoryContent, 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 };
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 };