@desplega.ai/agent-swarm 2.4.4 → 2.4.5

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 (221) hide show
  1. package/dist/{acp-adapter-thq04adh.js → acp-adapter-2wdkktv6.js} +1 -1
  2. package/dist/{actions-j6ywh6x5.js → actions-c40ebcm4.js} +18 -18
  3. package/dist/{amp-adapter-k8b5xmj8.js → amp-adapter-wb67m95z.js} +2 -2
  4. package/dist/{app-rb7vc02s.js → app-353vre8g.js} +3 -3
  5. package/dist/{assistant-ftta1zjf.js → assistant-sj1njh23.js} +21 -21
  6. package/dist/{boot-reembed-srp6v6af.js → boot-reembed-b9c3az3c.js} +1 -1
  7. package/dist/{boot-reembed-xns7h5h9.js → boot-reembed-qdkvxeem.js} +1 -1
  8. package/dist/{boot-scrub-sweep-3qqrh2mz.js → boot-scrub-sweep-m3wh8eks.js} +2 -2
  9. package/dist/{boot-seeds-9ks8hce7.js → boot-seeds-j2273s54.js} +4 -4
  10. package/dist/{claude-adapter-k5ksyres.js → claude-adapter-m7q0a085.js} +2 -2
  11. package/dist/{claude-managed-adapter-h2y889ge.js → claude-managed-adapter-5ptb6tzs.js} +2 -2
  12. package/dist/{claude-managed-setup-n5a5eqks.js → claude-managed-setup-smrqk5j5.js} +3 -3
  13. package/dist/{claude-sdk-session-2j3j4kwn.js → claude-sdk-session-38xnz21e.js} +8284 -8267
  14. package/dist/{cli-cynvc9fj.js → cli-018r4jq6.js} +5 -5
  15. package/dist/{cli-9fhkkpj5.js → cli-1f3qzw6y.js} +1 -1
  16. package/dist/{cli-dqb4n629.js → cli-1sp861s4.js} +7 -7
  17. package/dist/{cli-gqvh8d8a.js → cli-1syn2xy1.js} +10 -10
  18. package/dist/{cli-qkhc5aqy.js → cli-37j04k05.js} +11 -11
  19. package/dist/{cli-1d70crsy.js → cli-3a45zcgm.js} +1 -1
  20. package/dist/{cli-t7cyef5g.js → cli-43x64hv3.js} +4 -4
  21. package/dist/{cli-hj3debgw.js → cli-4zfqgjc5.js} +2 -2
  22. package/dist/{cli-55qmbp6z.js → cli-7c9qs530.js} +1 -1
  23. package/dist/{cli-9qtjfd60.js → cli-848hxdwj.js} +1 -1
  24. package/dist/{cli-pccfmtb5.js → cli-94gwyg7m.js} +7 -7
  25. package/dist/{cli-51y09c6p.js → cli-9hstj09h.js} +5 -5
  26. package/dist/{cli-zrwpctp4.js → cli-9yqgm9nd.js} +22 -22
  27. package/dist/{cli-esxerzg7.js → cli-a92r1127.js} +1 -1
  28. package/dist/{cli-b8k7epj1.js → cli-be2161h1.js} +7 -7
  29. package/dist/{cli-xc27fwzg.js → cli-bnes4z6b.js} +2 -2
  30. package/dist/{cli-zrk6jxv8.js → cli-cxxe61f6.js} +1 -1
  31. package/dist/{cli-amyhm3gj.js → cli-dk44dxec.js} +1 -1
  32. package/dist/{cli-nc35pxb7.js → cli-eww120g8.js} +1 -0
  33. package/dist/{cli-a0kcty51.js → cli-f01h25yt.js} +1 -1
  34. package/dist/{cli-82d3nkc3.js → cli-f0g3pgvf.js} +1 -1
  35. package/dist/{cli-1ephgwnq.js → cli-ftc1g5tj.js} +2 -2
  36. package/dist/{cli-2v045xyf.js → cli-fv5hepyy.js} +3 -3
  37. package/dist/{cli-bnz0r3kc.js → cli-g35m2xwm.js} +4 -4
  38. package/dist/{cli-qje9k2nh.js → cli-g9ypd5en.js} +12 -2
  39. package/dist/{cli-w6nadkh4.js → cli-j99azg3g.js} +3 -3
  40. package/dist/{cli-er83cjbn.js → cli-k8g16gz3.js} +416 -116
  41. package/dist/{cli-4dg55wsk.js → cli-kpw04va0.js} +1 -1
  42. package/dist/{cli-3cgngyd8.js → cli-ms85309d.js} +33 -15
  43. package/dist/{cli-v3yr2gbg.js → cli-n72rg53p.js} +1471 -635
  44. package/dist/{cli-37yb7307.js → cli-p14m2cnp.js} +1 -1
  45. package/dist/{cli-2zqpkvtt.js → cli-qfxc84gh.js} +1 -1
  46. package/dist/{cli-44159k28.js → cli-qwhy2qma.js} +1 -1
  47. package/dist/{cli-2y91wnbh.js → cli-st8aw1m6.js} +221 -9
  48. package/dist/{cli-vq97g1jq.js → cli-tw4p90jb.js} +92 -192
  49. package/dist/{cli-te6b5wvg.js → cli-v0yrfmdh.js} +1 -1
  50. package/dist/{cli-xj0re5tm.js → cli-v8fjakwf.js} +1 -1
  51. package/dist/{cli-p20r8w42.js → cli-wt0jf9hm.js} +215 -80
  52. package/dist/{cli-q6r7t299.js → cli-xpa64rek.js} +33 -11
  53. package/dist/{cli-vdm20wej.js → cli-z7d29rw9.js} +2 -2
  54. package/dist/cli.js +19 -19
  55. package/dist/{codex-adapter-968xwfy7.js → codex-adapter-tn6k5mkg.js} +1 -1
  56. package/dist/{codex-session-runner-ht4z99fa.js → codex-session-runner-7vjt7jbw.js} +1 -1
  57. package/dist/{commands-pcymaeg9.js → commands-t7rz9146.js} +2 -2
  58. package/dist/{controller-fpjyk46r.js → controller-m2jasma5.js} +2 -2
  59. package/dist/{controllers-connect-mwzx1fh6.js → controllers-connect-9ftpex99.js} +19 -19
  60. package/dist/{cursor-adapter-cp4s2e2f.js → cursor-adapter-mjv79e4z.js} +1 -1
  61. package/dist/{db-xsjg9jqq.js → db-6sfrn9g3.js} +1 -1
  62. package/dist/{db-sgd12bt9.js → db-rn673r06.js} +3 -3
  63. package/dist/{dispatcher-x0jfw2c9.js → dispatcher-c155xz0p.js} +17 -17
  64. package/dist/{dsh-adapter-jrq7ma7h.js → dsh-adapter-3mmszc1x.js} +1 -1
  65. package/dist/{external-channel-8njj4h3b.js → external-channel-35k6tkv8.js} +2 -2
  66. package/dist/{grok-adapter-kkr97v2f.js → grok-adapter-tfrq7tg1.js} +2 -2
  67. package/dist/handlers-7gw64dxw.js +39 -0
  68. package/dist/{heartbeat-wd03zhn0.js → heartbeat-dyg4npkp.js} +20 -20
  69. package/dist/{hook-f0vghj42.js → hook-drspbwpe.js} +1 -1
  70. package/dist/{hook-xzj2ts2p.js → hook-x26b31bg.js} +1 -1
  71. package/dist/{http-4hwxv62p.js → http-pk972xyw.js} +355 -216
  72. package/dist/{index-ww2vznkp.js → index-arytgj5q.js} +1 -1
  73. package/dist/{index-hg0x2cdv.js → index-bgdyvcnv.js} +17 -17
  74. package/dist/{index-c4ykd0f1.js → index-dr94zbnh.js} +13348 -11611
  75. package/dist/{index-gdh8jrdm.js → index-gabbcdn2.js} +17 -17
  76. package/dist/{index-97q4xn03.js → index-jwxkkex2.js} +129 -75
  77. package/dist/index-tfb26zhy.js +41 -0
  78. package/dist/{keepalive-hrh7xnr9.js → keepalive-7yrng7px.js} +3 -3
  79. package/dist/{lead-ee8vazz2.js → lead-7e02z839.js} +29 -29
  80. package/dist/{maintenance-e8wnwnqx.js → maintenance-e6cemdqt.js} +1 -1
  81. package/dist/{node-3v3f08f7.js → node-de6akczr.js} +10 -9
  82. package/dist/{oauth-refresh-sweep-zm0yj4sj.js → oauth-refresh-sweep-yw3xdbcj.js} +2 -2
  83. package/dist/{onboard-dtwcq603.js → onboard-0a9y5yrc.js} +2 -2
  84. package/dist/{otel-impl-w3fbhpn0.js → otel-impl-trjpkfb7.js} +1 -1
  85. package/dist/{pricing-refresh-j38dehfs.js → pricing-refresh-d2b5my0y.js} +3 -3
  86. package/dist/{rbac-roles-ejxx9b35.js → rbac-roles-hey3yv9d.js} +2 -2
  87. package/dist/{rbac-roles-ae8yttq4.js → rbac-roles-nxh5ahwk.js} +1 -1
  88. package/dist/{registry-rxw10xzg.js → registry-ajhexe44.js} +1 -1
  89. package/dist/{render-v2-n16n0phe.js → render-v2-rr3p2atg.js} +3 -3
  90. package/dist/{resume-z0fgjc38.js → resume-2efkf1s1.js} +5 -5
  91. package/dist/{session-access-cv3mq6mc.js → session-access-s2mttxpw.js} +4 -4
  92. package/dist/{setup-mafhj3yt.js → setup-vypma5yt.js} +1 -1
  93. package/dist/{work-objects-8b86mgjp.js → work-objects-rvhckdkp.js} +20 -20
  94. package/dist/{worker-16s75hm5.js → worker-5snytpbd.js} +29 -29
  95. package/openapi.json +9 -2
  96. package/package.json +7 -7
  97. package/src/apps/catalog.generated.json +206 -4
  98. package/src/apps/page-validator.ts +13 -1
  99. package/src/be/chunking.ts +42 -9
  100. package/src/be/db/tasks/draft-text.ts +15 -0
  101. package/src/be/db/tasks/read.ts +14 -1
  102. package/src/be/db.ts +5 -1
  103. package/src/be/memory/index-content.ts +36 -17
  104. package/src/be/memory/providers/openai-embedding.ts +115 -61
  105. package/src/be/memory/providers/sqlite-store.ts +69 -23
  106. package/src/be/memory/reranker.ts +31 -1
  107. package/src/be/memory/search-candidates.ts +47 -0
  108. package/src/be/memory/types.ts +14 -0
  109. package/src/be/scripts/typecheck.ts +2 -0
  110. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +106 -54
  111. package/src/be/seed-scripts/index.ts +2 -2
  112. package/src/be/swarm-config-guard.ts +24 -1
  113. package/src/be/task-attachment-store.ts +30 -0
  114. package/src/extensions/catalog.generated.json +4 -4
  115. package/src/extensions/contract-types.generated.ts +1 -1
  116. package/src/extensions/contract.ts +7 -0
  117. package/src/fs/provider.ts +13 -1
  118. package/src/heartbeat/heartbeat.ts +31 -11
  119. package/src/http/fs.ts +54 -34
  120. package/src/http/mcp-body.ts +37 -0
  121. package/src/http/mcp-user.ts +3 -5
  122. package/src/http/mcp.ts +6 -7
  123. package/src/http/memory.ts +26 -15
  124. package/src/http/page-proxy.ts +61 -5
  125. package/src/http/pages-public.ts +27 -44
  126. package/src/http/pages.ts +4 -4
  127. package/src/http/script-runs.ts +2 -0
  128. package/src/http/users.ts +12 -1
  129. package/src/integrations/chat-sdk/adapters.ts +7 -3
  130. package/src/integrations/chat-sdk/attachments.ts +90 -12
  131. package/src/integrations/chat-sdk/facts.ts +120 -0
  132. package/src/integrations/chat-sdk/inbound.ts +156 -8
  133. package/src/integrations/chat-sdk/limits.ts +24 -0
  134. package/src/integrations/chat-sdk/outbound-files.ts +186 -0
  135. package/src/integrations/chat-sdk/outbound.ts +234 -4
  136. package/src/integrations/chat-sdk/relay.ts +4 -1
  137. package/src/integrations/chat-sdk/router.ts +28 -2
  138. package/src/integrations/chat-sdk/steering.ts +9 -0
  139. package/src/integrations/chat-sdk/templates.ts +14 -0
  140. package/src/integrations/chat-sdk/thread-buffer.ts +4 -0
  141. package/src/mcp-limits.ts +20 -0
  142. package/src/pages/browser-sdk.ts +8 -3
  143. package/src/pages/feedback-overlay.ts +1 -1
  144. package/src/providers/amp-adapter.ts +1 -1
  145. package/src/providers/codex-adapter.ts +106 -119
  146. package/src/providers/codex-agents-md.ts +35 -229
  147. package/src/providers/cursor-adapter.ts +1 -1
  148. package/src/realtime/transport.ts +1 -2
  149. package/src/script-workflows/workflow-ctx.ts +1 -0
  150. package/src/scripts-runtime/types/stdlib.d.ts +2 -0
  151. package/src/scripts-runtime/types/swarm-extension.d.ts +8 -0
  152. package/src/scripts-runtime/types/swarm-sdk.d.ts +2 -0
  153. package/src/server-user.ts +2 -0
  154. package/src/server.ts +2 -0
  155. package/src/slack/assistant.ts +2 -2
  156. package/src/slack/files.ts +2 -0
  157. package/src/slack/handlers.ts +4 -4
  158. package/src/slack/inbound-files.ts +39 -6
  159. package/src/slack/thread-buffer.ts +2 -1
  160. package/src/tasks/task-terminal-effects.ts +21 -17
  161. package/src/tests/apps-card-grid.test.ts +197 -0
  162. package/src/tests/apps-catalog-additions.test.ts +120 -0
  163. package/src/tests/apps-tree.test.ts +129 -0
  164. package/src/tests/chat-sdk-attachments-reply.test.ts +52 -0
  165. package/src/tests/chat-sdk-config.test.ts +11 -0
  166. package/src/tests/chat-sdk-facts.test.ts +23 -0
  167. package/src/tests/chat-sdk-inbound.test.ts +558 -4
  168. package/src/tests/chat-sdk-outbound-files.test.ts +652 -0
  169. package/src/tests/codex-adapter.test.ts +167 -242
  170. package/src/tests/config-api-only-keys.test.ts +9 -0
  171. package/src/tests/cors-allowlist.test.ts +1 -1
  172. package/src/tests/extensions-example-slack-reply-gate.test.ts +262 -91
  173. package/src/tests/heartbeat-checklist.test.ts +33 -0
  174. package/src/tests/heartbeat-jev-gate-credentials.test.ts +44 -0
  175. package/src/tests/heartbeat-jev-gate.test.ts +242 -1
  176. package/src/tests/kv-page-proxy.test.ts +91 -5
  177. package/src/tests/launch-password-rejection.test.ts +2 -2
  178. package/src/tests/mcp-input-caps.test.ts +294 -0
  179. package/src/tests/memory-chunked-search-starvation.test.ts +200 -0
  180. package/src/tests/memory-embedding-input-cap.test.ts +114 -0
  181. package/src/tests/memory.test.ts +14 -0
  182. package/src/tests/page-guest-session.test.ts +19 -8
  183. package/src/tests/page-proxy-authed.test.ts +1 -1
  184. package/src/tests/page-proxy.test.ts +17 -10
  185. package/src/tests/page-session.test.ts +102 -1
  186. package/src/tests/pages-authed-mode.test.ts +82 -12
  187. package/src/tests/pages-password-mode.test.ts +5 -5
  188. package/src/tests/realtime-transport.test.ts +13 -7
  189. package/src/tests/script-runs-http.test.ts +84 -0
  190. package/src/tests/scripts-http.test.ts +10 -1
  191. package/src/tests/swarm-config-export-to-env.test.ts +22 -3
  192. package/src/tests/task-audio-transcription.test.ts +299 -0
  193. package/src/tests/task-completion-memory-chunking.test.ts +434 -0
  194. package/src/tests/task-terminal-secret-scrub.test.ts +6 -1
  195. package/src/tests/transcription.test.ts +299 -0
  196. package/src/tests/workflow-system-one-decision-providers.test.ts +98 -1
  197. package/src/tests/workflow-system-one-decision.test.ts +2 -1
  198. package/src/tools/chat-access.ts +10 -0
  199. package/src/tools/chat-post.ts +31 -11
  200. package/src/tools/chat-reply.ts +32 -10
  201. package/src/tools/memory-search.ts +3 -1
  202. package/src/tools/system-one-decide.ts +17 -4
  203. package/src/types.ts +6 -0
  204. package/src/utils/config-env-export.ts +3 -1
  205. package/src/utils/page-session.ts +133 -20
  206. package/src/utils/transcription.ts +246 -0
  207. package/src/workflows/executors/system-one-decision.ts +28 -7
  208. package/src/workflows/executors/system-one-providers.ts +39 -4
  209. package/templates/extensions/slack-reply-gate/README.md +24 -22
  210. package/templates/extensions/slack-reply-gate/hooks.ts +146 -95
  211. package/templates/extensions/slack-reply-gate/manifest.json +2 -2
  212. package/templates/skills/apps/SKILL.md +28 -6
  213. package/templates/skills/apps/content.md +28 -6
  214. package/templates/skills/chat-sdk/content.md +6 -2
  215. package/templates/skills/code-quality/content.md +2 -1
  216. package/templates/skills/heartbeat-runbook/content.md +5 -5
  217. package/templates/skills/pages/content.md +6 -4
  218. package/templates/skills/swarm-scripts/SKILL.md +2 -2
  219. package/templates/skills/swarm-scripts/content.md +2 -2
  220. package/dist/handlers-0pvee9nw.js +0 -39
  221. package/dist/index-thm0y6a8.js +0 -41
@@ -155,6 +155,8 @@ import {
155
155
  computeScore,
156
156
  rerank,
157
157
  init_reranker,
158
+ searchMemoryCandidates,
159
+ init_search_candidates,
158
160
  rowToCandidate,
159
161
  init_sqlite_store,
160
162
  getEmbeddingProvider2,
@@ -332,19 +334,19 @@ import {
332
334
  recordInlineScriptRun2,
333
335
  exports_db,
334
336
  init_db3
335
- } from "./cli-p20r8w42.js";
337
+ } from "./cli-wt0jf9hm.js";
336
338
  import {
337
339
  getUserGrant2,
338
340
  init_rbac_roles
339
- } from "./cli-4dg55wsk.js";
341
+ } from "./cli-kpw04va0.js";
340
342
  import {
341
343
  ensurePricingSeeded2,
342
344
  ensureRbacSeeded2,
343
345
  ensureModelProfilesSeeded2
344
- } from "./cli-t7cyef5g.js";
346
+ } from "./cli-43x64hv3.js";
345
347
  import {
346
348
  loadModelsDevCache
347
- } from "./cli-amyhm3gj.js";
349
+ } from "./cli-dk44dxec.js";
348
350
  import {
349
351
  buildCatalogEntries,
350
352
  listModelCatalog,
@@ -354,12 +356,12 @@ import {
354
356
  loadModelsCatalog,
355
357
  requestModelCatalogRefresh2,
356
358
  startPricingRefreshLoop2
357
- } from "./cli-xc27fwzg.js";
359
+ } from "./cli-bnes4z6b.js";
358
360
  import {
359
361
  ampPinProviderError,
360
362
  ampPinCatalogError,
361
363
  ampModelError
362
- } from "./cli-2zqpkvtt.js";
364
+ } from "./cli-qfxc84gh.js";
363
365
  import {
364
366
  notifyAutomationPreflightFailure,
365
367
  isNeedsSetupFailure,
@@ -411,7 +413,7 @@ import {
411
413
  buildNodeInterpolationCtx,
412
414
  interpolateNodeConfig,
413
415
  scriptBodyInterpolationError
414
- } from "./cli-51y09c6p.js";
416
+ } from "./cli-9hstj09h.js";
415
417
  import {
416
418
  require_dist2,
417
419
  publicEndpointSsrfOptions,
@@ -471,14 +473,14 @@ import {
471
473
  deleteApp,
472
474
  typecheckScript,
473
475
  parseSkillContent
474
- } from "./cli-2y91wnbh.js";
476
+ } from "./cli-st8aw1m6.js";
475
477
  import {
476
478
  buildAuthorizationUrl,
477
479
  onAuthorizationRefreshed,
478
480
  ensureAuthorizationTokenOrThrow,
479
481
  ensureToken,
480
482
  ensureTokenOrThrow
481
- } from "./cli-esxerzg7.js";
483
+ } from "./cli-a92r1127.js";
482
484
  import {
483
485
  detachedProcessGroup,
484
486
  registerProcessGroup,
@@ -508,14 +510,14 @@ import {
508
510
  getSlackApp2,
509
511
  startSlackApp2,
510
512
  stopSlackApp2
511
- } from "./cli-qkhc5aqy.js";
513
+ } from "./cli-37j04k05.js";
512
514
  import {
513
515
  slackCode,
514
516
  slackMissingScopeMessage,
515
517
  withAutoJoin,
516
518
  externalChannelToolError2,
517
519
  getChannelBlockReason2
518
- } from "./cli-1d70crsy.js";
520
+ } from "./cli-3a45zcgm.js";
519
521
  import {
520
522
  BaseExecutor,
521
523
  postApprovalCancellationUpdates,
@@ -533,7 +535,7 @@ import {
533
535
  definitionNodeIds,
534
536
  validateDefinition,
535
537
  applyDefinitionPatch
536
- } from "./cli-q6r7t299.js";
538
+ } from "./cli-xpa64rek.js";
537
539
  import {
538
540
  workflowEventBus2,
539
541
  init_event_bus
@@ -564,19 +566,21 @@ import {
564
566
  isPublicRoute,
565
567
  findRoute,
566
568
  route
567
- } from "./cli-cynvc9fj.js";
569
+ } from "./cli-018r4jq6.js";
568
570
  import {
569
571
  isMultiRuntimeEnabled
570
572
  } from "./cli-e8xyjvfc.js";
571
573
  import {
574
+ FilesError,
572
575
  providerPath,
576
+ normalizeStoredKey,
573
577
  AgentFsProvider,
574
578
  getFileStorageProvider2
575
- } from "./cli-qje9k2nh.js";
579
+ } from "./cli-g9ypd5en.js";
576
580
  import {
577
581
  getRuntimePool2,
578
582
  init_db
579
- } from "./cli-w6nadkh4.js";
583
+ } from "./cli-j99azg3g.js";
580
584
  import {
581
585
  getMemoryRaterNames,
582
586
  REFERENCES_SOURCE_MAX_LENGTH,
@@ -617,7 +621,7 @@ import {
617
621
  resolveSessionToken,
618
622
  fingerprintApiKey,
619
623
  init_users
620
- } from "./cli-9fhkkpj5.js";
624
+ } from "./cli-1f3qzw6y.js";
621
625
  import {
622
626
  isRbacEnabled,
623
627
  decideAdmission,
@@ -686,7 +690,7 @@ import {
686
690
  KvNamespaceSchema,
687
691
  KvKeySchema,
688
692
  init_types
689
- } from "./cli-nc35pxb7.js";
693
+ } from "./cli-eww120g8.js";
690
694
  import {
691
695
  generateDefaultClaudeMd2,
692
696
  generateDefaultSoulMd2,
@@ -757,7 +761,7 @@ import {
757
761
  import {
758
762
  init_package,
759
763
  package_default
760
- } from "./cli-pccfmtb5.js";
764
+ } from "./cli-94gwyg7m.js";
761
765
  import {
762
766
  realtimeBus,
763
767
  init_bus
@@ -786,6 +790,7 @@ import {
786
790
  import {
787
791
  scrubSecrets,
788
792
  scrubObject,
793
+ createValueScrubber,
789
794
  refreshSecretScrubberCache,
790
795
  registerVolatileSecret,
791
796
  registerSensitiveKeyName,
@@ -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);
@@ -21149,7 +21216,7 @@ class NotifyExecutor extends BaseExecutor {
21149
21216
  }
21150
21217
  }
21151
21218
  case "slack": {
21152
- const { getSlackApp } = await import("./app-rb7vc02s.js");
21219
+ const { getSlackApp } = await import("./app-353vre8g.js");
21153
21220
  const app = getSlackApp();
21154
21221
  if (!app) {
21155
21222
  return {
@@ -24512,7 +24579,7 @@ function setPreloadedTools(server, names) {
24512
24579
  async function applyPreToolCall(name, args, requestInfo, inputSchema) {
24513
24580
  if (requestInfo.callOrigin !== "mcp")
24514
24581
  return { args };
24515
- const dispatcher = await import("./dispatcher-x0jfw2c9.js");
24582
+ const dispatcher = await import("./dispatcher-c155xz0p.js");
24516
24583
  const result = await dispatcher.dispatchPre("pre.tool.call", { tool: name, args, requestInfo }, inputSchema ? {
24517
24584
  validateModify: async (data) => {
24518
24585
  const schema = normalizeObjectSchema(inputSchema) ?? inputSchema;
@@ -31268,7 +31335,11 @@ async function loadAdapter(name, config, logger) {
31268
31335
  switch (name) {
31269
31336
  case "telegram": {
31270
31337
  const { createTelegramAdapter } = await import("./index-g216q6jr.js");
31271
- return createTelegramAdapter({ ...base, allowUnverifiedWebhooks: false });
31338
+ return createTelegramAdapter({
31339
+ ...base,
31340
+ allowUnverifiedWebhooks: false,
31341
+ mentionOnReply: true
31342
+ });
31272
31343
  }
31273
31344
  case "slack": {
31274
31345
  const { createSlackAdapter } = await import("./index-zgvqzjsw.js");
@@ -31870,6 +31941,43 @@ function resetDiscordGatewayHealth() {
31870
31941
  // src/integrations/chat-sdk/inbound.ts
31871
31942
  init_zod();
31872
31943
  init_db3();
31944
+
31945
+ // src/be/unmapped-identities.ts
31946
+ init_db3();
31947
+ var TTL_MS = 30 * 24 * 60 * 60 * 1000;
31948
+ function namespace(kind) {
31949
+ return `integration:unmapped:${kind}`;
31950
+ }
31951
+ async function recordUnmappedIdentity(kind, externalId, meta) {
31952
+ const ns = namespace(kind);
31953
+ const now = new Date().toISOString();
31954
+ const expiresAt = Date.now() + TTL_MS;
31955
+ const countKey = `${externalId}:count`;
31956
+ const countBefore = await getKv2(ns, countKey);
31957
+ await upsertKv2({
31958
+ namespace: ns,
31959
+ key: `${externalId}:meta`,
31960
+ value: {
31961
+ lastSeenAt: now,
31962
+ sampleEventType: meta.sampleEventType,
31963
+ sampleContext: meta.sampleContext.slice(0, 100)
31964
+ },
31965
+ valueType: "json",
31966
+ expiresAt
31967
+ });
31968
+ const incremented = await incrKv2(ns, countKey, 1);
31969
+ if (countBefore === null) {
31970
+ await upsertKv2({
31971
+ namespace: ns,
31972
+ key: countKey,
31973
+ value: Number(incremented.value),
31974
+ valueType: "integer",
31975
+ expiresAt
31976
+ });
31977
+ }
31978
+ }
31979
+
31980
+ // src/integrations/chat-sdk/inbound.ts
31873
31981
  init_resolver();
31874
31982
  init_context_key();
31875
31983
  init_secret_scrubber();
@@ -31918,10 +32026,191 @@ async function recordTaskAttachmentUpload(input) {
31918
32026
  throw error;
31919
32027
  }
31920
32028
  }
32029
+ function scopeFromAttachment(attachment) {
32030
+ const storedKey = attachment.providerKey ?? attachment.path ?? "";
32031
+ return {
32032
+ taskId: attachment.taskId,
32033
+ name: attachment.name,
32034
+ key: storedKey.trim() ? storedKey : undefined,
32035
+ orgId: attachment.orgId,
32036
+ driveId: attachment.driveId
32037
+ };
32038
+ }
32039
+ function backingProviderId(attachment) {
32040
+ if (attachment.kind === "agent-fs")
32041
+ return attachment.providerId ?? "agent-fs";
32042
+ if (attachment.providerId === "local-fs")
32043
+ return "local-fs";
32044
+ return null;
32045
+ }
32046
+
32047
+ // src/utils/transcription.ts
32048
+ init_secret_scrubber();
32049
+ var TRANSCRIPTION_TIMEOUT_MS = 60000;
32050
+ var TRANSCRIPTION_API_KEY_ENV = "TRANSCRIPTION_API_KEY";
32051
+ var openAIShape = {
32052
+ path: "/audio/transcriptions",
32053
+ modelField: "model",
32054
+ authHeaders: (apiKey) => ({ authorization: `Bearer ${apiKey}` })
32055
+ };
32056
+ var PROVIDERS = {
32057
+ openai: {
32058
+ keyEnv: "OPENAI_API_KEY",
32059
+ defaultBaseUrl: "https://api.openai.com/v1",
32060
+ defaultModel: "whisper-1",
32061
+ ...openAIShape
32062
+ },
32063
+ groq: {
32064
+ keyEnv: "GROQ_API_KEY",
32065
+ defaultBaseUrl: "https://api.groq.com/openai/v1",
32066
+ defaultModel: "whisper-large-v3-turbo",
32067
+ ...openAIShape
32068
+ },
32069
+ elevenlabs: {
32070
+ keyEnv: "ELEVENLABS_API_KEY",
32071
+ defaultBaseUrl: "https://api.elevenlabs.io/v1",
32072
+ defaultModel: "scribe_v2",
32073
+ path: "/speech-to-text",
32074
+ modelField: "model_id",
32075
+ authHeaders: (apiKey) => ({ "xi-api-key": apiKey })
32076
+ }
32077
+ };
32078
+ var AUTO_DETECT_ORDER = ["elevenlabs", "openai", "groq"];
32079
+ var TRANSCRIPTION_ENV_KEYS = [
32080
+ TRANSCRIPTION_API_KEY_ENV,
32081
+ "TRANSCRIPTION_PROVIDER",
32082
+ "TRANSCRIPTION_BASE_URL",
32083
+ "TRANSCRIPTION_MODEL",
32084
+ ...AUTO_DETECT_ORDER.map((name) => PROVIDERS[name].keyEnv)
32085
+ ];
32086
+
32087
+ class TranscriptionError extends Error {
32088
+ constructor(message) {
32089
+ super(message);
32090
+ this.name = "TranscriptionError";
32091
+ }
32092
+ }
32093
+ function envValue(key) {
32094
+ return process.env[key]?.trim() || undefined;
32095
+ }
32096
+ function resolveTranscriptionConfig() {
32097
+ const pinned = envValue("TRANSCRIPTION_PROVIDER")?.toLowerCase();
32098
+ const explicitKey = envValue(TRANSCRIPTION_API_KEY_ENV);
32099
+ if (explicitKey) {
32100
+ return {
32101
+ provider: pinned ?? "openai",
32102
+ apiKey: explicitKey,
32103
+ keyEnv: TRANSCRIPTION_API_KEY_ENV,
32104
+ source: "explicit"
32105
+ };
32106
+ }
32107
+ const candidates = pinned ? AUTO_DETECT_ORDER.filter((name) => name === pinned) : AUTO_DETECT_ORDER;
32108
+ for (const name of candidates) {
32109
+ const { keyEnv } = PROVIDERS[name];
32110
+ const apiKey = envValue(keyEnv);
32111
+ if (apiKey)
32112
+ return { provider: name, apiKey, keyEnv, source: "auto" };
32113
+ }
32114
+ return null;
32115
+ }
32116
+ function isTranscriptionConfigured() {
32117
+ return resolveTranscriptionConfig() !== null;
32118
+ }
32119
+ function providerSpec(name) {
32120
+ if (!Object.hasOwn(PROVIDERS, name)) {
32121
+ throw new TranscriptionError(`TRANSCRIPTION_PROVIDER "${name}" is not supported (use ${Object.keys(PROVIDERS).join(", ")})`);
32122
+ }
32123
+ return PROVIDERS[name];
32124
+ }
32125
+ function errorDetail(payload, status) {
32126
+ const error = payload?.error;
32127
+ if (typeof error?.message === "string")
32128
+ return error.message;
32129
+ const detail = payload?.detail;
32130
+ if (typeof detail === "string")
32131
+ return detail;
32132
+ if (typeof detail?.message === "string")
32133
+ return detail.message;
32134
+ return `HTTP ${status}`;
32135
+ }
32136
+ async function transcribeAudio(input) {
32137
+ const config = resolveTranscriptionConfig();
32138
+ if (!config)
32139
+ throw new TranscriptionError("no transcription provider key is set");
32140
+ const { apiKey } = config;
32141
+ const provider = providerSpec(config.provider);
32142
+ const baseUrlOverride = config.source === "explicit" ? process.env.TRANSCRIPTION_BASE_URL?.trim() : undefined;
32143
+ const baseUrl = (baseUrlOverride || provider.defaultBaseUrl).replace(/\/+$/, "");
32144
+ const keyScrubber = createValueScrubber([{ value: apiKey, name: config.keyEnv }]);
32145
+ const scrub = (text) => scrubSecrets(keyScrubber.text(text));
32146
+ const form = new FormData;
32147
+ const type = input.mimeType ?? input.data.type;
32148
+ form.append("file", type ? new Blob([input.data], { type }) : input.data, input.filename);
32149
+ form.append(provider.modelField, process.env.TRANSCRIPTION_MODEL?.trim() || provider.defaultModel);
32150
+ let response;
32151
+ try {
32152
+ response = await fetch(`${baseUrl}${provider.path}`, {
32153
+ method: "POST",
32154
+ headers: provider.authHeaders(apiKey),
32155
+ body: form,
32156
+ signal: AbortSignal.timeout(TRANSCRIPTION_TIMEOUT_MS)
32157
+ });
32158
+ } catch (error) {
32159
+ if (error instanceof Error && error.name === "TimeoutError") {
32160
+ throw new TranscriptionError(`no answer within ${TRANSCRIPTION_TIMEOUT_MS / 1000} s`);
32161
+ }
32162
+ throw new TranscriptionError(scrub(error instanceof Error ? error.message : String(error)));
32163
+ }
32164
+ const payload = await response.json().catch(() => null);
32165
+ if (!response.ok || typeof payload?.text !== "string") {
32166
+ throw new TranscriptionError(scrub(errorDetail(payload, response.status)));
32167
+ }
32168
+ return payload.text.trim();
32169
+ }
32170
+ 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(", ")})`;
32171
+ var AUDIO_EXTENSIONS = {
32172
+ "audio/ogg": "ogg",
32173
+ "audio/opus": "ogg",
32174
+ "audio/mpeg": "mp3",
32175
+ "audio/mp4": "m4a",
32176
+ "audio/x-m4a": "m4a",
32177
+ "audio/wav": "wav",
32178
+ "audio/x-wav": "wav",
32179
+ "audio/webm": "webm"
32180
+ };
32181
+ async function transcribeAudioNotes(files, logPrefix) {
32182
+ const notes = new Map;
32183
+ if (files.length === 0)
32184
+ return notes;
32185
+ if (!isTranscriptionConfigured()) {
32186
+ for (const file of files)
32187
+ notes.set(file.key, NOT_TRANSCRIBED_NOTE);
32188
+ return notes;
32189
+ }
32190
+ for (const file of files) {
32191
+ const extension = AUDIO_EXTENSIONS[file.mimeType ?? ""] ?? "ogg";
32192
+ const filename = /\.\w+$/.test(file.name) ? file.name : `${file.name}.${extension}`;
32193
+ try {
32194
+ const text = await transcribeAudio({ data: file.data, filename, mimeType: file.mimeType });
32195
+ notes.set(file.key, `[Transcript of ${file.name}]
32196
+ ${text || "(no speech recognized)"}`);
32197
+ } catch (error) {
32198
+ const reason = scrubSecrets(error instanceof Error ? error.message : String(error));
32199
+ console.warn(`${logPrefix} could not transcribe file ${file.key}: ${reason}`);
32200
+ notes.set(file.key, `(transcription failed: ${reason})`);
32201
+ }
32202
+ }
32203
+ return notes;
32204
+ }
31921
32205
 
31922
32206
  // src/integrations/chat-sdk/attachments.ts
31923
32207
  var DRAFT_LEASE_REFRESH_MS = 60000;
31924
32208
  var SHARED_FILE_INTENT = "user-upload";
32209
+ var MB = 1024 * 1024;
32210
+ var CHAT_INBOUND_FILE_LIMITS = { telegram: 20 * MB };
32211
+ function chatInboundFileLimit(adapter) {
32212
+ return Math.min(CHAT_INBOUND_FILE_LIMITS[adapter] ?? MAX_TASK_ATTACHMENT_BYTES, MAX_TASK_ATTACHMENT_BYTES);
32213
+ }
31925
32214
  function formatFileSize(bytes) {
31926
32215
  if (bytes < 1024)
31927
32216
  return `${bytes} B`;
@@ -31942,16 +32231,42 @@ function toChatFiles(adapter, messageId, attachments) {
31942
32231
  attachment
31943
32232
  }));
31944
32233
  }
31945
- function buildChatAttachmentText(files, failed = []) {
32234
+ function buildChatAttachmentText(files, failed = [], notes = new Map) {
31946
32235
  const reasons = new Map(failed.map((f) => [f.file.id, f.reason]));
31947
32236
  return files.map((f) => {
31948
32237
  const size = typeof f.size === "number" ? formatFileSize(f.size) : "unknown size";
31949
32238
  const line = `[File: ${f.name} (${f.mimeType ?? "unknown type"}, ${size}) id=${f.id}]`;
31950
32239
  const reason = reasons.get(f.id);
31951
- return reason ? `${line} (not attached: ${reason})` : line;
32240
+ const note = notes.get(f.id);
32241
+ return [reason ? `${line} (not attached: ${reason})` : line, note].filter(Boolean).join(`
32242
+ `);
31952
32243
  }).join(`
31953
32244
  `);
31954
32245
  }
32246
+ function markdownLiteral(value) {
32247
+ const text = value.replace(/[\r\n]+/g, " ");
32248
+ const longestRun = Math.max(0, ...(text.match(/`+/g) ?? []).map((run) => run.length));
32249
+ const fence = "`".repeat(longestRun + 1);
32250
+ const pad = /^[` ]|[` ]$/.test(text) ? " " : "";
32251
+ return `${fence}${pad}${text}${pad}${fence}`;
32252
+ }
32253
+ function formatTooLargeReply(failed) {
32254
+ const lines = failed.map((f) => `- ${markdownLiteral(f.file.name)}: ${f.reason}`);
32255
+ return [
32256
+ `Too large to read, so the swarm did not get ${failed.length === 1 ? "this file" : "these files"}:`,
32257
+ ...lines,
32258
+ "Send a smaller file or a link."
32259
+ ].join(`
32260
+ `);
32261
+ }
32262
+ async function transcribeChatAudio(fetched) {
32263
+ return transcribeAudioNotes(fetched.filter(({ file }) => file.attachment.type === "audio").map(({ file, path }) => ({
32264
+ key: file.id,
32265
+ name: file.name,
32266
+ data: Bun.file(path),
32267
+ mimeType: file.mimeType
32268
+ })), "[chat-sdk]");
32269
+ }
31955
32270
  async function readAttachment(attachment) {
31956
32271
  if (attachment.data instanceof Blob)
31957
32272
  return new Uint8Array(await attachment.data.arrayBuffer());
@@ -31975,17 +32290,25 @@ async function fetchChatFiles(files) {
31975
32290
  };
31976
32291
  if (files.length === 0)
31977
32292
  return result;
31978
- const limit = `larger than the ${MAX_TASK_ATTACHMENT_BYTES / (1024 * 1024)} MB limit`;
32293
+ const tooLarge = (file, size) => {
32294
+ const limit = chatInboundFileLimit(file.adapter);
32295
+ const platform = file.adapter.charAt(0).toUpperCase() + file.adapter.slice(1);
32296
+ return {
32297
+ file,
32298
+ reason: `too large (${formatFileSize(size)}, the limit for files sent to the ${platform} bot is ${formatFileSize(limit)})`,
32299
+ tooLarge: true
32300
+ };
32301
+ };
31979
32302
  dir = await mkdtemp(join(tmpdir2(), "chat-files-"));
31980
32303
  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 });
32304
+ if (typeof file.size === "number" && file.size > chatInboundFileLimit(file.adapter)) {
32305
+ result.failed.push(tooLarge(file, file.size));
31983
32306
  continue;
31984
32307
  }
31985
32308
  try {
31986
32309
  const bytes = await readAttachment(file.attachment);
31987
- if (bytes.byteLength > MAX_TASK_ATTACHMENT_BYTES) {
31988
- result.failed.push({ file, reason: limit });
32310
+ if (bytes.byteLength > chatInboundFileLimit(file.adapter)) {
32311
+ result.failed.push(tooLarge(file, bytes.byteLength));
31989
32312
  continue;
31990
32313
  }
31991
32314
  const path = join(dir, String(index));
@@ -32060,6 +32383,63 @@ async function attachChatFilesToTask(taskId, fetched) {
32060
32383
  return unattached;
32061
32384
  }
32062
32385
 
32386
+ // src/integrations/chat-sdk/facts.ts
32387
+ var SNIPPET_MAX = 80;
32388
+ function snippet2(text) {
32389
+ const flat = text?.replace(/\s+/g, " ").trim();
32390
+ if (!flat)
32391
+ return;
32392
+ return flat.length > SNIPPET_MAX ? `${flat.slice(0, SNIPPET_MAX)}...` : flat;
32393
+ }
32394
+ function personLabel(name, username, fallback) {
32395
+ if (name && username && name !== username)
32396
+ return `${name} (@${username})`;
32397
+ if (username)
32398
+ return `@${username}`;
32399
+ return name || fallback;
32400
+ }
32401
+ function telegramFacts(raw, message, botUserId) {
32402
+ const reply = raw.reply_to_message;
32403
+ const replyIsTopicRoot = reply !== undefined && (reply.forum_topic_created !== undefined || raw.is_topic_message === true && reply.message_id === raw.message_thread_id);
32404
+ const realReply = reply && !replyIsTopicRoot ? reply : undefined;
32405
+ const topicName = replyIsTopicRoot ? reply?.forum_topic_created?.name : undefined;
32406
+ const name = [raw.from?.first_name, raw.from?.last_name].filter(Boolean).join(" ").trim();
32407
+ return {
32408
+ chatType: raw.chat?.type,
32409
+ isForum: raw.chat?.is_forum === true ? true : undefined,
32410
+ title: raw.chat?.title,
32411
+ topic: raw.is_topic_message === true && raw.message_thread_id !== undefined ? topicName ? `"${topicName}"` : `#${raw.message_thread_id}` : undefined,
32412
+ from: personLabel(name || undefined, raw.from?.username, message.author.userId),
32413
+ replyToBot: realReply?.from?.id !== undefined && botUserId !== undefined && String(realReply.from.id) === botUserId,
32414
+ replyToSnippet: snippet2(realReply?.text ?? realReply?.caption)
32415
+ };
32416
+ }
32417
+ function readChatMessageFacts(thread, message) {
32418
+ const raw = message.raw;
32419
+ if (thread.adapter.name === "telegram" && raw && typeof raw === "object") {
32420
+ return telegramFacts(raw, message, thread.adapter.botUserId);
32421
+ }
32422
+ const { fullName, userName, userId } = message.author;
32423
+ return {
32424
+ chatType: thread.isDM ? "dm" : undefined,
32425
+ from: personLabel(fullName || undefined, userName || undefined, userId),
32426
+ replyToBot: message.replyTo?.author.isMe === true,
32427
+ replyToSnippet: snippet2(message.replyTo?.text)
32428
+ };
32429
+ }
32430
+ function formatChatHeaderFacts(adapter, facts, addressed) {
32431
+ const oneLine = (text) => text.replace(/\s+/g, " ").trim();
32432
+ const parts = [adapter];
32433
+ if (facts.chatType)
32434
+ parts.push(facts.title ? `${facts.chatType} "${oneLine(facts.title)}"` : facts.chatType);
32435
+ if (facts.isForum)
32436
+ parts.push(facts.topic ? `forum topic ${oneLine(facts.topic)}` : "forum");
32437
+ parts.push(`from: ${oneLine(facts.from)}`, `addressed: ${addressed}`);
32438
+ if (facts.replyToSnippet)
32439
+ parts.push(`reply-to: "${facts.replyToSnippet}"`);
32440
+ return parts.join(" · ");
32441
+ }
32442
+
32063
32443
  // src/integrations/chat-sdk/outbound.ts
32064
32444
  init_secret_scrubber();
32065
32445
  init_event_bus();
@@ -32075,6 +32455,17 @@ var FALLBACK_LIMIT = 2000;
32075
32455
  function chatMessageLimit(adapter) {
32076
32456
  return CHAT_MESSAGE_LIMITS[adapter] ?? FALLBACK_LIMIT;
32077
32457
  }
32458
+ var MB2 = 1024 * 1024;
32459
+ var CHAT_UPLOAD_LIMITS = {
32460
+ telegram: 50 * MB2,
32461
+ discord: 10 * MB2
32462
+ };
32463
+ var FALLBACK_UPLOAD_LIMIT = 50 * MB2;
32464
+ var TELEGRAM_PHOTO_LIMIT = 10 * MB2;
32465
+ function chatUploadLimit(adapter) {
32466
+ return CHAT_UPLOAD_LIMITS[adapter] ?? FALLBACK_UPLOAD_LIMIT;
32467
+ }
32468
+ var CHAT_FILES_PER_MESSAGE = 10;
32078
32469
  function splitChatMessage(text, limit) {
32079
32470
  if (limit <= 0)
32080
32471
  throw new Error("splitChatMessage: limit must be positive");
@@ -32115,6 +32506,15 @@ function adapterOfChatId(id) {
32115
32506
  const index = id.indexOf(":");
32116
32507
  return index === -1 ? id : id.slice(0, index);
32117
32508
  }
32509
+
32510
+ class ChatFileTooLargeError extends Error {
32511
+ sizeBytes;
32512
+ constructor(sizeBytes) {
32513
+ super(`file is ${formatFileSize(sizeBytes)}`);
32514
+ this.sizeBytes = sizeBytes;
32515
+ this.name = "ChatFileTooLargeError";
32516
+ }
32517
+ }
32118
32518
  async function postChunks(adapter, target, text) {
32119
32519
  const messageIds = [];
32120
32520
  let threadId;
@@ -32125,6 +32525,125 @@ async function postChunks(adapter, target, text) {
32125
32525
  }
32126
32526
  return { messageIds, threadId };
32127
32527
  }
32528
+ function resolveMimeType(name, ...candidates) {
32529
+ for (const candidate of candidates) {
32530
+ const type = candidate?.split(";")[0]?.trim().toLowerCase();
32531
+ if (type && type !== "application/octet-stream")
32532
+ return type;
32533
+ }
32534
+ return Bun.file(name).type.split(";")[0] ?? "application/octet-stream";
32535
+ }
32536
+ function telegramAttachmentType(mimeType, sizeBytes) {
32537
+ if ((mimeType === "image/jpeg" || mimeType === "image/png") && sizeBytes <= TELEGRAM_PHOTO_LIMIT) {
32538
+ return "image";
32539
+ }
32540
+ if (mimeType === "video/mp4")
32541
+ return "video";
32542
+ if (mimeType === "audio/mpeg" || mimeType === "audio/mp4" || mimeType === "audio/x-m4a") {
32543
+ return "audio";
32544
+ }
32545
+ return "file";
32546
+ }
32547
+ function fileGroupKey(adapter, file) {
32548
+ if (adapter !== "telegram")
32549
+ return "files";
32550
+ const type = telegramAttachmentType(file.mimeType, file.data.byteLength);
32551
+ return type === "image" || type === "video" ? "visual" : type;
32552
+ }
32553
+ function fileMessage(adapter, files) {
32554
+ if (adapter === "telegram") {
32555
+ return {
32556
+ markdown: "",
32557
+ attachments: files.map((file) => ({
32558
+ type: telegramAttachmentType(file.mimeType, file.data.byteLength),
32559
+ name: file.name,
32560
+ mimeType: file.mimeType,
32561
+ size: file.data.byteLength,
32562
+ data: file.data
32563
+ }))
32564
+ };
32565
+ }
32566
+ return {
32567
+ markdown: "",
32568
+ files: files.map((file) => ({ data: file.data, filename: file.name, mimeType: file.mimeType }))
32569
+ };
32570
+ }
32571
+ function platformName(adapter) {
32572
+ return adapter.charAt(0).toUpperCase() + adapter.slice(1);
32573
+ }
32574
+ async function postFiles(adapter, target, files) {
32575
+ const limit = chatUploadLimit(adapter);
32576
+ const tooLarge = (size) => `${formatFileSize(size)}, over the ${formatFileSize(limit)} upload limit of ${platformName(adapter)}`;
32577
+ const messageIds = [];
32578
+ const unsent = [];
32579
+ const groups = new Map;
32580
+ const send = async (group) => {
32581
+ try {
32582
+ const sent = await target.post(fileMessage(adapter, group));
32583
+ messageIds.push(sent.id);
32584
+ } catch (error) {
32585
+ const reason = `refused by ${platformName(adapter)} (${scrubSecrets(errorMessage(error))})`;
32586
+ for (const file of group)
32587
+ unsent.push({ name: file.name, reason });
32588
+ }
32589
+ };
32590
+ for (const file of files) {
32591
+ if (file.sizeBytes !== undefined && file.sizeBytes > limit) {
32592
+ unsent.push({ name: file.name, reason: tooLarge(file.sizeBytes) });
32593
+ continue;
32594
+ }
32595
+ let loaded;
32596
+ try {
32597
+ const { data, mimeType } = await file.load(limit);
32598
+ if (data.byteLength > limit)
32599
+ throw new ChatFileTooLargeError(data.byteLength);
32600
+ loaded = {
32601
+ name: file.name,
32602
+ mimeType: resolveMimeType(file.name, file.mimeType, mimeType),
32603
+ data: Buffer.from(data.buffer, data.byteOffset, data.byteLength)
32604
+ };
32605
+ } catch (error) {
32606
+ unsent.push({
32607
+ name: file.name,
32608
+ reason: error instanceof ChatFileTooLargeError ? tooLarge(error.sizeBytes) : `could not be read (${scrubSecrets(errorMessage(error))})`
32609
+ });
32610
+ continue;
32611
+ }
32612
+ const key = fileGroupKey(adapter, loaded);
32613
+ const group = [...groups.get(key) ?? [], loaded];
32614
+ if (group.length === CHAT_FILES_PER_MESSAGE) {
32615
+ groups.delete(key);
32616
+ await send(group);
32617
+ } else {
32618
+ groups.set(key, group);
32619
+ }
32620
+ }
32621
+ for (const group of groups.values())
32622
+ await send(group);
32623
+ return { messageIds, unsent };
32624
+ }
32625
+ function unsentFilesSummary(unsent) {
32626
+ return unsent.length === 0 ? "" : ` ${formatUnsentFilesNote(unsent)}`;
32627
+ }
32628
+ function singleLine(text) {
32629
+ return text.replace(/[\u0000-\u001f\u007f\u2028\u2029]+/g, " ").trim();
32630
+ }
32631
+ function breakMentions(text) {
32632
+ return text.replace(/@/g, "@​").replace(/<!/g, "<​!");
32633
+ }
32634
+ function codeSpan(text) {
32635
+ const value = breakMentions(singleLine(text)) || "(unnamed)";
32636
+ const longestRun = Math.max(0, ...(value.match(/`+/g) ?? []).map((run) => run.length));
32637
+ const fence = "`".repeat(longestRun + 1);
32638
+ const pad = value.startsWith("`") || value.endsWith("`") ? " " : "";
32639
+ return `${fence}${pad}${value}${pad}${fence}`;
32640
+ }
32641
+ function formatUnsentFilesNote(unsent) {
32642
+ const lines = unsent.map((file) => `- ${codeSpan(file.name)}: ${breakMentions(singleLine(file.reason))}`);
32643
+ const count = unsent.length === 1 ? "1 file" : `${unsent.length} files`;
32644
+ return [`Could not send ${count}:`, ...lines].join(`
32645
+ `);
32646
+ }
32128
32647
  async function postChatMessage(args) {
32129
32648
  assertTrustedChatTarget(args.threadId ?? args.channelId ?? "");
32130
32649
  const chat = getChatInstance(args.adapter);
@@ -32132,27 +32651,42 @@ async function postChatMessage(args) {
32132
32651
  throw new ChatAdapterUnavailableError(args.adapter);
32133
32652
  const text = scrubSecrets(args.text);
32134
32653
  let result;
32654
+ let target;
32135
32655
  if (args.threadId) {
32136
32656
  const thread = chat.thread(args.threadId);
32657
+ target = thread;
32137
32658
  const sent = await postChunks(args.adapter, thread, text);
32138
32659
  result = {
32139
32660
  adapter: args.adapter,
32140
32661
  threadId: thread.id,
32141
32662
  channelId: thread.channelId,
32142
- messageIds: sent.messageIds
32663
+ messageIds: sent.messageIds,
32664
+ unsentFiles: []
32143
32665
  };
32144
32666
  } else if (args.channelId) {
32145
32667
  const channel = chat.channel(args.channelId);
32668
+ target = channel;
32146
32669
  const sent = await postChunks(args.adapter, channel, text);
32147
32670
  result = {
32148
32671
  adapter: args.adapter,
32149
32672
  threadId: sent.threadId ?? channel.id,
32150
32673
  channelId: channel.id,
32151
- messageIds: sent.messageIds
32674
+ messageIds: sent.messageIds,
32675
+ unsentFiles: []
32152
32676
  };
32153
32677
  } else {
32154
32678
  throw new Error("postChatMessage needs a threadId or a channelId");
32155
32679
  }
32680
+ if (args.files?.length) {
32681
+ const sent = await postFiles(args.adapter, target, args.files);
32682
+ result.messageIds.push(...sent.messageIds);
32683
+ result.unsentFiles = sent.unsent;
32684
+ if (sent.unsent.length > 0) {
32685
+ const note = formatUnsentFilesNote(sent.unsent);
32686
+ const noted = await postChunks(args.adapter, target, scrubSecrets(note));
32687
+ result.messageIds.push(...noted.messageIds);
32688
+ }
32689
+ }
32156
32690
  emitChatMessageSent({
32157
32691
  adapter: result.adapter,
32158
32692
  channelId: result.channelId,
@@ -32218,9 +32752,19 @@ async function putChatChannelMapping(adapter, channelId, mapping) {
32218
32752
  async function deleteChatChannelMapping(adapter, channelId) {
32219
32753
  return deleteKv2(CHAT_CHANNELS_NAMESPACE, chatChannelKey(adapter, channelId));
32220
32754
  }
32755
+ function hasRoutingToken(text) {
32756
+ return /swarm#(?:[a-f0-9-]{36}|all)/i.test(text);
32757
+ }
32221
32758
  function stripRoutingTokens(text) {
32222
32759
  return text.replace(/swarm#[a-f0-9-]{36}/gi, "").replace(/swarm#all/gi, "").trim();
32223
32760
  }
32761
+ var DEFAULT_OWNER_WINDOW_MINUTES = 15;
32762
+ function chatOwnerWindowStart(now = Date.now()) {
32763
+ const raw = process.env.CHAT_SDK_OWNER_WINDOW_MIN?.trim();
32764
+ const value = raw ? Number(raw) : Number.NaN;
32765
+ const minutes = Number.isFinite(value) && value >= 0 ? value : DEFAULT_OWNER_WINDOW_MINUTES;
32766
+ return new Date(now - minutes * 60000).toISOString();
32767
+ }
32224
32768
  async function leadMatch(reachable, matchedText) {
32225
32769
  const lead = reachable.find((agent) => agent.isLead) ?? await getLeadAgent2();
32226
32770
  return { agent: lead, reason: "skill", matchedText };
@@ -32262,7 +32806,7 @@ async function routeChatMessage(text, ctx) {
32262
32806
  }
32263
32807
  console.warn(scrubSecrets(`[chat-sdk] Channel mapping for ${ctx.channelId} names unknown agent ${mapping.agentId}; using the default route`));
32264
32808
  }
32265
- const owner = await getAgentWorkingOnContextKey2(chatSdkContextKey(ctx.threadId), "chat");
32809
+ const owner = await getAgentWorkingOnContextKey2(chatSdkContextKey(ctx.threadId), "chat", ctx.adapter === "telegram" && !ctx.isDirectMessage ? chatOwnerWindowStart() : undefined);
32266
32810
  if (owner && await isAgentReachable(owner)) {
32267
32811
  return {
32268
32812
  kind: "agents",
@@ -32292,6 +32836,9 @@ async function requestChatThreadSteering(args) {
32292
32836
  const task = await getLatestLeadTaskByContextKey2(args.contextKey, "chat");
32293
32837
  if (!task || task.status !== "in_progress")
32294
32838
  return null;
32839
+ const senderUserId = await args.resolveSender();
32840
+ if (senderUserId !== task.requestedByUserId)
32841
+ return null;
32295
32842
  try {
32296
32843
  const result = await requestSteering({
32297
32844
  taskId: task.id,
@@ -32299,7 +32846,8 @@ async function requestChatThreadSteering(args) {
32299
32846
  mode: "queue",
32300
32847
  onUnsupported: "degrade",
32301
32848
  source: "chat",
32302
- createdByKind: "user"
32849
+ createdByKind: "user",
32850
+ createdByUserId: senderUserId
32303
32851
  });
32304
32852
  return { task, result };
32305
32853
  } catch (error) {
@@ -32393,6 +32941,18 @@ registerTemplate({
32393
32941
  ],
32394
32942
  category: "system"
32395
32943
  });
32944
+ registerTemplate({
32945
+ eventType: "chat.message.header",
32946
+ header: "",
32947
+ defaultBody: "[chat] {{chat_facts}}",
32948
+ variables: [
32949
+ {
32950
+ name: "chat_facts",
32951
+ description: "Adapter, chat type and title, forum topic, sender, why the message was taken (addressed) and the replied-to snippet, joined with ' · '"
32952
+ }
32953
+ ],
32954
+ category: "system"
32955
+ });
32396
32956
 
32397
32957
  // src/integrations/chat-sdk/inbound.ts
32398
32958
  var ChatRouteModifySchema = object2({
@@ -32437,10 +32997,24 @@ async function handleChatInbound(thread, message, kind) {
32437
32997
  if (immediate)
32438
32998
  text = text.replace(/^!now\s*/i, "").trim();
32439
32999
  const attachments = message.attachments ?? [];
33000
+ const facts = readChatMessageFacts(thread, message);
33001
+ const isDirectMessage = kind === "dm" || thread.isDM;
33002
+ const mentioned = kind === "mention" || message.isMention === true;
33003
+ let addressed = isDirectMessage ? "dm" : facts.replyToBot ? "reply-to-bot" : mentioned ? "mention" : "none";
33004
+ if (addressed === "none" && (facts.chatType === "group" || facts.chatType === "supergroup")) {
33005
+ const unaddressed = await classifyUnaddressedGroupMessage(thread, message.author.userId, text);
33006
+ if (unaddressed === "chatter") {
33007
+ console.log(`[chat-sdk] ${thread.id}: unaddressed group message from a non-requester, ignored`);
33008
+ return;
33009
+ }
33010
+ if (unaddressed === "requester-follow-up")
33011
+ addressed = unaddressed;
33012
+ }
32440
33013
  if (!immediate && attachments.length === 0 && text && !isChatThreadBuffered(thread.id)) {
32441
33014
  const steering = await requestChatThreadSteering({
32442
33015
  contextKey: chatSdkContextKey(thread.id),
32443
- message: text
33016
+ message: text,
33017
+ resolveSender: () => resolveChatSender(adapter, message.author.userId)
32444
33018
  });
32445
33019
  if (steering) {
32446
33020
  console.log(`[chat-sdk] ${adapter} message steered task ${steering.task.id} (${steering.result.outcome})`);
@@ -32469,8 +33043,10 @@ async function handleChatInbound(thread, message, kind) {
32469
33043
  text,
32470
33044
  userId: message.author.userId,
32471
33045
  userName: message.author.userName || undefined,
32472
- botMentioned: kind === "mention" || message.isMention === true,
32473
- isDirectMessage: kind === "dm" || thread.isDM,
33046
+ botMentioned: mentioned || facts.replyToBot,
33047
+ isDirectMessage,
33048
+ addressed,
33049
+ facts,
32474
33050
  attachments
32475
33051
  });
32476
33052
  if (kind !== "subscribed")
@@ -32479,6 +33055,47 @@ async function handleChatInbound(thread, message, kind) {
32479
33055
  if (immediate)
32480
33056
  await instantFlushChat(thread.id);
32481
33057
  }
33058
+ var REQUESTER_KEY_PREFIX = "swarm:requester:";
33059
+ var REQUESTER_TTL_MS = 30 * 24 * 60 * 60 * 1000;
33060
+ async function rememberChatThreadRequester(threadId, userId) {
33061
+ try {
33062
+ await new SqliteChatState().set(`${REQUESTER_KEY_PREFIX}${threadId}`, userId, REQUESTER_TTL_MS);
33063
+ } catch (error) {
33064
+ console.warn(`[chat-sdk] Could not store the thread requester: ${errorMessage(error)}`);
33065
+ }
33066
+ }
33067
+ async function classifyUnaddressedGroupMessage(thread, senderId, text) {
33068
+ if (hasRoutingToken(text))
33069
+ return "routable";
33070
+ if ((await getChatChannelMapping(thread.adapter.name, thread.channelId))?.agentId) {
33071
+ return "routable";
33072
+ }
33073
+ const owner = await getAgentWorkingOnContextKey2(chatSdkContextKey(thread.id), "chat", chatOwnerWindowStart());
33074
+ if (!owner)
33075
+ return "chatter";
33076
+ const requester = await new SqliteChatState().get(`${REQUESTER_KEY_PREFIX}${thread.id}`);
33077
+ return requester === senderId ? "requester-follow-up" : "chatter";
33078
+ }
33079
+ async function resolveChatRequester(adapter, item) {
33080
+ return resolveChatSender(adapter, item.userId, {
33081
+ sampleEventType: "chat.message",
33082
+ sampleContext: `${item.facts.from}: ${item.text}`
33083
+ });
33084
+ }
33085
+ async function resolveChatSender(adapter, userId, sample) {
33086
+ if (!userId || userId.startsWith("chat:"))
33087
+ return;
33088
+ try {
33089
+ const resolution = await resolveIdentity(adapter, userId);
33090
+ if (resolution.status === "resolved")
33091
+ return resolution.userId;
33092
+ if (sample)
33093
+ await recordUnmappedIdentity(adapter, userId, sample);
33094
+ } catch (error) {
33095
+ console.warn(`[chat-sdk] Could not resolve the requester: ${errorMessage(error)}`);
33096
+ }
33097
+ return;
33098
+ }
32482
33099
  async function getChatThreadContext(thread, exclude, since) {
32483
33100
  try {
32484
33101
  await thread.refresh();
@@ -32549,6 +33166,8 @@ async function flushChatThread(threadId, items, immediate) {
32549
33166
  `);
32550
33167
  const botMentioned = items.some((item) => item.botMentioned);
32551
33168
  const isDirectMessage = items.some((item) => item.isDirectMessage);
33169
+ const requester = items.find((item) => item.addressed !== "none") ?? first;
33170
+ const otherSenders = new Set(items.map((item) => item.userId)).size - 1;
32552
33171
  const resetAt = await getChatThreadResetAt(threadId);
32553
33172
  const previousTask = await getLatestTaskByContextKey2(contextKey);
32554
33173
  const mostRecentTask = previousTask && resetAt && new Date(previousTask.createdAt).getTime() <= resetAt.getTime() ? null : previousTask;
@@ -32561,6 +33180,9 @@ async function flushChatThread(threadId, items, immediate) {
32561
33180
  text: rawText,
32562
33181
  botMentioned,
32563
33182
  isDirectMessage,
33183
+ ...first.facts.chatType ? { chatType: first.facts.chatType } : {},
33184
+ ...first.facts.isForum ? { isForum: true } : {},
33185
+ replyToBot: items.some((item) => item.facts.replyToBot),
32564
33186
  ...mostRecentTask ? { threadContext: { adapter, threadId } } : {}
32565
33187
  }, {
32566
33188
  validateModify: (data) => {
@@ -32611,7 +33233,16 @@ async function flushChatThread(threadId, items, immediate) {
32611
33233
  const body = stripRoutingTokens(rawText);
32612
33234
  const files = items.flatMap((item) => toChatFiles(adapter, item.messageId, item.attachments));
32613
33235
  const inbound = __using(__stack, await fetchChatFiles(files), 1);
32614
- const fileText = buildChatAttachmentText(inbound.files, inbound.failed);
33236
+ const tooLarge = inbound.failed.filter((failure) => failure.tooLarge);
33237
+ if (tooLarge.length > 0) {
33238
+ try {
33239
+ await postChatMessage({ adapter, threadId, text: formatTooLargeReply(tooLarge) });
33240
+ } catch (error) {
33241
+ console.warn(`[chat-sdk] ${threadId}: could not post the too-large reply: ${errorMessage(error)}`);
33242
+ }
33243
+ }
33244
+ const notes = await transcribeChatAudio(inbound.fetched);
33245
+ const fileText = buildChatAttachmentText(inbound.files, inbound.failed, notes);
32615
33246
  const combined = [body, fileText].filter(Boolean).join(`
32616
33247
 
32617
33248
  `);
@@ -32619,9 +33250,17 @@ async function flushChatThread(threadId, items, immediate) {
32619
33250
 
32620
33251
  ${combined}` : combined;
32621
33252
  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}
33253
+ const header = resolveTemplate("chat.message.header", {
33254
+ chat_facts: formatChatHeaderFacts(adapter, otherSenders > 0 ? { ...requester.facts, from: `${requester.facts.from} +${otherSenders} more` } : requester.facts, requester.addressed)
33255
+ }).text;
33256
+ const description = [
33257
+ header,
33258
+ threadContext ? resolveTemplate("chat.message.thread_context", { thread_messages: threadContext }).text : "",
33259
+ marked
33260
+ ].filter(Boolean).join(`
32623
33261
 
32624
- ${marked}` : marked;
33262
+ `);
33263
+ const requestedByUserId = otherSenders > 0 ? undefined : await resolveChatRequester(adapter, requester);
32625
33264
  const latestActive = await getLatestActiveTaskByContextKey2(contextKey, "chat");
32626
33265
  const dependsOn = !immediate && latestActive ? [latestActive.id] : undefined;
32627
33266
  let created = 0;
@@ -32636,7 +33275,9 @@ ${marked}` : marked;
32636
33275
  priority: 70,
32637
33276
  contextKey,
32638
33277
  dependsOn,
33278
+ requestedByUserId,
32639
33279
  parentTaskId: mostRecentTask?.id,
33280
+ inheritParentRequester: false,
32640
33281
  inheritParentOutputSchema: false
32641
33282
  };
32642
33283
  try {
@@ -32652,6 +33293,7 @@ ${marked}` : marked;
32652
33293
  }
32653
33294
  }
32654
33295
  if (created > 0) {
33296
+ await rememberChatThreadRequester(threadId, requester.userId);
32655
33297
  await subscribe(thread);
32656
33298
  startTypingKeepalive(adapter, threadId);
32657
33299
  } else {
@@ -32697,6 +33339,127 @@ init_db3();
32697
33339
  init_context_key();
32698
33340
  init_secret_scrubber();
32699
33341
  init_event_bus();
33342
+
33343
+ // src/integrations/chat-sdk/outbound-files.ts
33344
+ init_db3();
33345
+ init_secret_scrubber();
33346
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
33347
+ async function download(scope, maxBytes, provider = getFileStorageProvider2()) {
33348
+ const response = await provider.download(scope);
33349
+ const length = Number(response.headers.get("content-length"));
33350
+ if (Number.isFinite(length) && length > maxBytes) {
33351
+ await response.body?.cancel();
33352
+ throw new ChatFileTooLargeError(length);
33353
+ }
33354
+ const data = new Uint8Array(await response.arrayBuffer());
33355
+ if (data.byteLength > maxBytes)
33356
+ throw new ChatFileTooLargeError(data.byteLength);
33357
+ return { data, mimeType: response.headers.get("content-type") ?? undefined };
33358
+ }
33359
+ function chatFileOfTaskAttachment(attachment) {
33360
+ if (backingProviderId(attachment) !== getFileStorageProvider2().id)
33361
+ return;
33362
+ return {
33363
+ name: attachment.name,
33364
+ mimeType: attachment.mimeType,
33365
+ sizeBytes: attachment.sizeBytes,
33366
+ load: (maxBytes) => download(scopeFromAttachment(attachment), maxBytes)
33367
+ };
33368
+ }
33369
+ function pathSegments(path) {
33370
+ return normalizeStoredKey(path).split("/").map((segment) => {
33371
+ let decoded = segment;
33372
+ try {
33373
+ decoded = decodeURIComponent(segment);
33374
+ } catch {}
33375
+ if (!decoded || decoded === "." || decoded === ".." || /[/\\\0]/.test(decoded)) {
33376
+ throw new FilesError("Provider", "Path must not contain empty, `.` or `..` segments, or encoded separators");
33377
+ }
33378
+ return decoded;
33379
+ });
33380
+ }
33381
+ async function callerAgentFs(agentId) {
33382
+ if (!agentId)
33383
+ return;
33384
+ const configs = await getResolvedConfig2(agentId);
33385
+ const value = (key) => configs.find((c) => c.key === key)?.value?.trim();
33386
+ const apiUrl = value("AGENT_FS_API_URL") || process.env.AGENT_FS_API_URL?.trim();
33387
+ const apiKey = value("AGENT_FS_API_KEY");
33388
+ const orgId = value("AGENT_FS_DEFAULT_ORG_ID");
33389
+ const driveId = value("AGENT_FS_DEFAULT_DRIVE_ID");
33390
+ return apiUrl && apiKey && orgId && driveId ? { apiUrl, apiKey, orgId, driveId } : undefined;
33391
+ }
33392
+ function chatFileOfPath(path, access) {
33393
+ const segments = pathSegments(path);
33394
+ const name = segments.at(-1);
33395
+ const key = segments.map(encodeURIComponent).join("/");
33396
+ const keyScrubber = createValueScrubber([{ value: access.apiKey, name: "AGENT_FS_API_KEY" }]);
33397
+ return {
33398
+ name,
33399
+ load: async (maxBytes) => {
33400
+ try {
33401
+ return await download({ taskId: "chat", name, key, orgId: access.orgId, driveId: access.driveId }, maxBytes, new AgentFsProvider(access));
33402
+ } catch (error) {
33403
+ if (error instanceof ChatFileTooLargeError)
33404
+ throw error;
33405
+ if (error instanceof FilesError && error.code === "Unauthorized") {
33406
+ throw new Error("your agent-fs credential cannot read this path");
33407
+ }
33408
+ throw new Error(keyScrubber.text(error instanceof Error ? error.message : String(error)));
33409
+ }
33410
+ }
33411
+ };
33412
+ }
33413
+ async function resolveChatAttachmentRefs(refs, taskId, agentId) {
33414
+ let taskAttachments;
33415
+ let access = null;
33416
+ const files = [];
33417
+ for (const ref of refs) {
33418
+ if (UUID_PATTERN.test(ref)) {
33419
+ if (!taskId)
33420
+ return { error: `Attachment ${ref}: no current task to look it up in.` };
33421
+ taskAttachments ??= await getTaskAttachments2(taskId);
33422
+ const attachment = taskAttachments.find((a) => a.id === ref);
33423
+ if (!attachment)
33424
+ return { error: `Attachment ${ref} is not an attachment of task ${taskId}.` };
33425
+ const file = chatFileOfTaskAttachment(attachment);
33426
+ if (!file) {
33427
+ return {
33428
+ 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.`
33429
+ };
33430
+ }
33431
+ files.push(file);
33432
+ continue;
33433
+ }
33434
+ if (access === null)
33435
+ access = await callerAgentFs(agentId);
33436
+ if (!access) {
33437
+ return {
33438
+ 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.`
33439
+ };
33440
+ }
33441
+ try {
33442
+ files.push(chatFileOfPath(ref, access));
33443
+ } catch (error) {
33444
+ return { error: `Path ${ref}: ${errorMessage(error)}` };
33445
+ }
33446
+ }
33447
+ return { files };
33448
+ }
33449
+ var FETCHED_SLACK_FILE_INTENT = "slack-file";
33450
+ async function taskOutputChatFiles(taskId) {
33451
+ return (await getTaskAttachments2(taskId)).flatMap((attachment) => {
33452
+ if (attachment.agentId === null)
33453
+ return [];
33454
+ if (attachment.intent === SHARED_FILE_INTENT || attachment.intent === FETCHED_SLACK_FILE_INTENT) {
33455
+ return [];
33456
+ }
33457
+ const file = chatFileOfTaskAttachment(attachment);
33458
+ return file ? [file] : [];
33459
+ });
33460
+ }
33461
+
33462
+ // src/integrations/chat-sdk/relay.ts
32700
33463
  var RELAY_GIVE_UP_AFTER_MS = 24 * 60 * 60 * 1000;
32701
33464
  var SWEEP_EVERY_N_TICKS = 20;
32702
33465
  var EARLY_TICK_DEBOUNCE_MS = 250;
@@ -32746,7 +33509,8 @@ async function processPendingChatRelays(now = Date.now(), signal) {
32746
33509
  adapter: target.adapter,
32747
33510
  threadId: target.threadId,
32748
33511
  text: formatChatRelayText(task),
32749
- taskId: task.id
33512
+ taskId: task.id,
33513
+ files: await taskOutputChatFiles(task.id)
32750
33514
  });
32751
33515
  stopTypingKeepalive(target.threadId);
32752
33516
  await markChatRelayDelivered2(task.id, now);
@@ -33404,43 +34168,6 @@ Original issue: {{issue_key}} — {{issue_summary}}`,
33404
34168
  // src/jira/sync.ts
33405
34169
  init_db3();
33406
34170
  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
34171
  init_users();
33445
34172
  init_resolver();
33446
34173
  init_context_key();
@@ -33826,7 +34553,7 @@ async function notifySlack(text) {
33826
34553
  return;
33827
34554
  }
33828
34555
  try {
33829
- const { getSlackApp } = await import("./app-rb7vc02s.js");
34556
+ const { getSlackApp } = await import("./app-353vre8g.js");
33830
34557
  const app = getSlackApp();
33831
34558
  if (!app) {
33832
34559
  console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
@@ -33897,7 +34624,7 @@ async function deleteJiraWebhook(webhookId) {
33897
34624
  console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
33898
34625
  }
33899
34626
  async function overwriteWebhookIds(next) {
33900
- const { getDbClient } = await import("./db-xsjg9jqq.js");
34627
+ const { getDbClient } = await import("./db-6sfrn9g3.js");
33901
34628
  await getDbClient().transaction(async (tx) => {
33902
34629
  const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
33903
34630
  if (!row) {
@@ -106997,11 +107724,34 @@ function parseCookieHeader(cookieHeader, name) {
106997
107724
  const match = header.match(re);
106998
107725
  return match ? match[1] : undefined;
106999
107726
  }
107000
- async function extractAndVerifyCookie(req) {
107001
- const token = parseCookieHeader(req.headers.cookie, "page_session");
107002
- if (!token)
107727
+ var LEGACY_PAGE_SESSION_COOKIE = "page_session";
107728
+ var COOKIE_SAFE_PAGE_ID = /^[A-Za-z0-9_-]{1,64}$/;
107729
+ function isCookieSafePageId(pageId) {
107730
+ return COOKIE_SAFE_PAGE_ID.test(pageId);
107731
+ }
107732
+ function pageSessionCookieName(pageId) {
107733
+ return `${LEGACY_PAGE_SESSION_COOKIE}_${pageId}`;
107734
+ }
107735
+ async function verifyNamedCookie(req, name) {
107736
+ const token = parseCookieHeader(req.headers.cookie, name);
107737
+ const payload = await verifyPageSession(token);
107738
+ return payload && token ? { token, payload } : null;
107739
+ }
107740
+ async function extractPageSession(req, pageId) {
107741
+ if (!isCookieSafePageId(pageId))
107003
107742
  return null;
107004
- return verifyPageSession(token);
107743
+ for (const name of [pageSessionCookieName(pageId), LEGACY_PAGE_SESSION_COOKIE]) {
107744
+ const session = await verifyNamedCookie(req, name);
107745
+ if (session?.payload.pageId === pageId)
107746
+ return session;
107747
+ }
107748
+ return null;
107749
+ }
107750
+ async function extractLegacyPageSession(req) {
107751
+ return verifyNamedCookie(req, LEGACY_PAGE_SESSION_COOKIE);
107752
+ }
107753
+ async function extractAndVerifyCookie(req, pageId) {
107754
+ return (await extractPageSession(req, pageId))?.payload ?? null;
107005
107755
  }
107006
107756
  var PAGE_SESSION_TTL_SECONDS = 3600;
107007
107757
  async function issuePageSessionCookie(pageId, opts) {
@@ -107013,13 +107763,11 @@ async function issuePageSessionCookie(pageId, opts) {
107013
107763
  ...opts.name ? { name: opts.name } : {},
107014
107764
  ...opts.op ? { op: true } : {}
107015
107765
  });
107016
- const attrs = [
107017
- `page_session=${token}`,
107018
- "HttpOnly",
107019
- "Path=/",
107020
- `Max-Age=${PAGE_SESSION_TTL_SECONDS}`
107021
- ];
107022
- if (opts.dev) {
107766
+ return buildCookie(pageSessionCookieName(pageId), token, PAGE_SESSION_TTL_SECONDS, opts.dev);
107767
+ }
107768
+ function buildCookie(name, value, maxAge, dev) {
107769
+ const attrs = [`${name}=${value}`, "HttpOnly", "Path=/", `Max-Age=${maxAge}`];
107770
+ if (dev) {
107023
107771
  attrs.push("SameSite=Lax");
107024
107772
  } else {
107025
107773
  attrs.push("SameSite=None");
@@ -107027,6 +107775,30 @@ async function issuePageSessionCookie(pageId, opts) {
107027
107775
  }
107028
107776
  return attrs.join("; ");
107029
107777
  }
107778
+ var MAX_PAGE_SESSION_COOKIES = 20;
107779
+ var PAGE_SESSION_COOKIE_RE = new RegExp(`(?:^|;\\s*)(${LEGACY_PAGE_SESSION_COOKIE}_[A-Za-z0-9_-]{1,64})=([^;]*)`, "g");
107780
+ async function pageSessionSetCookies(req, pageId, opts) {
107781
+ const issued = await issuePageSessionCookie(pageId, opts);
107782
+ const header = Array.isArray(req.headers.cookie) ? req.headers.cookie.join("; ") : req.headers.cookie ?? "";
107783
+ const keep = [];
107784
+ const evict = new Set;
107785
+ const seen = new Set([pageSessionCookieName(pageId)]);
107786
+ for (const [, name, token] of header.matchAll(PAGE_SESSION_COOKIE_RE)) {
107787
+ if (!name || seen.has(name))
107788
+ continue;
107789
+ seen.add(name);
107790
+ const payload = await verifyPageSession(token);
107791
+ if (payload && name === pageSessionCookieName(payload.pageId)) {
107792
+ keep.push({ name, exp: payload.exp, order: keep.length });
107793
+ } else {
107794
+ evict.add(name);
107795
+ }
107796
+ }
107797
+ keep.sort((a, b) => b.exp - a.exp || b.order - a.order);
107798
+ for (const { name } of keep.slice(MAX_PAGE_SESSION_COOKIES - 1))
107799
+ evict.add(name);
107800
+ return [issued, ...[...evict].map((name) => buildCookie(name, "", 0, opts.dev))];
107801
+ }
107030
107802
 
107031
107803
  // src/http/auth.ts
107032
107804
  function extractBearer(req) {
@@ -107247,14 +108019,14 @@ async function reloadGlobalConfigsAndIntegrations() {
107247
108019
  return runWithoutRequestAuth(() => reloadGlobalConfigsAndIntegrationsInner());
107248
108020
  }
107249
108021
  async function reloadGlobalConfigsAndIntegrationsInner() {
107250
- const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-ww2vznkp.js");
108022
+ const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-arytgj5q.js");
107251
108023
  const wasEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
107252
108024
  const updated = await loadGlobalConfigsIntoEnv(true);
107253
108025
  await syncTelemetryEnabled("settings").catch((err) => {
107254
108026
  console.error("[config-reload] telemetry re-init failed (non-fatal):", err);
107255
108027
  });
107256
108028
  await stopSlackApp2();
107257
- const { resetFileStorageProvider } = await import("./registry-rxw10xzg.js");
108029
+ const { resetFileStorageProvider } = await import("./registry-ajhexe44.js");
107258
108030
  resetFileStorageProvider();
107259
108031
  resetEmbeddingProvider();
107260
108032
  const isEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
@@ -107263,10 +108035,10 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
107263
108035
  integrations.push("embeddings");
107264
108036
  }
107265
108037
  if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
107266
- import("./boot-reembed-srp6v6af.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
108038
+ import("./boot-reembed-b9c3az3c.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
107267
108039
  console.error("[config-reload] memory backfill failed (non-fatal):", err);
107268
108040
  });
107269
- import("./boot-reembed-xns7h5h9.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
108041
+ import("./boot-reembed-qdkvxeem.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
107270
108042
  console.error("[config-reload] script backfill failed (non-fatal):", err);
107271
108043
  });
107272
108044
  }
@@ -107678,6 +108450,10 @@ async function handleCore(req, res, myAgentId, apiKey) {
107678
108450
  return false;
107679
108451
  }
107680
108452
 
108453
+ // src/mcp-limits.ts
108454
+ var MCP_MAX_TOOL_INPUT_ELEMENTS = 25000;
108455
+ var MCP_MAX_REQUEST_BODY_BYTES = 4 * 1024 * 1024;
108456
+
107681
108457
  // src/server.ts
107682
108458
  init_resolver();
107683
108459
  init_rbac();
@@ -112726,9 +113502,11 @@ var registerCancelTaskTool = (server) => {
112726
113502
  init_zod();
112727
113503
 
112728
113504
  // src/tools/chat-access.ts
113505
+ init_zod();
112729
113506
  init_db3();
112730
113507
  init_rbac();
112731
113508
  init_context_key();
113509
+ 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
113510
  async function callerChatThread(requestInfo) {
112733
113511
  if (!requestInfo.agentId)
112734
113512
  return null;
@@ -112809,16 +113587,18 @@ var registerChatPostTool = (server) => {
112809
113587
  adapter: _enum2(CHAT_SDK_ADAPTER_NAMES).describe("Chat SDK adapter name."),
112810
113588
  threadId: string2().min(1).optional().describe("Full SDK thread id, such as telegram:12345 or slack:C123:1700000000.000100."),
112811
113589
  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.")
113590
+ text: string2().min(1).max(20000).describe("Markdown text to post."),
113591
+ attachments: chatAttachmentsSchema
112813
113592
  }),
112814
113593
  outputSchema: swarmToolOutputSchema({
112815
113594
  yourAgentId: string2().optional(),
112816
113595
  messageId: string2().optional(),
112817
113596
  adapter: string2().optional(),
112818
113597
  threadId: string2().optional(),
112819
- channelId: string2().optional()
113598
+ channelId: string2().optional(),
113599
+ unsentFiles: array2(looseObject({ name: string2().optional(), reason: string2().optional() })).optional()
112820
113600
  })
112821
- }, async ({ adapter, threadId, channelId, text }, requestInfo) => {
113601
+ }, async ({ adapter, threadId, channelId, text, attachments }, requestInfo) => {
112822
113602
  const data = { yourAgentId: requestInfo.agentId };
112823
113603
  const target = threadId ?? channelId;
112824
113604
  if (!target)
@@ -112829,20 +113609,25 @@ var registerChatPostTool = (server) => {
112829
113609
  if (!await canUseChatVerb(requestInfo, "integration.chat.post")) {
112830
113610
  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
113611
  }
113612
+ const resolved = await resolveChatAttachmentRefs(attachments ?? [], requestInfo.sourceTaskId, requestInfo.agentId);
113613
+ if ("error" in resolved)
113614
+ return toolErr(resolved.error, { data });
112832
113615
  try {
112833
113616
  const sent = await postChatMessage({
112834
113617
  adapter,
112835
113618
  ...threadId ? { threadId } : { channelId },
112836
113619
  text,
112837
- taskId: requestInfo.sourceTaskId
113620
+ taskId: requestInfo.sourceTaskId,
113621
+ files: resolved.files
112838
113622
  });
112839
- return toolOk(`Posted to ${adapter} ${threadId ? "thread" : "channel"} ${target}.`, {
113623
+ return toolOk(`Posted to ${adapter} ${threadId ? "thread" : "channel"} ${target}.${unsentFilesSummary(sent.unsentFiles)}`, {
112840
113624
  data: {
112841
113625
  ...data,
112842
113626
  messageId: sent.messageIds.at(-1),
112843
113627
  adapter: sent.adapter,
112844
113628
  threadId: sent.threadId,
112845
- channelId: sent.channelId
113629
+ channelId: sent.channelId,
113630
+ unsentFiles: sent.unsentFiles
112846
113631
  }
112847
113632
  });
112848
113633
  } catch (error) {
@@ -112923,18 +113708,20 @@ init_context_key();
112923
113708
  var registerChatReplyTool = (server) => {
112924
113709
  createToolRegistrar(server)("chat-reply", {
112925
113710
  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.",
113711
+ 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
113712
  annotations: { openWorldHint: true },
112928
113713
  inputSchema: object2({
112929
- text: string2().min(1).max(20000).describe("Markdown text to post to the thread.")
113714
+ text: string2().min(1).max(20000).describe("Markdown text to post to the thread."),
113715
+ attachments: chatAttachmentsSchema
112930
113716
  }),
112931
113717
  outputSchema: swarmToolOutputSchema({
112932
113718
  yourAgentId: string2().optional(),
112933
113719
  messageId: string2().optional(),
112934
113720
  adapter: string2().optional(),
112935
- threadId: string2().optional()
113721
+ threadId: string2().optional(),
113722
+ unsentFiles: array2(looseObject({ name: string2().optional(), reason: string2().optional() })).optional()
112936
113723
  })
112937
- }, async ({ text }, requestInfo) => {
113724
+ }, async ({ text, attachments }, requestInfo) => {
112938
113725
  if (!requestInfo.agentId)
112939
113726
  return toolErr("Agent ID not found.");
112940
113727
  const data = { yourAgentId: requestInfo.agentId };
@@ -112948,19 +113735,24 @@ var registerChatReplyTool = (server) => {
112948
113735
  if (!thread) {
112949
113736
  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
113737
  }
113738
+ const resolved = await resolveChatAttachmentRefs(attachments ?? [], task.id, requestInfo.agentId);
113739
+ if ("error" in resolved)
113740
+ return toolErr(resolved.error, { data });
112951
113741
  try {
112952
113742
  const sent = await postChatMessage({
112953
113743
  adapter: thread.adapter,
112954
113744
  threadId: thread.threadId,
112955
113745
  text,
112956
- taskId: task.id
113746
+ taskId: task.id,
113747
+ files: resolved.files
112957
113748
  });
112958
- return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}.`, {
113749
+ return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}.${unsentFilesSummary(sent.unsentFiles)}`, {
112959
113750
  data: {
112960
113751
  ...data,
112961
113752
  messageId: sent.messageIds.at(-1),
112962
113753
  adapter: sent.adapter,
112963
- threadId: sent.threadId
113754
+ threadId: sent.threadId,
113755
+ unsentFiles: sent.unsentFiles
112964
113756
  }
112965
113757
  });
112966
113758
  } catch (error) {
@@ -114448,8 +115240,523 @@ init_db3();
114448
115240
 
114449
115241
  // src/tasks/task-terminal-effects.ts
114450
115242
  init_db3();
115243
+
115244
+ // src/be/chunking.ts
115245
+ var MAX_CHUNK_SIZE = 2000;
115246
+ var CHUNK_OVERLAP = 100;
115247
+ var MIN_CHUNK_SIZE = 50;
115248
+ function chunkContent(text) {
115249
+ const trimmed = text.trim();
115250
+ if (!trimmed || trimmed.length < MIN_CHUNK_SIZE) {
115251
+ return [];
115252
+ }
115253
+ if (trimmed.length <= MAX_CHUNK_SIZE) {
115254
+ return [{ content: trimmed, chunkIndex: 0, totalChunks: 1, headings: [] }];
115255
+ }
115256
+ const sections = splitByHeaders(trimmed);
115257
+ const rawChunks = [];
115258
+ for (const section of sections) {
115259
+ if (section.content.length <= MAX_CHUNK_SIZE) {
115260
+ rawChunks.push(section);
115261
+ } else {
115262
+ const subChunks = recursiveSplit(section.content);
115263
+ for (const sub of subChunks) {
115264
+ rawChunks.push({ content: sub, headings: section.headings });
115265
+ }
115266
+ }
115267
+ }
115268
+ const packed = packSmallSections(rawChunks);
115269
+ return packed.map((c, i) => ({
115270
+ content: c.content,
115271
+ chunkIndex: i,
115272
+ totalChunks: packed.length,
115273
+ headings: c.headings
115274
+ }));
115275
+ }
115276
+ function renderSection(section) {
115277
+ return section.headings.length > 0 ? `${section.headings.join(" > ")}
115278
+
115279
+ ${section.content}` : section.content;
115280
+ }
115281
+ function packSmallSections(sections) {
115282
+ const out = [];
115283
+ let pending = null;
115284
+ const flush = () => {
115285
+ if (pending)
115286
+ out.push({ content: pending.parts.join(`
115287
+
115288
+ `), headings: pending.headings });
115289
+ pending = null;
115290
+ };
115291
+ for (const section of sections) {
115292
+ const rendered = renderSection(section);
115293
+ if (section.content.trim().length >= MIN_CHUNK_SIZE) {
115294
+ flush();
115295
+ out.push({ content: rendered, headings: section.headings });
115296
+ continue;
115297
+ }
115298
+ if (pending && pending.length + 2 + rendered.length > MAX_CHUNK_SIZE)
115299
+ flush();
115300
+ if (pending) {
115301
+ pending.parts.push(rendered);
115302
+ pending.length += 2 + rendered.length;
115303
+ } else {
115304
+ pending = { parts: [rendered], length: rendered.length, headings: section.headings };
115305
+ }
115306
+ }
115307
+ flush();
115308
+ return out;
115309
+ }
115310
+ function splitByHeaders(text) {
115311
+ const lines = text.split(`
115312
+ `);
115313
+ const sections = [];
115314
+ let currentContent = [];
115315
+ const headingStack = [];
115316
+ for (const line of lines) {
115317
+ const headingMatch = line.match(/^(#{1,3})\s+(.+)$/);
115318
+ if (headingMatch) {
115319
+ if (currentContent.length > 0) {
115320
+ const content = currentContent.join(`
115321
+ `).trim();
115322
+ if (content) {
115323
+ sections.push({ content, headings: [...headingStack] });
115324
+ }
115325
+ currentContent = [];
115326
+ }
115327
+ const level = headingMatch[1].length;
115328
+ const title = headingMatch[2].trim();
115329
+ while (headingStack.length >= level) {
115330
+ headingStack.pop();
115331
+ }
115332
+ headingStack.push(`${"#".repeat(level)} ${title}`);
115333
+ } else {
115334
+ currentContent.push(line);
115335
+ }
115336
+ }
115337
+ if (currentContent.length > 0) {
115338
+ const content = currentContent.join(`
115339
+ `).trim();
115340
+ if (content) {
115341
+ sections.push({ content, headings: [...headingStack] });
115342
+ }
115343
+ }
115344
+ if (sections.length === 0) {
115345
+ return [{ content: text, headings: [] }];
115346
+ }
115347
+ return sections;
115348
+ }
115349
+ var SEPARATORS = [`
115350
+
115351
+ `, `
115352
+ `, ". ", " "];
115353
+ function recursiveSplit(text) {
115354
+ return recursiveSplitWithSeparators(text, 0);
115355
+ }
115356
+ function recursiveSplitWithSeparators(text, separatorIndex) {
115357
+ if (text.length <= MAX_CHUNK_SIZE) {
115358
+ return [text.trim()].filter((s) => s.length > 0);
115359
+ }
115360
+ if (separatorIndex >= SEPARATORS.length) {
115361
+ return hardSplit(text);
115362
+ }
115363
+ const separator = SEPARATORS[separatorIndex];
115364
+ const parts = text.split(separator);
115365
+ if (parts.length <= 1) {
115366
+ return recursiveSplitWithSeparators(text, separatorIndex + 1);
115367
+ }
115368
+ const chunks = [];
115369
+ let current = "";
115370
+ for (const part of parts) {
115371
+ const candidate = current ? current + separator + part : part;
115372
+ if (candidate.length <= MAX_CHUNK_SIZE) {
115373
+ current = candidate;
115374
+ } else {
115375
+ if (current) {
115376
+ chunks.push(current.trim());
115377
+ }
115378
+ if (part.length > MAX_CHUNK_SIZE) {
115379
+ chunks.push(...recursiveSplitWithSeparators(part, separatorIndex + 1));
115380
+ current = "";
115381
+ } else {
115382
+ current = part;
115383
+ }
115384
+ }
115385
+ }
115386
+ if (current.trim()) {
115387
+ chunks.push(current.trim());
115388
+ }
115389
+ return addOverlap(chunks, text);
115390
+ }
115391
+ function hardSplit(text) {
115392
+ const chunks = [];
115393
+ let start = 0;
115394
+ while (start < text.length) {
115395
+ const end = Math.min(start + MAX_CHUNK_SIZE, text.length);
115396
+ chunks.push(text.slice(start, end).trim());
115397
+ if (end === text.length)
115398
+ break;
115399
+ start = end - CHUNK_OVERLAP;
115400
+ }
115401
+ return chunks.filter((c) => c.length > 0);
115402
+ }
115403
+ function addOverlap(chunks, _originalText) {
115404
+ if (chunks.length <= 1)
115405
+ return chunks;
115406
+ const result = [chunks[0]];
115407
+ for (let i = 1;i < chunks.length; i++) {
115408
+ const prevChunk = chunks[i - 1];
115409
+ const chunk = chunks[i];
115410
+ const overlapText = prevChunk.slice(-CHUNK_OVERLAP);
115411
+ if (overlapText.length + chunk.length <= MAX_CHUNK_SIZE + CHUNK_OVERLAP) {
115412
+ result.push(overlapText + chunk);
115413
+ } else {
115414
+ result.push(chunk);
115415
+ }
115416
+ }
115417
+ return result;
115418
+ }
115419
+
115420
+ // src/be/memory/index-content.ts
114451
115421
  init_memory();
114452
115422
 
115423
+ // src/be/memory/key-guard.ts
115424
+ init_rbac();
115425
+ init_key_paths();
115426
+
115427
+ class MemoryKeyError extends Error {
115428
+ reason;
115429
+ constructor(message, reason) {
115430
+ super(message);
115431
+ this.reason = reason;
115432
+ this.name = "MemoryKeyError";
115433
+ }
115434
+ }
115435
+ var NO_AUTHORITY = {
115436
+ principal: { kind: "agent", agentId: "", isLead: false },
115437
+ source: "http"
115438
+ };
115439
+ function shapeError(key, origin) {
115440
+ if (key.length <= MEMORY_KEY_MAX_LENGTH && MEMORY_KEY_PATTERN.test(key))
115441
+ return null;
115442
+ 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.`;
115443
+ return `${subject} ${MEMORY_KEY_PATTERN_MESSAGE}`;
115444
+ }
115445
+ function assertKeyWritable(key, origin, writer) {
115446
+ if (origin === "sourcePath" && !isLongtermKey(key))
115447
+ return;
115448
+ const shape = shapeError(key, origin);
115449
+ if (shape)
115450
+ throw new MemoryKeyError(shape, "invalid");
115451
+ const pathError = longtermKeyError(key);
115452
+ if (pathError)
115453
+ throw new MemoryKeyError(pathError, "invalid");
115454
+ if (!isConsolidatedKey(key))
115455
+ return;
115456
+ const { principal, source } = writer ?? NO_AUTHORITY;
115457
+ const decision = can({
115458
+ principal,
115459
+ verb: "memory.write.consolidated",
115460
+ resource: { kind: "none" },
115461
+ source
115462
+ });
115463
+ if (!decision.allow)
115464
+ throw new MemoryKeyError(consolidatedKeyMessage(key), "forbidden");
115465
+ }
115466
+
115467
+ // src/be/memory/link-resolver.ts
115468
+ init_db3();
115469
+ init_constants2();
115470
+ var WIKILINK_RE = /\[\[([^\]]+)\]\]/g;
115471
+ var PR_HASH_RE = /(?:^|[\s(])#(\d{1,5})(?=[\s,.)!?]|$)/gm;
115472
+ var PR_PREFIX_RE = /\bPR\s*#(\d{1,5})\b/gi;
115473
+ var GITHUB_PR_URL_RE = /https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+)\/pull\/(\d+)/g;
115474
+ var AGENT_FS_LIVE_HOSTS = String.raw`agent-fs|live\.agent-fs\.dev`;
115475
+ var AGENT_FS_FILE_ROUTE = String.raw`\/file\/~\/([a-f0-9-]+)\/([a-f0-9-]+)\/([\w/.%-]+)`;
115476
+ var AGENT_UI_PAGE_RE = /(?:app\.[^/]+|localhost:\d+)\/pages\/([a-f0-9-]+)/g;
115477
+ var AGENT_UI_TASK_RE = /(?:app\.[^/]+|localhost:\d+)\/tasks\/([a-f0-9-]+)/g;
115478
+ var wikilinkMatcher = (content) => {
115479
+ const results = [];
115480
+ for (const match of content.matchAll(WIKILINK_RE)) {
115481
+ const name = match[1].trim();
115482
+ if (!name)
115483
+ continue;
115484
+ results.push({
115485
+ linkType: "wikilink",
115486
+ targetKind: "memory",
115487
+ targetId: name,
115488
+ sourceText: match[0],
115489
+ resolver: "wikilink"
115490
+ });
115491
+ }
115492
+ return results;
115493
+ };
115494
+ var prMatcher = (content) => {
115495
+ const results = [];
115496
+ const seen = new Set;
115497
+ for (const match of content.matchAll(GITHUB_PR_URL_RE)) {
115498
+ const id = `github:${match[1]}/${match[2]}#${match[3]}`;
115499
+ if (seen.has(id))
115500
+ continue;
115501
+ seen.add(id);
115502
+ results.push({
115503
+ linkType: "pr",
115504
+ targetKind: "pr",
115505
+ targetId: id,
115506
+ sourceText: match[0],
115507
+ resolver: "pr-url",
115508
+ metadata: { owner: match[1], repo: match[2], number: Number(match[3]) }
115509
+ });
115510
+ }
115511
+ for (const match of content.matchAll(PR_PREFIX_RE)) {
115512
+ const id = `pr:${match[1]}`;
115513
+ if (seen.has(id))
115514
+ continue;
115515
+ seen.add(id);
115516
+ results.push({
115517
+ linkType: "pr",
115518
+ targetKind: "pr",
115519
+ targetId: id,
115520
+ sourceText: match[0].trim(),
115521
+ resolver: "pr-prefix",
115522
+ metadata: { number: Number(match[1]) }
115523
+ });
115524
+ }
115525
+ for (const match of content.matchAll(PR_HASH_RE)) {
115526
+ const id = `pr:${match[1]}`;
115527
+ if (seen.has(id))
115528
+ continue;
115529
+ seen.add(id);
115530
+ results.push({
115531
+ linkType: "pr",
115532
+ targetKind: "pr",
115533
+ targetId: id,
115534
+ sourceText: `#${match[1]}`,
115535
+ resolver: "pr-hash",
115536
+ metadata: { number: Number(match[1]) }
115537
+ });
115538
+ }
115539
+ return results;
115540
+ };
115541
+ function escapeRegExp2(value) {
115542
+ return value.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
115543
+ }
115544
+ function agentFsPathRegex() {
115545
+ const appHosts = getConfiguredAppUrls().flatMap((value) => {
115546
+ try {
115547
+ const url = new URL(value);
115548
+ return [escapeRegExp2(`${url.host}${url.pathname.replace(/\/+$/, "")}`)];
115549
+ } catch {
115550
+ return [];
115551
+ }
115552
+ });
115553
+ const hosts = [AGENT_FS_LIVE_HOSTS, ...appHosts, String.raw`localhost:\d+`].join("|");
115554
+ return new RegExp(`(?<![\\w.-])(?:${hosts})${AGENT_FS_FILE_ROUTE}`, "gi");
115555
+ }
115556
+ var agentFsMatcher = (content) => {
115557
+ const results = [];
115558
+ for (const match of content.matchAll(agentFsPathRegex())) {
115559
+ const orgId = match[1];
115560
+ const driveId = match[2];
115561
+ const path = match[3];
115562
+ results.push({
115563
+ linkType: "agent-fs-file",
115564
+ targetKind: "agent-fs-file",
115565
+ targetId: `${orgId}/${driveId}/${path}`,
115566
+ sourceText: match[0],
115567
+ resolver: "agent-fs-path",
115568
+ metadata: { orgId, driveId, path }
115569
+ });
115570
+ }
115571
+ return results;
115572
+ };
115573
+ var agentUiMatcher = (content) => {
115574
+ const results = [];
115575
+ for (const match of content.matchAll(AGENT_UI_PAGE_RE)) {
115576
+ results.push({
115577
+ linkType: "agent-ui",
115578
+ targetKind: "agent-ui",
115579
+ targetId: `page:${match[1]}`,
115580
+ sourceText: match[0],
115581
+ resolver: "agent-ui-page"
115582
+ });
115583
+ }
115584
+ for (const match of content.matchAll(AGENT_UI_TASK_RE)) {
115585
+ results.push({
115586
+ linkType: "agent-ui",
115587
+ targetKind: "agent-ui",
115588
+ targetId: `task:${match[1]}`,
115589
+ sourceText: match[0],
115590
+ resolver: "agent-ui-task"
115591
+ });
115592
+ }
115593
+ return results;
115594
+ };
115595
+ var MATCHERS = [wikilinkMatcher, prMatcher, agentFsMatcher, agentUiMatcher];
115596
+ function resolveLinks(content) {
115597
+ const results = [];
115598
+ for (const matcher of MATCHERS) {
115599
+ for (const link of matcher(content)) {
115600
+ results.push({ ...link, strength: 1 });
115601
+ }
115602
+ }
115603
+ return results;
115604
+ }
115605
+ async function resolveWikilinksToMemoryIds(agentId, links) {
115606
+ const db = getDbClient2();
115607
+ const resolved = [];
115608
+ for (const link of links) {
115609
+ if (link.linkType !== "wikilink") {
115610
+ resolved.push(link);
115611
+ continue;
115612
+ }
115613
+ const row = await db.get("SELECT id FROM agent_memory WHERE name = ? AND (agentId = ? OR scope = 'swarm') LIMIT 1", [link.targetId, agentId]);
115614
+ resolved.push(row ? { ...link, targetId: row.id } : link);
115615
+ }
115616
+ return resolved;
115617
+ }
115618
+ var INSERT_LINK_SQL = `INSERT OR IGNORE INTO memory_link
115619
+ (id, from_memory_id, linkType, targetKind, targetId, strength, resolver, sourceText, metadata, createdAt, updatedAt)
115620
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
115621
+ function insertLinkArgs(memoryId, link, now) {
115622
+ return [
115623
+ crypto.randomUUID(),
115624
+ memoryId,
115625
+ link.linkType,
115626
+ link.targetKind,
115627
+ link.targetId,
115628
+ link.strength,
115629
+ link.resolver,
115630
+ link.sourceText,
115631
+ link.metadata ? JSON.stringify(link.metadata) : null,
115632
+ now,
115633
+ now
115634
+ ];
115635
+ }
115636
+ async function storeLinks(memoryId, agentId, content) {
115637
+ const links = resolveLinks(content);
115638
+ if (links.length === 0)
115639
+ return;
115640
+ const resolved = await resolveWikilinksToMemoryIds(agentId, links);
115641
+ const now = new Date().toISOString();
115642
+ await getDbClient2().transaction(async (tx) => {
115643
+ for (const link of resolved) {
115644
+ await tx.run(INSERT_LINK_SQL, insertLinkArgs(memoryId, link, now));
115645
+ }
115646
+ });
115647
+ }
115648
+ function linkIdentity2(link) {
115649
+ return JSON.stringify([link.linkType, link.targetKind, link.targetId, link.sourceText ?? null]);
115650
+ }
115651
+ async function refreshLinks(memoryId, agentId, content) {
115652
+ const resolved = await resolveWikilinksToMemoryIds(agentId, resolveLinks(content));
115653
+ const nextIdentities = new Set(resolved.map((link) => linkIdentity2(link)));
115654
+ const now = new Date().toISOString();
115655
+ await getDbClient2().transaction(async (tx) => {
115656
+ const existing = await tx.query(`SELECT id, linkType, targetKind, targetId, sourceText
115657
+ FROM memory_link
115658
+ WHERE from_memory_id = ? AND linkType != 'sequel'`, [memoryId]);
115659
+ for (const row of existing) {
115660
+ if (!nextIdentities.has(linkIdentity2(row))) {
115661
+ await tx.run("DELETE FROM memory_link WHERE id = ?", [row.id]);
115662
+ }
115663
+ }
115664
+ for (const link of resolved) {
115665
+ await tx.run(INSERT_LINK_SQL, insertLinkArgs(memoryId, link, now));
115666
+ }
115667
+ });
115668
+ }
115669
+
115670
+ // src/be/memory/index-content.ts
115671
+ init_secret_scrubber();
115672
+ function taskCompletionMemoryKey(taskId) {
115673
+ return `/task-completions/${taskId.toLowerCase().replace(/[^a-z0-9._-]/g, "-")}`;
115674
+ }
115675
+ async function indexMemoryContent(params) {
115676
+ const { agentId, content, name, scope, source, sourceTaskId, sourcePath, tags } = params;
115677
+ const rowKey = params.key ?? (sourcePath || null);
115678
+ if (rowKey)
115679
+ assertKeyWritable(rowKey, params.key != null ? "key" : "sourcePath", params.writer);
115680
+ const contentChunks = chunkContent(content);
115681
+ if (contentChunks.length === 0) {
115682
+ contentChunks.push({
115683
+ content: content.trim(),
115684
+ chunkIndex: 0,
115685
+ totalChunks: 1,
115686
+ headings: []
115687
+ });
115688
+ }
115689
+ const store = getMemoryStore2();
115690
+ const provider = getEmbeddingProvider2();
115691
+ if (sourcePath && agentId && contentChunks.length === 1) {
115692
+ const existing = (await store.list(agentId, {
115693
+ scope,
115694
+ limit: 2,
115695
+ ownerAgentId: agentId,
115696
+ sourcePath
115697
+ })).filter((memory) => memory.sourcePath === sourcePath);
115698
+ if (existing.length === 1 && existing[0]?.totalChunks === 1) {
115699
+ const result = await store.edit({
115700
+ id: existing[0].id,
115701
+ mode: "replace",
115702
+ content: contentChunks[0].content,
115703
+ intent: "re-index memory source path",
115704
+ changedByAgentId: agentId
115705
+ });
115706
+ const embedding = await provider.embed(result.memory.content);
115707
+ if (embedding)
115708
+ await store.updateEmbedding(result.memory.id, embedding, provider.name);
115709
+ try {
115710
+ await refreshLinks(result.memory.id, agentId, result.memory.content);
115711
+ } catch (err) {
115712
+ console.error(`[memory] Link resolution failed for ${result.memory.id}:`, err.message);
115713
+ }
115714
+ return { queued: false, memoryIds: [result.memory.id], edited: result.changed, chunks: 1 };
115715
+ }
115716
+ }
115717
+ if (sourcePath && agentId) {
115718
+ await store.deleteBySourcePath(sourcePath, agentId);
115719
+ }
115720
+ const inputs = contentChunks.map((chunk) => ({
115721
+ agentId: agentId || null,
115722
+ content: chunk.content,
115723
+ name,
115724
+ scope,
115725
+ source,
115726
+ sourcePath: sourcePath || null,
115727
+ sourceTaskId: sourceTaskId || null,
115728
+ chunkIndex: chunk.chunkIndex,
115729
+ totalChunks: chunk.totalChunks,
115730
+ tags: tags || [],
115731
+ contextKey: params.contextKey ?? null,
115732
+ intent: params.intent ?? "index memory content",
115733
+ key: rowKey
115734
+ }));
115735
+ const memories = params.replaceExisting && params.key ? await store.replaceDocument({ key: params.key, scope, agentId: agentId || null, source }, inputs) : await store.storeBatch(inputs);
115736
+ if (agentId) {
115737
+ for (const memory of memories) {
115738
+ try {
115739
+ await storeLinks(memory.id, agentId, memory.content);
115740
+ } catch (err) {
115741
+ console.error(`[memory] Link resolution failed for ${memory.id}:`, err.message);
115742
+ }
115743
+ }
115744
+ }
115745
+ (async () => {
115746
+ try {
115747
+ const embeddings = await provider.embedBatch(memories.map((m) => m.content));
115748
+ for (let i = 0;i < embeddings.length; i++) {
115749
+ if (embeddings[i]) {
115750
+ await store.updateEmbedding(memories[i].id, embeddings[i], provider.name);
115751
+ }
115752
+ }
115753
+ } catch (err) {
115754
+ console.error("[memory] Batch embedding failed:", err.message);
115755
+ }
115756
+ })().catch((err) => console.error("[memory] batch embed failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
115757
+ return { queued: true, memoryIds: memories.map((m) => m.id), chunks: contentChunks.length };
115758
+ }
115759
+
114453
115760
  // src/be/memory/raters/retrieval.ts
114454
115761
  init_db3();
114455
115762
  function dedupeMemoryDocumentIds(memories) {
@@ -115205,40 +116512,39 @@ ${safeFailureReason || "No reason provided"}
115205
116512
  This task failed. Learn from this to avoid repeating the mistake.`;
115206
116513
  if (taskContent.length < 30)
115207
116514
  return;
115208
- const store = getMemoryStore2();
115209
- const provider = getEmbeddingProvider2();
115210
- const memory = await store.store({
116515
+ const key = taskCompletionMemoryKey(taskId);
116516
+ await indexMemoryContent({
115211
116517
  agentId: agentId ?? null,
115212
116518
  content: taskContent,
115213
116519
  name: `Task: ${safeTask.slice(0, 80)}`,
115214
116520
  scope: "agent",
115215
116521
  source: "task_completion",
115216
- sourceTaskId: taskId
116522
+ sourceTaskId: taskId,
116523
+ key,
116524
+ intent: "task completion memory",
116525
+ replaceExisting: true
115217
116526
  });
115218
- const embedding = await provider.embed(taskContent);
115219
- if (embedding) {
115220
- await store.updateEmbedding(memory.id, embedding, provider.name);
115221
- }
115222
116527
  const shouldShareWithSwarm = status === "completed" && (task.taskType === "research" || task.tags?.includes("knowledge") || task.tags?.includes("shared"));
115223
116528
  if (shouldShareWithSwarm) {
115224
116529
  try {
115225
- const swarmMemory = await store.store({
116530
+ await indexMemoryContent({
115226
116531
  agentId: agentId ?? null,
115227
- scope: "swarm",
115228
- name: `Shared: ${safeTask.slice(0, 80)}`,
115229
116532
  content: `Task completed by agent ${agentId}:
115230
116533
 
115231
116534
  ${taskContent}`,
116535
+ name: `Shared: ${safeTask.slice(0, 80)}`,
116536
+ scope: "swarm",
115232
116537
  source: "task_completion",
115233
- sourceTaskId: taskId
116538
+ sourceTaskId: taskId,
116539
+ key,
116540
+ intent: "task completion memory",
116541
+ replaceExisting: true
115234
116542
  });
115235
- const swarmEmbedding = await provider.embed(taskContent);
115236
- if (swarmEmbedding) {
115237
- await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
115238
- }
115239
116543
  } catch {}
115240
116544
  }
115241
- } catch {}
116545
+ } catch (err) {
116546
+ console.error("[task-terminal-effects] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err)));
116547
+ }
115242
116548
  })().catch((err) => console.error("[task-terminal-effects] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
115243
116549
  }
115244
116550
  (async () => {
@@ -117929,258 +119235,7 @@ var registerMemoryDeleteTool = (server) => {
117929
119235
  init_zod();
117930
119236
  init_db3();
117931
119237
  init_memory();
117932
-
117933
- // src/be/memory/key-guard.ts
117934
- init_rbac();
117935
119238
  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
119239
  init_rbac();
118185
119240
  init_types();
118186
119241
  var agentMemoryOutputSchema = looseObject({
@@ -118744,6 +119799,7 @@ async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
118744
119799
  // src/tools/memory-search.ts
118745
119800
  init_key_paths();
118746
119801
  init_reranker();
119802
+ init_search_candidates();
118747
119803
  init_types();
118748
119804
  var NUDGE_ELIGIBLE_SOURCES2 = new Set(["manual", "file_index"]);
118749
119805
  function rateHintFor(memoryId) {
@@ -118799,7 +119855,7 @@ var registerMemorySearchTool = (server) => {
118799
119855
  const store = getMemoryStore2();
118800
119856
  const queryEmbedding = await provider.embed(query);
118801
119857
  const candidateLimit = limit * CANDIDATE_SET_MULTIPLIER;
118802
- const candidates = await store.search(queryEmbedding ?? new Float32Array(0), requestInfo.agentId, {
119858
+ const candidates = await searchMemoryCandidates(store, queryEmbedding ?? new Float32Array(0), requestInfo.agentId, {
118803
119859
  scope,
118804
119860
  limit: candidateLimit,
118805
119861
  source,
@@ -118887,242 +119943,6 @@ var registerMemorySearchTool = (server) => {
118887
119943
  // src/tools/memory-store.ts
118888
119944
  init_zod();
118889
119945
  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
119946
  init_key_paths();
119127
119947
  init_types();
119128
119948
  var registerMemoryStoreTool = (server) => {
@@ -131658,33 +132478,35 @@ function formatFileSize2(bytes) {
131658
132478
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
131659
132479
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
131660
132480
  }
131661
- function buildAttachmentText(files, failed = []) {
132481
+ function buildAttachmentText(files, failed = [], notes = new Map) {
131662
132482
  const reasons = new Map(failed.map((f) => [f.file.id, f.reason]));
131663
132483
  return files.map((f) => {
131664
132484
  const size = typeof f.size === "number" ? formatFileSize2(f.size) : "unknown size";
131665
132485
  const line = `[File: ${f.name ?? f.id} (${f.mimetype ?? "unknown type"}, ${size}) id=${f.id}]`;
131666
132486
  const reason = reasons.get(f.id);
131667
- return reason ? `${line} (not attached: ${reason})` : line;
132487
+ const note = notes.get(f.id);
132488
+ return [reason ? `${line} (not attached: ${reason})` : line, note].filter(Boolean).join(`
132489
+ `);
131668
132490
  }).join(`
131669
132491
  `);
131670
132492
  }
131671
- function buildEffectiveText(text, files, failed) {
132493
+ function buildEffectiveText(text, files, failed, notes) {
131672
132494
  const hasText = !!text?.trim();
131673
132495
  const hasFiles = files && files.length > 0;
131674
132496
  if (hasText && hasFiles) {
131675
132497
  return `${text}
131676
132498
 
131677
- ${buildAttachmentText(files, failed)}`;
132499
+ ${buildAttachmentText(files, failed, notes)}`;
131678
132500
  }
131679
132501
  if (hasFiles) {
131680
- return buildAttachmentText(files, failed);
132502
+ return buildAttachmentText(files, failed, notes);
131681
132503
  }
131682
132504
  return text || "";
131683
132505
  }
131684
132506
  function bufferedFileFailures(files) {
131685
132507
  return (files ?? []).map((file) => ({ file, reason: BUFFERED_REASON }));
131686
132508
  }
131687
- async function fetchSlackFiles(client, files) {
132509
+ async function fetchSlackFiles(client, files, options = {}) {
131688
132510
  let dir;
131689
132511
  const result = {
131690
132512
  files: [],
@@ -131710,8 +132532,19 @@ async function fetchSlackFiles(client, files) {
131710
132532
  result.fetched.push({ file, ...outcome });
131711
132533
  }
131712
132534
  }
132535
+ if (options.transcribe) {
132536
+ result.notes = await transcribeAudioNotes(result.fetched.filter(({ file }) => isSlackAudio(file)).map(({ file, path }) => ({
132537
+ key: file.id,
132538
+ name: file.name ?? file.id,
132539
+ data: Bun.file(path),
132540
+ mimeType: file.mimetype
132541
+ })), "[Slack]");
132542
+ }
131713
132543
  return result;
131714
132544
  }
132545
+ function isSlackAudio(file) {
132546
+ return file.subtype === "slack_audio" || Boolean(file.mimetype?.startsWith("audio/"));
132547
+ }
131715
132548
  function looksLikeSignIn(head) {
131716
132549
  const joined = new Uint8Array(head.reduce((total, part) => total + part.byteLength, 0));
131717
132550
  let offset = 0;
@@ -133925,9 +134758,9 @@ var registerSystemOneDecideTool = (server) => {
133925
134758
  createToolRegistrar(server)("system-one-decide", {
133926
134759
  title: "Ask a SystemOne decision model",
133927
134760
  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.",
134761
+ 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
134762
  inputSchema: object2({
133930
- provider: _enum2(SYSTEM_ONE_PROVIDER_IDS).optional().describe("Decision host (default typesafe)"),
134763
+ provider: _enum2(SYSTEM_ONE_PROVIDER_IDS).optional().describe("Decision host (default: the SYSTEM_ONE_DEFAULT_PROVIDER global config, typesafe when unset)"),
133931
134764
  model: string2().min(1).optional().describe("Provider model id (default: the provider's)"),
133932
134765
  state: union2([string2(), array2(string2()), record2(string2(), unknown())]).describe("The state to decide on"),
133933
134766
  questions: record2(string2(), record2(string2(), unknown())).describe("Questions by id, each `{ type: 'noul' | 'choice' | 'score', instructions, criteria }`"),
@@ -133938,7 +134771,8 @@ var registerSystemOneDecideTool = (server) => {
133938
134771
  model: string2().optional(),
133939
134772
  answers: record2(string2(), unknown()).optional(),
133940
134773
  usage: record2(string2(), unknown()).optional(),
133941
- requestId: string2().optional()
134774
+ requestId: string2().optional(),
134775
+ 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
134776
  })
133943
134777
  }, async ({ provider, model, state, questions, timeoutMs, maxRetries }, requestInfo) => {
133944
134778
  if (!requestInfo.agentId) {
@@ -133963,8 +134797,9 @@ var registerSystemOneDecideTool = (server) => {
133963
134797
  return toolErr("The system-one-decision executor is not available");
133964
134798
  }
133965
134799
  const decided = await executor.decide(parsed.data);
133966
- if (!decided.ok)
133967
- return toolErr(decided.error);
134800
+ if (!decided.ok) {
134801
+ return toolErr(decided.error, decided.deploymentRefused ? { data: { providerUnavailable: true } } : {});
134802
+ }
133968
134803
  const { output } = decided;
133969
134804
  return toolOk(`Decision from ${output.model}`, {
133970
134805
  data: {
@@ -135961,7 +136796,8 @@ async function createServer(opts = {}) {
135961
136796
  ...opts.preloadedTools?.length ? { instructions: resolveTemplate("system.agent.tool_preload", {}).text } : {},
135962
136797
  capabilities: {
135963
136798
  logging: {}
135964
- }
136799
+ },
136800
+ maxToolInputElements: MCP_MAX_TOOL_INPUT_ELEMENTS
135965
136801
  });
135966
136802
  if (opts.preloadedTools?.length)
135967
136803
  setPreloadedTools(server, opts.preloadedTools);
@@ -136196,4 +137032,4 @@ async function createServer(opts = {}) {
136196
137032
  return server;
136197
137033
  }
136198
137034
 
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 };
137035
+ 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, 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 };