@vellumai/assistant 0.6.6 → 0.7.1

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 (1603) hide show
  1. package/AGENTS.md +20 -0
  2. package/ARCHITECTURE.md +46 -38
  3. package/Dockerfile +27 -6
  4. package/README.md +9 -11
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +83 -149
  6. package/bun.lock +309 -119
  7. package/docs/architecture/memory.md +1 -90
  8. package/docs/architecture/security.md +28 -41
  9. package/docs/credential-execution-service.md +7 -5
  10. package/docs/skills.md +10 -10
  11. package/docs/stt-provider-onboarding.md +17 -45
  12. package/examples/plugins/echo/bun.lock +25 -0
  13. package/knip.json +9 -22
  14. package/node_modules/@vellumai/ces-client/bun.lock +33 -0
  15. package/node_modules/@vellumai/ces-client/package.json +25 -0
  16. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
  17. package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
  18. package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
  19. package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
  20. package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
  21. package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
  22. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
  23. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  24. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  25. package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
  26. package/node_modules/@vellumai/gateway-client/package.json +23 -0
  27. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
  28. package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
  29. package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
  30. package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
  31. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
  32. package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
  33. package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
  34. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  35. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  36. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  37. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  38. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  39. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  40. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  41. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  42. package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
  43. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +887 -0
  44. package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
  45. package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
  46. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +86 -0
  47. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1342 -0
  48. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
  49. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
  50. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
  51. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +325 -0
  52. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
  53. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
  54. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
  55. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  56. package/node_modules/@vellumai/slack-text/package.json +18 -0
  57. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  58. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  59. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  60. package/openapi.yaml +3136 -650
  61. package/package.json +15 -7
  62. package/scripts/check-circular-deps.ts +80 -0
  63. package/scripts/generate-openapi.ts +29 -107
  64. package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +27 -27
  65. package/src/__tests__/access-request-decision.test.ts +2 -11
  66. package/src/__tests__/acp-session.test.ts +4 -150
  67. package/src/__tests__/actor-token-service.test.ts +17 -678
  68. package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
  69. package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
  70. package/src/__tests__/agent-loop-thinking.test.ts +4 -4
  71. package/src/__tests__/agent-wake-override-profile.test.ts +283 -0
  72. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
  73. package/src/__tests__/anthropic-provider.test.ts +183 -28
  74. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  75. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  76. package/src/__tests__/app-routes-csp.test.ts +106 -55
  77. package/src/__tests__/approval-cascade.test.ts +3 -370
  78. package/src/__tests__/approval-conversation-turn.test.ts +3 -8
  79. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
  80. package/src/__tests__/approval-primitive.test.ts +2 -1
  81. package/src/__tests__/approval-routes-http.test.ts +36 -464
  82. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  83. package/src/__tests__/assistant-event.test.ts +0 -5
  84. package/src/__tests__/assistant-events-sse-hardening.test.ts +107 -92
  85. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  86. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
  87. package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
  88. package/src/__tests__/attachments-store.test.ts +46 -1
  89. package/src/__tests__/audit-log-rotation.test.ts +2 -1
  90. package/src/__tests__/auto-analysis-end-to-end.test.ts +8 -20
  91. package/src/__tests__/background-shell-bash.test.ts +227 -0
  92. package/src/__tests__/background-shell-host-bash.test.ts +465 -0
  93. package/src/__tests__/background-tool-registry.test.ts +145 -0
  94. package/src/__tests__/background-tool-routes.test.ts +175 -0
  95. package/src/__tests__/btw-routes.test.ts +147 -183
  96. package/src/__tests__/call-controller.test.ts +15 -2
  97. package/src/__tests__/call-conversation-messages.test.ts +2 -1
  98. package/src/__tests__/call-domain.test.ts +2 -2
  99. package/src/__tests__/call-pointer-messages.test.ts +11 -13
  100. package/src/__tests__/call-recovery.test.ts +2 -1
  101. package/src/__tests__/call-routes-http.test.ts +3 -14
  102. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  103. package/src/__tests__/call-store.test.ts +2 -1
  104. package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
  105. package/src/__tests__/canonical-guardian-store.test.ts +2 -2
  106. package/src/__tests__/catalog-files.test.ts +0 -26
  107. package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
  108. package/src/__tests__/channel-approval-routes.test.ts +88 -344
  109. package/src/__tests__/channel-approval.test.ts +9 -7
  110. package/src/__tests__/channel-approvals.test.ts +34 -197
  111. package/src/__tests__/channel-delivery-store.test.ts +11 -10
  112. package/src/__tests__/channel-guardian.test.ts +114 -171
  113. package/src/__tests__/channel-readiness-service.test.ts +8 -6
  114. package/src/__tests__/channel-reply-delivery.test.ts +3 -19
  115. package/src/__tests__/channel-retry-sweep.test.ts +2 -5
  116. package/src/__tests__/checker.test.ts +272 -3933
  117. package/src/__tests__/circuit-breaker-pipeline.test.ts +1 -1
  118. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
  119. package/src/__tests__/cli.test.ts +1 -38
  120. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  121. package/src/__tests__/compaction-events.test.ts +2 -1
  122. package/src/__tests__/compaction-pipeline.test.ts +1 -1
  123. package/src/__tests__/compaction-strip-metadata-clear.test.ts +2 -2
  124. package/src/__tests__/compaction-timeout-recovery.test.ts +1 -1
  125. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
  126. package/src/__tests__/config-model-image-provider.test.ts +0 -1
  127. package/src/__tests__/config-schema-cmd.test.ts +1 -1
  128. package/src/__tests__/config-schema.test.ts +36 -269
  129. package/src/__tests__/config-watcher.test.ts +12 -0
  130. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
  131. package/src/__tests__/connection-policy.test.ts +1 -52
  132. package/src/__tests__/contact-store-user-file.test.ts +2 -1
  133. package/src/__tests__/contacts-tools.test.ts +56 -29
  134. package/src/__tests__/contacts-write.test.ts +8 -125
  135. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  136. package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
  137. package/src/__tests__/context-search-agent-runner.test.ts +998 -0
  138. package/src/__tests__/context-search-conversations-source.test.ts +320 -0
  139. package/src/__tests__/context-search-fanout.test.ts +380 -0
  140. package/src/__tests__/context-search-memory-source.test.ts +430 -0
  141. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  142. package/src/__tests__/context-search-pkb-source.test.ts +493 -0
  143. package/src/__tests__/context-search-types.test.ts +95 -0
  144. package/src/__tests__/context-search-workspace-source.test.ts +532 -0
  145. package/src/__tests__/context-window-manager.test.ts +71 -0
  146. package/src/__tests__/conversation-abort-tool-results.test.ts +10 -1
  147. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +633 -0
  148. package/src/__tests__/conversation-agent-loop-overflow.test.ts +117 -31
  149. package/src/__tests__/conversation-agent-loop.test.ts +1004 -15
  150. package/src/__tests__/conversation-analysis-routes.test.ts +68 -88
  151. package/src/__tests__/conversation-attachments.test.ts +9 -20
  152. package/src/__tests__/conversation-attention-store.test.ts +2 -1
  153. package/src/__tests__/conversation-attention-telegram.test.ts +15 -5
  154. package/src/__tests__/conversation-clear-safety.test.ts +53 -95
  155. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -330
  156. package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
  157. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
  158. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  159. package/src/__tests__/conversation-disk-view.test.ts +5 -4
  160. package/src/__tests__/conversation-fork-crud.test.ts +26 -55
  161. package/src/__tests__/conversation-fork-route.test.ts +5 -74
  162. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  163. package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
  164. package/src/__tests__/conversation-inference-profile-route.test.ts +205 -0
  165. package/src/__tests__/conversation-init.benchmark.test.ts +4 -81
  166. package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
  167. package/src/__tests__/conversation-lifecycle.test.ts +4 -5
  168. package/src/__tests__/conversation-list-source.test.ts +2 -2
  169. package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
  170. package/src/__tests__/conversation-pairing.test.ts +0 -1
  171. package/src/__tests__/conversation-pre-run-repair.test.ts +137 -297
  172. package/src/__tests__/conversation-process-callsite.test.ts +79 -3
  173. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -1
  174. package/src/__tests__/conversation-queue.test.ts +4 -41
  175. package/src/__tests__/conversation-routes-disk-view.test.ts +55 -188
  176. package/src/__tests__/conversation-routes-guardian-reply.test.ts +64 -71
  177. package/src/__tests__/conversation-routes-slash-commands.test.ts +144 -64
  178. package/src/__tests__/conversation-runtime-assembly.test.ts +295 -84
  179. package/src/__tests__/conversation-slash-commands.test.ts +30 -47
  180. package/src/__tests__/conversation-slash-queue.test.ts +2 -1
  181. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  182. package/src/__tests__/conversation-speed-override.test.ts +0 -4
  183. package/src/__tests__/conversation-starter-routes.test.ts +254 -55
  184. package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
  185. package/src/__tests__/conversation-store.test.ts +2 -375
  186. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  187. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  188. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  189. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -47
  190. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
  191. package/src/__tests__/conversation-unread-route.test.ts +1 -1
  192. package/src/__tests__/conversation-usage.test.ts +255 -4
  193. package/src/__tests__/conversation-wipe.test.ts +2 -103
  194. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -1
  195. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  196. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  197. package/src/__tests__/conversations-defer-cli.test.ts +150 -0
  198. package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
  199. package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
  200. package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
  201. package/src/__tests__/credential-execution-client.test.ts +1 -1
  202. package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
  203. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  204. package/src/__tests__/credential-health-service.test.ts +68 -0
  205. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  206. package/src/__tests__/credential-security-invariants.test.ts +15 -5
  207. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  208. package/src/__tests__/credentials-cli.test.ts +45 -21
  209. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  210. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  211. package/src/__tests__/daemon-credential-client.test.ts +26 -108
  212. package/src/__tests__/db-acp-history.test.ts +284 -0
  213. package/src/__tests__/db-activation-state.test.ts +240 -0
  214. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  215. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
  216. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
  217. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
  218. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
  219. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  220. package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
  221. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  222. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  223. package/src/__tests__/delete-propagation.test.ts +3 -2
  224. package/src/__tests__/deterministic-verification-control-plane.test.ts +38 -104
  225. package/src/__tests__/dm-backfill.test.ts +3 -2
  226. package/src/__tests__/document-conversations.test.ts +332 -0
  227. package/src/__tests__/edit-propagation.test.ts +5 -7
  228. package/src/__tests__/embedding-managed-proxy-selection.test.ts +3 -3
  229. package/src/__tests__/emit-event-signal.test.ts +4 -6
  230. package/src/__tests__/empty-response-pipeline.test.ts +1 -1
  231. package/src/__tests__/events-client-registration.test.ts +441 -0
  232. package/src/__tests__/file-write-tool.test.ts +2 -4
  233. package/src/__tests__/filing-service.test.ts +197 -19
  234. package/src/__tests__/first-greeting.test.ts +156 -150
  235. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  236. package/src/__tests__/followup-tools.test.ts +2 -1
  237. package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
  238. package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
  239. package/src/__tests__/gateway-only-guard.test.ts +4 -3
  240. package/src/__tests__/gemini-provider.test.ts +276 -10
  241. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  242. package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
  243. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
  244. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
  245. package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
  246. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
  247. package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
  248. package/src/__tests__/guardian-action-store.test.ts +2 -1
  249. package/src/__tests__/guardian-action-sweep.test.ts +9 -8
  250. package/src/__tests__/guardian-binding-drift-heal.test.ts +3 -2
  251. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
  252. package/src/__tests__/guardian-dispatch.test.ts +14 -11
  253. package/src/__tests__/guardian-grant-minting.test.ts +16 -17
  254. package/src/__tests__/guardian-outbound-http.test.ts +71 -106
  255. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
  256. package/src/__tests__/guardian-routing-invariants.test.ts +41 -92
  257. package/src/__tests__/guardian-routing-state.test.ts +15 -23
  258. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
  259. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +274 -0
  260. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +10 -87
  261. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  262. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  263. package/src/__tests__/heartbeat-service.test.ts +325 -25
  264. package/src/__tests__/helpers/call-route-handler.ts +72 -0
  265. package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
  266. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  267. package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
  268. package/src/__tests__/helpers/mock-logger.ts +36 -0
  269. package/src/__tests__/history-repair-pipeline.test.ts +1 -1
  270. package/src/__tests__/home-state-routes.test.ts +10 -31
  271. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  272. package/src/__tests__/host-browser-e2e-cloud.test.ts +38 -498
  273. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +35 -95
  274. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  275. package/src/__tests__/host-browser-routes.test.ts +68 -153
  276. package/src/__tests__/host-browser-ws-events-e2e.test.ts +35 -31
  277. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  278. package/src/__tests__/host-file-proxy.test.ts +44 -98
  279. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  280. package/src/__tests__/host-proxy-interface.test.ts +3 -3
  281. package/src/__tests__/host-shell-tool.test.ts +35 -72
  282. package/src/__tests__/host-transfer-pending-interactions.test.ts +144 -0
  283. package/src/__tests__/host-transfer-proxy.test.ts +723 -0
  284. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  285. package/src/__tests__/http-user-message-parity.test.ts +18 -15
  286. package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
  287. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  288. package/src/__tests__/injector-chain.test.ts +25 -21
  289. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  290. package/src/__tests__/inline-command-runner.test.ts +0 -66
  291. package/src/__tests__/inline-skill-load-permissions.test.ts +41 -208
  292. package/src/__tests__/install-skill-routing.test.ts +2 -14
  293. package/src/__tests__/invite-redemption-service.test.ts +2 -1
  294. package/src/__tests__/invite-routes-http.test.ts +80 -12
  295. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
  296. package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
  297. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
  298. package/src/__tests__/list-messages-attachments.test.ts +52 -55
  299. package/src/__tests__/list-messages-page-latest.test.ts +283 -0
  300. package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
  301. package/src/__tests__/llm-call-pipeline.test.ts +7 -8
  302. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  303. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  304. package/src/__tests__/llm-context-normalization.test.ts +69 -4
  305. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  306. package/src/__tests__/llm-context-route-provider.test.ts +39 -113
  307. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
  308. package/src/__tests__/llm-resolver.test.ts +279 -0
  309. package/src/__tests__/llm-schema.test.ts +57 -1
  310. package/src/__tests__/llm-usage-store.test.ts +271 -5
  311. package/src/__tests__/log-export-routes.test.ts +89 -0
  312. package/src/__tests__/log-export-workspace.test.ts +28 -17
  313. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  314. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  315. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  316. package/src/__tests__/mcp-abort-signal.test.ts +2 -3
  317. package/src/__tests__/mcp-client-auth.test.ts +2 -3
  318. package/src/__tests__/memory-admin-recall.test.ts +221 -0
  319. package/src/__tests__/memory-recall-log-store.test.ts +2 -1
  320. package/src/__tests__/memory-retrieval-pipeline.test.ts +6 -8
  321. package/src/__tests__/memory-upsert-concurrency.test.ts +2 -1
  322. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  323. package/src/__tests__/migration-cross-version-compatibility.test.ts +209 -302
  324. package/src/__tests__/migration-export-http.test.ts +50 -43
  325. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  326. package/src/__tests__/migration-export-to-gcs.test.ts +531 -0
  327. package/src/__tests__/migration-import-commit-http.test.ts +82 -37
  328. package/src/__tests__/migration-import-from-gcs.test.ts +574 -0
  329. package/src/__tests__/migration-import-from-url.test.ts +34 -27
  330. package/src/__tests__/migration-import-preflight-http.test.ts +108 -108
  331. package/src/__tests__/migration-jobs-status.test.ts +164 -0
  332. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  333. package/src/__tests__/migration-transport.test.ts +115 -23
  334. package/src/__tests__/migration-validate-http.test.ts +149 -159
  335. package/src/__tests__/migration-wizard.test.ts +133 -27
  336. package/src/__tests__/mock-gateway-ipc.ts +32 -62
  337. package/src/__tests__/model-intents.test.ts +15 -2
  338. package/src/__tests__/nl-approval-parser.test.ts +13 -17
  339. package/src/__tests__/non-member-access-request.test.ts +14 -6
  340. package/src/__tests__/notification-guardian-path.test.ts +15 -8
  341. package/src/__tests__/notification-schedule-notify-dedup.test.ts +2 -1
  342. package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
  343. package/src/__tests__/oauth-apps-routes.test.ts +76 -122
  344. package/src/__tests__/oauth-cli.test.ts +14 -1
  345. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  346. package/src/__tests__/oauth-provider-visibility.test.ts +3 -1
  347. package/src/__tests__/oauth-providers-routes.test.ts +78 -101
  348. package/src/__tests__/oauth-store.test.ts +22 -1
  349. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
  350. package/src/__tests__/openai-provider.test.ts +105 -6
  351. package/src/__tests__/openai-responses-provider.test.ts +146 -4
  352. package/src/__tests__/openrouter-provider-only.test.ts +22 -4
  353. package/src/__tests__/overflow-reduce-pipeline.test.ts +4 -9
  354. package/src/__tests__/permission-types.test.ts +3 -18
  355. package/src/__tests__/persistence-pipeline.test.ts +3 -2
  356. package/src/__tests__/pipeline-runner.test.ts +1 -1
  357. package/src/__tests__/platform-bash-auto-approve.test.ts +44 -28
  358. package/src/__tests__/platform.test.ts +11 -63
  359. package/src/__tests__/playbook-execution.test.ts +2 -1
  360. package/src/__tests__/playbook-tools.test.ts +2 -1
  361. package/src/__tests__/plugin-bootstrap.test.ts +51 -5
  362. package/src/__tests__/plugin-registry.test.ts +30 -0
  363. package/src/__tests__/plugin-route-contribution.test.ts +17 -11
  364. package/src/__tests__/plugin-skill-contribution.test.ts +3 -3
  365. package/src/__tests__/plugin-tool-contribution.test.ts +10 -4
  366. package/src/__tests__/plugin-types.test.ts +1 -1
  367. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  368. package/src/__tests__/pricing.test.ts +218 -5
  369. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  370. package/src/__tests__/profiler-routes.test.ts +112 -177
  371. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  372. package/src/__tests__/provider-send-message-override-profile.test.ts +273 -0
  373. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  374. package/src/__tests__/proxy-approval-callback.test.ts +6 -554
  375. package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
  376. package/src/__tests__/reaction-persistence.test.ts +12 -8
  377. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  378. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  379. package/src/__tests__/recording-handler.test.ts +64 -83
  380. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  381. package/src/__tests__/registry.test.ts +1 -0
  382. package/src/__tests__/relay-server.test.ts +37 -17
  383. package/src/__tests__/require-fresh-approval.test.ts +24 -182
  384. package/src/__tests__/resolve-trust-class.test.ts +2 -1
  385. package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
  386. package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
  387. package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
  388. package/src/__tests__/runtime-events-sse-parity.test.ts +15 -17
  389. package/src/__tests__/runtime-events-sse.test.ts +16 -33
  390. package/src/__tests__/schedule-routes.test.ts +226 -129
  391. package/src/__tests__/schedule-store.test.ts +119 -1
  392. package/src/__tests__/schedule-tools.test.ts +2 -1
  393. package/src/__tests__/scheduler-recurrence.test.ts +2 -1
  394. package/src/__tests__/scheduler-reuse-conversation.test.ts +2 -1
  395. package/src/__tests__/scheduler-wake.test.ts +356 -0
  396. package/src/__tests__/scoped-approval-grants.test.ts +2 -1
  397. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
  398. package/src/__tests__/search-skills-unified.test.ts +9 -15
  399. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  400. package/src/__tests__/secret-ingress-http.test.ts +36 -23
  401. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  402. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  403. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  404. package/src/__tests__/secret-response-routing.test.ts +29 -15
  405. package/src/__tests__/secret-routes-managed-proxy.test.ts +51 -103
  406. package/src/__tests__/secret-scanner.test.ts +2 -545
  407. package/src/__tests__/send-endpoint-busy.test.ts +36 -38
  408. package/src/__tests__/sequence-store.test.ts +2 -1
  409. package/src/__tests__/server-history-render.test.ts +2 -2
  410. package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
  411. package/src/__tests__/set-permission-mode.test.ts +0 -10
  412. package/src/__tests__/settings-routes.test.ts +36 -69
  413. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  414. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  415. package/src/__tests__/skill-boundary-guard.test.ts +105 -0
  416. package/src/__tests__/skill-load-inline-command.test.ts +2 -2
  417. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  418. package/src/__tests__/skill-runtime-path.test.ts +64 -0
  419. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  420. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  421. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -32
  422. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  423. package/src/__tests__/slack-inbound-verification.test.ts +12 -64
  424. package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
  425. package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
  426. package/src/__tests__/slack-share-routes.test.ts +37 -72
  427. package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
  428. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  429. package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
  430. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  431. package/src/__tests__/subagent-notify-parent.test.ts +83 -109
  432. package/src/__tests__/subagent-role-registry.test.ts +3 -3
  433. package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
  434. package/src/__tests__/subagent-tools.test.ts +0 -1
  435. package/src/__tests__/suggestion-routes.test.ts +55 -62
  436. package/src/__tests__/system-prompt.test.ts +115 -13
  437. package/src/__tests__/task-compiler.test.ts +2 -1
  438. package/src/__tests__/task-management-tools.test.ts +2 -1
  439. package/src/__tests__/task-memory-cleanup.test.ts +2 -1
  440. package/src/__tests__/task-scheduler.test.ts +2 -1
  441. package/src/__tests__/telegram-config.test.ts +0 -1
  442. package/src/__tests__/terminal-tools.test.ts +3 -401
  443. package/src/__tests__/test-preload.ts +0 -11
  444. package/src/__tests__/thread-backfill.test.ts +947 -32
  445. package/src/__tests__/token-estimate-pipeline.test.ts +68 -15
  446. package/src/__tests__/tool-approval-handler.test.ts +21 -63
  447. package/src/__tests__/tool-audit-listener.test.ts +3 -3
  448. package/src/__tests__/tool-domain-event-publisher.test.ts +3 -39
  449. package/src/__tests__/tool-error-pipeline.test.ts +6 -6
  450. package/src/__tests__/tool-execute-pipeline.test.ts +6 -14
  451. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  452. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +69 -16
  453. package/src/__tests__/tool-executor-lifecycle-events.test.ts +31 -62
  454. package/src/__tests__/tool-executor.test.ts +336 -1654
  455. package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
  456. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  457. package/src/__tests__/tool-result-truncate-pipeline.test.ts +1 -1
  458. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  459. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  460. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  461. package/src/__tests__/trust-context-guards.test.ts +1 -1
  462. package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
  463. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
  464. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +5 -151
  465. package/src/__tests__/trusted-contact-multichannel.test.ts +5 -6
  466. package/src/__tests__/trusted-contact-verification.test.ts +3 -2
  467. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  468. package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
  469. package/src/__tests__/twilio-routes.test.ts +25 -66
  470. package/src/__tests__/usage-attribution.test.ts +247 -0
  471. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
  472. package/src/__tests__/usage-cli.test.ts +143 -0
  473. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  474. package/src/__tests__/usage-routes.test.ts +223 -90
  475. package/src/__tests__/user-plugin-loader.test.ts +54 -12
  476. package/src/__tests__/validation-results-screen.test.ts +39 -16
  477. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  478. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +51 -139
  479. package/src/__tests__/verification-control-plane-policy.test.ts +97 -19
  480. package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
  481. package/src/__tests__/voice-invite-redemption.test.ts +2 -1
  482. package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
  483. package/src/__tests__/voice-session-bridge.test.ts +285 -106
  484. package/src/__tests__/volume-security-guard.test.ts +0 -2
  485. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
  486. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
  487. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
  488. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
  489. package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
  490. package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
  491. package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
  492. package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
  493. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
  494. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  495. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  496. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  497. package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
  498. package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
  499. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +252 -0
  500. package/src/acp/__tests__/client-handler.test.ts +64 -0
  501. package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
  502. package/src/acp/__tests__/helpers/which-stub.ts +45 -0
  503. package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
  504. package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
  505. package/src/acp/__tests__/session-manager.test.ts +83 -0
  506. package/src/acp/client-handler.ts +23 -139
  507. package/src/acp/index.ts +0 -15
  508. package/src/acp/resolve-agent.test.ts +291 -0
  509. package/src/acp/resolve-agent.ts +176 -0
  510. package/src/acp/session-manager.ts +193 -31
  511. package/src/acp/types.ts +2 -50
  512. package/src/agent/loop.ts +53 -15
  513. package/src/agent/message-types.ts +0 -2
  514. package/src/approvals/AGENTS.md +5 -1
  515. package/src/approvals/__tests__/guardian-feed-event.test.ts +11 -12
  516. package/src/approvals/approval-primitive.ts +3 -20
  517. package/src/approvals/guardian-decision-primitive.ts +37 -68
  518. package/src/approvals/guardian-request-resolvers.ts +38 -104
  519. package/src/avatar/character-components.ts +6 -6
  520. package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
  521. package/src/backup/__tests__/backup-worker.test.ts +36 -10
  522. package/src/backup/__tests__/paths.test.ts +5 -4
  523. package/src/backup/__tests__/restore.test.ts +45 -28
  524. package/src/backup/backup-worker.ts +37 -12
  525. package/src/backup/paths.ts +11 -24
  526. package/src/backup/restore.ts +7 -11
  527. package/src/browser/__tests__/operations.test.ts +0 -35
  528. package/src/browser/operations.ts +1 -47
  529. package/src/browser-session/events.ts +0 -9
  530. package/src/bundler/package-resolver.ts +2 -6
  531. package/src/calls/active-call-lease.ts +1 -1
  532. package/src/calls/call-constants.ts +1 -1
  533. package/src/calls/call-controller.ts +1 -5
  534. package/src/calls/call-domain.ts +14 -14
  535. package/src/calls/call-pointer-messages.ts +4 -9
  536. package/src/calls/call-store.ts +2 -34
  537. package/src/calls/guardian-action-sweep.ts +9 -25
  538. package/src/calls/guardian-dispatch.ts +1 -20
  539. package/src/calls/guardian-question-copy.ts +0 -108
  540. package/src/calls/media-stream-audio-transcode.ts +2 -41
  541. package/src/calls/media-stream-server.ts +2 -3
  542. package/src/calls/media-stream-stt-session.ts +1 -3
  543. package/src/calls/relay-access-wait.ts +5 -8
  544. package/src/calls/relay-server.ts +15 -42
  545. package/src/calls/relay-setup-router.ts +2 -2
  546. package/src/calls/relay-verification.ts +4 -4
  547. package/src/calls/twilio-rest.ts +1 -39
  548. package/src/calls/twilio-routes.ts +160 -78
  549. package/src/calls/voice-control-protocol.ts +10 -10
  550. package/src/calls/voice-ingress-preflight.ts +2 -2
  551. package/src/calls/voice-session-bridge.ts +141 -77
  552. package/src/channels/__tests__/types.test.ts +25 -3
  553. package/src/channels/permission-profiles.ts +2 -72
  554. package/src/channels/types.ts +25 -44
  555. package/src/cli/AGENTS.md +1 -0
  556. package/src/cli/__tests__/notifications.test.ts +12 -10
  557. package/src/cli/commands/__tests__/attachment.test.ts +14 -8
  558. package/src/cli/commands/__tests__/backup.test.ts +3 -14
  559. package/src/cli/commands/__tests__/browser.test.ts +36 -31
  560. package/src/cli/commands/__tests__/cache.test.ts +175 -23
  561. package/src/cli/commands/__tests__/memory-v2.test.ts +382 -0
  562. package/src/cli/commands/__tests__/task.test.ts +36 -35
  563. package/src/cli/commands/__tests__/trust.test.ts +236 -0
  564. package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
  565. package/src/cli/commands/__tests__/ui.test.ts +17 -17
  566. package/src/cli/commands/__tests__/watchers.test.ts +29 -29
  567. package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
  568. package/src/cli/commands/attachment.ts +12 -8
  569. package/src/cli/commands/auth.ts +1 -1
  570. package/src/cli/commands/avatar.ts +192 -9
  571. package/src/cli/commands/backup.ts +18 -48
  572. package/src/cli/commands/browser.ts +52 -4
  573. package/src/cli/commands/cache-fs.ts +8 -0
  574. package/src/cli/commands/cache.ts +157 -84
  575. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  576. package/src/cli/commands/clients.ts +74 -17
  577. package/src/cli/commands/completions.ts +3 -3
  578. package/src/cli/commands/contacts.ts +241 -86
  579. package/src/cli/commands/conversations-defer.ts +364 -0
  580. package/src/cli/commands/conversations-import.ts +2 -3
  581. package/src/cli/commands/conversations.ts +63 -53
  582. package/src/cli/commands/credential-execution.ts +1 -1
  583. package/src/cli/commands/credentials.ts +139 -5
  584. package/src/cli/commands/default-action.ts +1 -1
  585. package/src/cli/commands/domain.ts +2 -2
  586. package/src/cli/commands/email.ts +7 -7
  587. package/src/cli/commands/image-generation.ts +1 -1
  588. package/src/cli/commands/keys.ts +5 -2
  589. package/src/cli/commands/mcp.ts +1 -1
  590. package/src/cli/commands/memory-v2.ts +315 -0
  591. package/src/cli/commands/memory.ts +8 -8
  592. package/src/cli/commands/notifications.ts +21 -20
  593. package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
  594. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
  595. package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
  596. package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
  597. package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
  598. package/src/cli/commands/oauth/connect.ts +2 -2
  599. package/src/cli/commands/pending.ts +102 -0
  600. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
  601. package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
  602. package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
  603. package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
  604. package/src/cli/commands/platform/connect.ts +3 -3
  605. package/src/cli/commands/platform/disconnect.ts +4 -6
  606. package/src/cli/commands/platform/index.ts +12 -10
  607. package/src/cli/commands/routes.ts +7 -1
  608. package/src/cli/commands/sequence.ts +7 -7
  609. package/src/cli/commands/skills.ts +264 -116
  610. package/src/cli/commands/task.ts +12 -10
  611. package/src/cli/commands/trust.ts +105 -167
  612. package/src/cli/commands/ui.ts +3 -3
  613. package/src/cli/commands/usage.ts +29 -15
  614. package/src/cli/commands/watchers.ts +8 -8
  615. package/src/cli/commands/webhooks.ts +270 -0
  616. package/src/cli/lib/daemon-avatar-client.ts +37 -0
  617. package/src/cli/lib/daemon-credential-client.ts +41 -189
  618. package/src/cli/lib/ipc-params.ts +22 -0
  619. package/src/cli/program.ts +6 -0
  620. package/src/cli.ts +1 -82
  621. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  622. package/src/config/acp-defaults.test.ts +57 -0
  623. package/src/config/acp-defaults.ts +40 -0
  624. package/src/config/acp-schema.ts +1 -1
  625. package/src/config/assistant-feature-flags.ts +18 -142
  626. package/src/config/bundled-skills/acp/SKILL.md +44 -16
  627. package/src/config/bundled-skills/acp/TOOLS.json +45 -1
  628. package/src/config/bundled-skills/acp/tools/acp-list-agents.ts +12 -0
  629. package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
  630. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +14 -14
  631. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -4
  632. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +11 -6
  633. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
  634. package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
  635. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  636. package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
  637. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  638. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
  639. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
  640. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
  641. package/src/config/bundled-skills/settings/SKILL.md +2 -17
  642. package/src/config/bundled-skills/settings/TOOLS.json +0 -56
  643. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  644. package/src/config/bundled-tool-registry.ts +4 -6
  645. package/src/config/env-registry.ts +12 -2
  646. package/src/config/env.ts +10 -22
  647. package/src/config/feature-flag-registry.json +38 -46
  648. package/src/config/llm-callsite-catalog.ts +12 -0
  649. package/src/config/llm-context-resolution.ts +80 -0
  650. package/src/config/llm-resolver.ts +90 -36
  651. package/src/config/loader.ts +9 -12
  652. package/src/config/schema.ts +5 -228
  653. package/src/config/schemas/__tests__/filing.test.ts +58 -0
  654. package/src/config/schemas/__tests__/memory-v2.test.ts +187 -0
  655. package/src/config/schemas/call-site-catalog.ts +271 -0
  656. package/src/config/schemas/calls.ts +5 -5
  657. package/src/config/schemas/filing.ts +12 -0
  658. package/src/config/schemas/host-browser.ts +2 -2
  659. package/src/config/schemas/inference.ts +1 -3
  660. package/src/config/schemas/ingress.ts +2 -2
  661. package/src/config/schemas/llm.ts +82 -12
  662. package/src/config/schemas/memory-retrieval.ts +2 -2
  663. package/src/config/schemas/memory-storage.ts +1 -1
  664. package/src/config/schemas/memory-v2.ts +185 -0
  665. package/src/config/schemas/memory.ts +2 -0
  666. package/src/config/schemas/security.ts +1 -102
  667. package/src/config/schemas/services.ts +52 -13
  668. package/src/config/schemas/skills.ts +5 -5
  669. package/src/config/schemas/tts.ts +1 -1
  670. package/src/config/seed-inference-profiles.ts +117 -0
  671. package/src/config/skills.ts +1 -91
  672. package/src/config/types.ts +3 -47
  673. package/src/contacts/contact-store.ts +2 -19
  674. package/src/contacts/contacts-write.ts +1 -143
  675. package/src/contacts/types.ts +8 -10
  676. package/src/context/token-estimator.ts +1 -1
  677. package/src/context/tool-result-truncation.ts +1 -1
  678. package/src/context/window-manager.ts +45 -6
  679. package/src/credential-execution/approval-bridge.ts +7 -69
  680. package/src/credential-execution/client.ts +17 -422
  681. package/src/credential-execution/feature-gates.ts +1 -2
  682. package/src/credential-execution/managed-catalog.ts +1 -1
  683. package/src/credential-execution/process-manager.ts +34 -10
  684. package/src/credential-health/credential-health-service.ts +22 -17
  685. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -13
  686. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +76 -83
  687. package/src/daemon/__tests__/daemon-skill-host.test.ts +265 -0
  688. package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
  689. package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
  690. package/src/daemon/approval-generators.ts +2 -14
  691. package/src/daemon/classifier.ts +0 -106
  692. package/src/daemon/config-watcher.ts +14 -54
  693. package/src/daemon/connection-policy.ts +1 -40
  694. package/src/daemon/conversation-agent-loop-handlers.ts +89 -9
  695. package/src/daemon/conversation-agent-loop.ts +440 -88
  696. package/src/daemon/conversation-attachments.ts +5 -81
  697. package/src/daemon/conversation-error.ts +9 -5
  698. package/src/daemon/conversation-history.ts +9 -9
  699. package/src/daemon/conversation-launch.ts +21 -136
  700. package/src/daemon/conversation-lifecycle.ts +1 -1
  701. package/src/daemon/conversation-messaging.ts +2 -1
  702. package/src/daemon/conversation-notifiers.ts +1 -1
  703. package/src/daemon/conversation-process.ts +90 -174
  704. package/src/daemon/conversation-runtime-assembly.ts +245 -164
  705. package/src/daemon/conversation-slash.ts +50 -164
  706. package/src/daemon/conversation-store.ts +344 -0
  707. package/src/daemon/conversation-surfaces.ts +27 -32
  708. package/src/daemon/conversation-tool-setup.ts +23 -202
  709. package/src/daemon/conversation-usage.ts +36 -0
  710. package/src/daemon/conversation.ts +129 -381
  711. package/src/daemon/daemon-control.ts +4 -72
  712. package/src/daemon/daemon-skill-host.ts +259 -0
  713. package/src/daemon/dictation-profile-store.ts +2 -26
  714. package/src/daemon/external-plugins-bootstrap.ts +67 -13
  715. package/src/daemon/first-greeting.ts +44 -156
  716. package/src/daemon/handlers/config-channels.ts +14 -14
  717. package/src/daemon/handlers/config-embeddings.ts +1 -1
  718. package/src/daemon/handlers/config-ingress.ts +27 -166
  719. package/src/daemon/handlers/config-model.test.ts +17 -0
  720. package/src/daemon/handlers/config-model.ts +8 -53
  721. package/src/daemon/handlers/config-telegram.ts +6 -53
  722. package/src/daemon/handlers/config-voice.ts +0 -42
  723. package/src/daemon/handlers/conversations.ts +32 -345
  724. package/src/daemon/handlers/recording.ts +27 -159
  725. package/src/daemon/handlers/shared.ts +50 -99
  726. package/src/daemon/handlers/skills.ts +55 -114
  727. package/src/daemon/host-bash-proxy.ts +67 -45
  728. package/src/daemon/host-browser-proxy.ts +65 -27
  729. package/src/daemon/host-cu-proxy.ts +40 -39
  730. package/src/daemon/host-file-proxy.ts +58 -37
  731. package/src/daemon/host-transfer-proxy.ts +538 -0
  732. package/src/daemon/lifecycle.ts +71 -272
  733. package/src/daemon/meet-host-startup.ts +51 -0
  734. package/src/daemon/meet-host-supervisor.ts +781 -0
  735. package/src/daemon/meet-manifest-loader.ts +410 -0
  736. package/src/daemon/memory-v2-startup.ts +35 -0
  737. package/src/daemon/message-protocol.ts +4 -7
  738. package/src/daemon/message-types/acp.ts +1 -0
  739. package/src/daemon/message-types/conversations.ts +23 -2
  740. package/src/daemon/message-types/host-bash.ts +1 -0
  741. package/src/daemon/message-types/host-cu.ts +1 -0
  742. package/src/daemon/message-types/host-file.ts +1 -0
  743. package/src/daemon/message-types/host-transfer.ts +42 -0
  744. package/src/daemon/message-types/integrations.ts +6 -0
  745. package/src/daemon/message-types/messages.ts +24 -23
  746. package/src/daemon/message-types/schedules.ts +1 -0
  747. package/src/daemon/message-types/settings.ts +0 -6
  748. package/src/daemon/message-types/shared.ts +5 -2
  749. package/src/daemon/message-types/subagents.ts +2 -1
  750. package/src/daemon/message-types/workspace.ts +1 -3
  751. package/src/daemon/pkb-reminder-builder.test.ts +13 -12
  752. package/src/daemon/pkb-reminder-builder.ts +8 -16
  753. package/src/daemon/process-message.ts +479 -0
  754. package/src/daemon/providers-setup.ts +14 -6
  755. package/src/daemon/server.ts +58 -1702
  756. package/src/daemon/shutdown-handlers.ts +3 -3
  757. package/src/daemon/startup-error.ts +1 -1
  758. package/src/daemon/tool-side-effects.ts +125 -107
  759. package/src/daemon/trust-context.ts +45 -0
  760. package/src/daemon/wake-target-adapter.ts +218 -0
  761. package/src/email/feature-gate.ts +1 -1
  762. package/src/events/domain-events.ts +1 -16
  763. package/src/events/tool-audit-listener.ts +5 -9
  764. package/src/events/tool-domain-event-publisher.ts +0 -10
  765. package/src/events/tool-metrics-listener.ts +1 -21
  766. package/src/events/tool-trace-listener.ts +0 -14
  767. package/src/filing/filing-service.ts +207 -55
  768. package/src/followups/followup-store.ts +3 -71
  769. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +93 -21
  770. package/src/heartbeat/heartbeat-service.ts +55 -16
  771. package/src/home/__tests__/feed-writer.test.ts +0 -4
  772. package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
  773. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  774. package/src/home/__tests__/rollup-producer.test.ts +67 -2
  775. package/src/home/assistant-feed-authoring.ts +8 -1
  776. package/src/home/feed-types.ts +1 -1
  777. package/src/home/feed-writer.ts +1 -2
  778. package/src/home/relationship-state-writer.ts +17 -4
  779. package/src/home/rewrite-feed-title.ts +58 -0
  780. package/src/home/rollup-producer.ts +16 -3
  781. package/src/inbound/platform-callback-registration.ts +1 -17
  782. package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
  783. package/src/ipc/__tests__/browser-ipc.test.ts +72 -58
  784. package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
  785. package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
  786. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +253 -0
  787. package/src/ipc/__tests__/skill-server.test.ts +182 -0
  788. package/src/ipc/__tests__/socket-path.test.ts +69 -23
  789. package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
  790. package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
  791. package/src/ipc/assistant-server.ts +443 -0
  792. package/src/ipc/cli-client.ts +3 -3
  793. package/src/ipc/gateway-client.test.ts +131 -0
  794. package/src/ipc/gateway-client.ts +98 -123
  795. package/src/ipc/ipc-framing.ts +281 -0
  796. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +171 -0
  797. package/src/ipc/routes/db-proxy.ts +73 -0
  798. package/src/ipc/routes/route-adapter.ts +32 -0
  799. package/src/ipc/routes/trust-rules.test.ts +123 -0
  800. package/src/ipc/skill-ipc-types.ts +54 -0
  801. package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
  802. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +388 -0
  803. package/src/ipc/skill-routes/__tests__/identity.test.ts +62 -0
  804. package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
  805. package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
  806. package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
  807. package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
  808. package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
  809. package/src/ipc/skill-routes/config.ts +47 -0
  810. package/src/ipc/skill-routes/events.ts +120 -0
  811. package/src/ipc/skill-routes/identity.ts +21 -0
  812. package/src/ipc/skill-routes/index.ts +37 -0
  813. package/src/ipc/skill-routes/log.ts +40 -0
  814. package/src/ipc/skill-routes/memory.ts +76 -0
  815. package/src/ipc/skill-routes/platform.ts +39 -0
  816. package/src/ipc/skill-routes/providers.ts +163 -0
  817. package/src/ipc/skill-routes/registries.ts +393 -0
  818. package/src/ipc/skill-server.ts +738 -0
  819. package/src/ipc/skill-socket-path.ts +20 -0
  820. package/src/ipc/socket-cleanup.ts +92 -0
  821. package/src/ipc/socket-path.ts +63 -32
  822. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
  823. package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
  824. package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
  825. package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
  826. package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
  827. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
  828. package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
  829. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
  830. package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
  831. package/src/live-voice/__tests__/protocol.test.ts +295 -0
  832. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +413 -0
  833. package/src/live-voice/live-voice-archive.ts +758 -0
  834. package/src/live-voice/live-voice-metrics.ts +472 -0
  835. package/src/live-voice/live-voice-session-manager.ts +222 -0
  836. package/src/live-voice/live-voice-session.ts +1144 -0
  837. package/src/live-voice/live-voice-tts.ts +260 -0
  838. package/src/live-voice/protocol.ts +515 -0
  839. package/src/mcp/client.ts +2 -2
  840. package/src/mcp/manager.ts +0 -5
  841. package/src/media/types.ts +4 -4
  842. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
  843. package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
  844. package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
  845. package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
  846. package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
  847. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  848. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
  849. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  850. package/src/memory/admin.ts +65 -7
  851. package/src/memory/app-git-service.ts +0 -46
  852. package/src/memory/app-store.ts +154 -0
  853. package/src/memory/attachments-store.ts +20 -16
  854. package/src/memory/auto-analysis-enqueue.ts +2 -17
  855. package/src/memory/canonical-guardian-store.ts +2 -1
  856. package/src/memory/channel-verification-sessions.ts +1 -1
  857. package/src/memory/checkpoints.ts +1 -1
  858. package/src/memory/context-search/agent-protocol.ts +424 -0
  859. package/src/memory/context-search/agent-runner.ts +1295 -0
  860. package/src/memory/context-search/format.ts +160 -0
  861. package/src/memory/context-search/limits.ts +106 -0
  862. package/src/memory/context-search/search.ts +387 -0
  863. package/src/memory/context-search/sources/conversations.ts +278 -0
  864. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  865. package/src/memory/context-search/sources/memory.ts +95 -0
  866. package/src/memory/context-search/sources/pkb.ts +477 -0
  867. package/src/memory/context-search/sources/workspace.ts +1256 -0
  868. package/src/memory/context-search/types.ts +49 -0
  869. package/src/memory/conversation-analyze-job.ts +3 -24
  870. package/src/memory/conversation-attention-store.ts +1 -1
  871. package/src/memory/conversation-bootstrap.ts +1 -1
  872. package/src/memory/conversation-crud.ts +86 -119
  873. package/src/memory/conversation-directories.ts +1 -11
  874. package/src/memory/conversation-disk-view.ts +1 -5
  875. package/src/memory/conversation-display-order-migration.ts +11 -2
  876. package/src/memory/conversation-group-migration.ts +20 -4
  877. package/src/memory/conversation-key-store.ts +3 -4
  878. package/src/memory/conversation-queries.ts +13 -26
  879. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  880. package/src/memory/conversation-starter-validation.ts +88 -0
  881. package/src/memory/conversation-starters-cadence.ts +1 -1
  882. package/src/memory/conversation-title-service.ts +2 -1
  883. package/src/memory/db-connection.ts +62 -0
  884. package/src/memory/db-init.ts +28 -4
  885. package/src/memory/db-maintenance.ts +1 -1
  886. package/src/memory/delivery-channels.ts +1 -14
  887. package/src/memory/delivery-crud.ts +2 -32
  888. package/src/memory/delivery-status.ts +1 -1
  889. package/src/memory/embedding-backend.ts +3 -21
  890. package/src/memory/embedding-gemini.test.ts +4 -4
  891. package/src/memory/embedding-gemini.ts +0 -2
  892. package/src/memory/embedding-local.ts +6 -6
  893. package/src/memory/embedding-ollama.ts +6 -6
  894. package/src/memory/embedding-openai.ts +6 -6
  895. package/src/memory/embedding-types.ts +21 -0
  896. package/src/memory/external-conversation-store.ts +1 -1
  897. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +408 -0
  898. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
  899. package/src/memory/graph/bootstrap.test.ts +2 -7
  900. package/src/memory/graph/bootstrap.ts +2 -1
  901. package/src/memory/graph/capability-seed.ts +3 -3
  902. package/src/memory/graph/compaction.ts +1 -1
  903. package/src/memory/graph/consolidation.ts +13 -10
  904. package/src/memory/graph/conversation-graph-memory.ts +184 -12
  905. package/src/memory/graph/decay.ts +1 -1
  906. package/src/memory/graph/extraction.ts +53 -21
  907. package/src/memory/graph/graph-memory-state-store.ts +1 -1
  908. package/src/memory/graph/graph-search.test.ts +94 -2
  909. package/src/memory/graph/graph-search.ts +22 -7
  910. package/src/memory/graph/image-ref-utils.ts +1 -1
  911. package/src/memory/graph/injection.test.ts +2 -2
  912. package/src/memory/graph/injection.ts +1 -1
  913. package/src/memory/graph/retriever.test.ts +158 -4
  914. package/src/memory/graph/retriever.ts +17 -5
  915. package/src/memory/graph/store.test.ts +2 -1
  916. package/src/memory/graph/store.ts +1 -1
  917. package/src/memory/graph/tool-handlers.ts +73 -247
  918. package/src/memory/graph/tools.ts +35 -53
  919. package/src/memory/group-crud.ts +1 -2
  920. package/src/memory/guardian-action-store.ts +2 -84
  921. package/src/memory/guardian-approvals.ts +1 -49
  922. package/src/memory/guardian-rate-limits.ts +1 -1
  923. package/src/memory/indexer.ts +44 -32
  924. package/src/memory/invite-store.ts +1 -1
  925. package/src/memory/job-handlers/backfill.ts +1 -1
  926. package/src/memory/job-handlers/cleanup.ts +2 -1
  927. package/src/memory/job-handlers/conversation-starters.ts +54 -63
  928. package/src/memory/job-handlers/embedding.test.ts +2 -1
  929. package/src/memory/job-handlers/embedding.ts +1 -1
  930. package/src/memory/job-handlers/index-maintenance.ts +1 -1
  931. package/src/memory/job-handlers/summarization.ts +3 -3
  932. package/src/memory/job-utils.ts +3 -9
  933. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
  934. package/src/memory/jobs/embed-concept-page.ts +210 -0
  935. package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
  936. package/src/memory/jobs-store.ts +9 -2
  937. package/src/memory/jobs-worker.ts +56 -17
  938. package/src/memory/lifecycle-events-store.ts +1 -1
  939. package/src/memory/llm-request-log-store.ts +1 -42
  940. package/src/memory/llm-usage-store.ts +130 -44
  941. package/src/memory/media-store.ts +1 -1
  942. package/src/memory/memory-recall-log-store.ts +1 -1
  943. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  944. package/src/memory/migrations/038-actor-token-records.ts +3 -0
  945. package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
  946. package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
  947. package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
  948. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
  949. package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
  950. package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
  951. package/src/memory/migrations/230-acp-session-history.ts +41 -0
  952. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
  953. package/src/memory/migrations/232-activation-state.ts +38 -0
  954. package/src/memory/migrations/233-document-conversations.ts +54 -0
  955. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  956. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  957. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  958. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  959. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  960. package/src/memory/migrations/index.ts +24 -0
  961. package/src/memory/migrations/registry.ts +31 -0
  962. package/src/memory/pkb/pkb-index.test.ts +4 -5
  963. package/src/memory/pkb/pkb-reconcile.test.ts +4 -5
  964. package/src/memory/pkb/pkb-search.test.ts +83 -3
  965. package/src/memory/pkb/pkb-search.ts +27 -14
  966. package/src/memory/published-pages-store.ts +1 -1
  967. package/src/memory/raw-query.ts +2 -68
  968. package/src/memory/schema/acp.ts +30 -0
  969. package/src/memory/schema/conversations.ts +8 -1
  970. package/src/memory/schema/index.ts +1 -0
  971. package/src/memory/schema/infrastructure.ts +26 -32
  972. package/src/memory/schema/memory-graph.ts +36 -14
  973. package/src/memory/scoped-approval-grants.ts +2 -1
  974. package/src/memory/search/semantic.ts +7 -18
  975. package/src/memory/shared-app-links-store.ts +2 -1
  976. package/src/memory/tool-usage-store.ts +3 -1
  977. package/src/memory/trace-event-store.ts +2 -1
  978. package/src/memory/turn-events-store.ts +1 -1
  979. package/src/memory/usage-buckets.ts +40 -1
  980. package/src/memory/usage-grouped-buckets.ts +127 -0
  981. package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
  982. package/src/memory/v2/__tests__/activation.test.ts +1155 -0
  983. package/src/memory/v2/__tests__/backfill-jobs.test.ts +483 -0
  984. package/src/memory/v2/__tests__/consolidation-job.test.ts +412 -0
  985. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  986. package/src/memory/v2/__tests__/injection.test.ts +1161 -0
  987. package/src/memory/v2/__tests__/migration.test.ts +840 -0
  988. package/src/memory/v2/__tests__/page-store.test.ts +517 -0
  989. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  990. package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
  991. package/src/memory/v2/__tests__/sim.test.ts +549 -0
  992. package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
  993. package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
  994. package/src/memory/v2/__tests__/skill-store.test.ts +463 -0
  995. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  996. package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
  997. package/src/memory/v2/activation-store.ts +109 -0
  998. package/src/memory/v2/activation.ts +561 -0
  999. package/src/memory/v2/backfill-jobs.ts +357 -0
  1000. package/src/memory/v2/consolidation-job.ts +306 -0
  1001. package/src/memory/v2/edge-index.ts +191 -0
  1002. package/src/memory/v2/injection.ts +431 -0
  1003. package/src/memory/v2/migration.ts +647 -0
  1004. package/src/memory/v2/now-text.ts +37 -0
  1005. package/src/memory/v2/page-store.ts +382 -0
  1006. package/src/memory/v2/prompts/consolidation.ts +261 -0
  1007. package/src/memory/v2/prompts/sweep.ts +56 -0
  1008. package/src/memory/v2/qdrant.ts +342 -0
  1009. package/src/memory/v2/sim.ts +206 -0
  1010. package/src/memory/v2/skill-content.ts +42 -0
  1011. package/src/memory/v2/skill-qdrant.ts +395 -0
  1012. package/src/memory/v2/skill-store.ts +176 -0
  1013. package/src/memory/v2/static-context.ts +62 -0
  1014. package/src/memory/v2/sweep-job.ts +298 -0
  1015. package/src/memory/v2/types.ts +106 -0
  1016. package/src/memory/validation.ts +0 -11
  1017. package/src/messaging/draft-store.ts +0 -6
  1018. package/src/messaging/provider-types.ts +8 -0
  1019. package/src/messaging/provider.ts +7 -0
  1020. package/src/messaging/providers/gmail/client.ts +1 -121
  1021. package/src/messaging/providers/index.ts +262 -0
  1022. package/src/messaging/providers/outlook/client.ts +0 -73
  1023. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  1024. package/src/messaging/providers/slack/adapter.ts +122 -21
  1025. package/src/messaging/providers/slack/api.ts +242 -0
  1026. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  1027. package/src/messaging/providers/slack/backfill.ts +89 -11
  1028. package/src/messaging/providers/slack/client.ts +10 -124
  1029. package/src/messaging/providers/slack/message-metadata.ts +13 -3
  1030. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  1031. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  1032. package/src/messaging/providers/slack/send.ts +383 -0
  1033. package/src/messaging/providers/slack/types.ts +1 -0
  1034. package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
  1035. package/src/messaging/providers/telegram-bot/api.ts +253 -0
  1036. package/src/messaging/providers/telegram-bot/client.ts +17 -58
  1037. package/src/messaging/providers/telegram-bot/send.ts +232 -0
  1038. package/src/messaging/providers/whatsapp/adapter.ts +4 -36
  1039. package/src/messaging/providers/whatsapp/api.ts +319 -0
  1040. package/src/messaging/providers/whatsapp/client.ts +4 -48
  1041. package/src/messaging/providers/whatsapp/send.ts +209 -0
  1042. package/src/notifications/adapters/slack.ts +5 -23
  1043. package/src/notifications/adapters/telegram.ts +8 -29
  1044. package/src/notifications/conversation-candidates.ts +1 -1
  1045. package/src/notifications/conversation-seed-composer.ts +12 -6
  1046. package/src/notifications/copy-composer.ts +1 -1
  1047. package/src/notifications/decision-engine.ts +1 -1
  1048. package/src/notifications/decisions-store.ts +1 -1
  1049. package/src/notifications/deliveries-store.ts +2 -1
  1050. package/src/notifications/deterministic-checks.ts +1 -1
  1051. package/src/notifications/events-store.ts +1 -13
  1052. package/src/notifications/preferences-store.ts +1 -1
  1053. package/src/notifications/signal.ts +0 -9
  1054. package/src/oauth/connection-resolver.test.ts +8 -0
  1055. package/src/oauth/connection-resolver.ts +6 -5
  1056. package/src/oauth/credential-token-resolver.ts +97 -0
  1057. package/src/oauth/manual-token-connection.ts +30 -34
  1058. package/src/oauth/oauth-store.ts +8 -5
  1059. package/src/outbound-proxy/certs.ts +0 -7
  1060. package/src/outbound-proxy/config.ts +0 -74
  1061. package/src/outbound-proxy/health.ts +0 -44
  1062. package/src/outbound-proxy/index.ts +0 -23
  1063. package/src/permissions/approval-policy.test.ts +149 -132
  1064. package/src/permissions/approval-policy.ts +65 -91
  1065. package/src/permissions/approval-provenance.test.ts +184 -0
  1066. package/src/permissions/approval-provenance.ts +70 -0
  1067. package/src/permissions/checker.test.ts +632 -0
  1068. package/src/permissions/checker.ts +270 -460
  1069. package/src/permissions/gateway-threshold-reader.ts +31 -47
  1070. package/src/permissions/ipc-risk-types.ts +95 -0
  1071. package/src/permissions/prompter.ts +13 -11
  1072. package/src/permissions/risk-types.ts +24 -210
  1073. package/src/permissions/secret-prompter.ts +21 -48
  1074. package/src/permissions/types.ts +49 -46
  1075. package/src/permissions/workspace-policy.ts +1 -8
  1076. package/src/platform/sync-identity.ts +0 -8
  1077. package/src/playbooks/playbook-compiler.ts +1 -1
  1078. package/src/plugins/defaults/index.ts +1 -1
  1079. package/src/plugins/defaults/injectors.ts +87 -23
  1080. package/src/plugins/defaults/llm-call.ts +6 -9
  1081. package/src/plugins/defaults/memory-retrieval.ts +1 -6
  1082. package/src/plugins/defaults/overflow-reduce.ts +12 -7
  1083. package/src/plugins/defaults/token-estimate.ts +2 -3
  1084. package/src/plugins/registry.ts +61 -1
  1085. package/src/plugins/types.ts +14 -7
  1086. package/src/plugins/user-loader.ts +36 -10
  1087. package/src/prompts/persona-resolver.ts +2 -4
  1088. package/src/prompts/system-prompt.ts +34 -31
  1089. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  1090. package/src/prompts/templates/SOUL.md +3 -1
  1091. package/src/prompts/update-bulletin-job.ts +2 -0
  1092. package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
  1093. package/src/providers/__tests__/retry-callsite.test.ts +141 -7
  1094. package/src/providers/anthropic/client.ts +143 -52
  1095. package/src/providers/call-site-routing.ts +49 -6
  1096. package/src/providers/fireworks/client.ts +3 -0
  1097. package/src/providers/gemini/client.ts +113 -23
  1098. package/src/providers/managed-proxy/context.ts +0 -17
  1099. package/src/providers/model-catalog.ts +188 -27
  1100. package/src/providers/model-intents.ts +7 -8
  1101. package/src/providers/openai/chat-completions-provider.ts +43 -7
  1102. package/src/providers/openai/responses-provider.ts +46 -5
  1103. package/src/providers/openrouter/client.ts +4 -5
  1104. package/src/providers/provider-env-vars.ts +4 -12
  1105. package/src/providers/provider-send-message.ts +61 -13
  1106. package/src/providers/ratelimit.ts +7 -2
  1107. package/src/providers/registry.ts +15 -10
  1108. package/src/providers/retry.ts +148 -31
  1109. package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
  1110. package/src/providers/speech-to-text/openai-whisper.ts +3 -6
  1111. package/src/providers/speech-to-text/provider-catalog.ts +75 -0
  1112. package/src/providers/speech-to-text/xai.ts +5 -5
  1113. package/src/providers/thinking-config.ts +34 -0
  1114. package/src/providers/types.ts +35 -10
  1115. package/src/providers/usage-tracking.ts +96 -0
  1116. package/src/runtime/AGENTS.md +16 -11
  1117. package/src/runtime/__tests__/agent-wake.test.ts +122 -9
  1118. package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
  1119. package/src/runtime/access-request-helper.ts +9 -20
  1120. package/src/runtime/actor-trust-resolver.ts +2 -2
  1121. package/src/runtime/agent-wake.ts +211 -68
  1122. package/src/runtime/approval-conversation-turn.ts +2 -15
  1123. package/src/runtime/approval-message-composer.ts +11 -60
  1124. package/src/runtime/assistant-event-hub.ts +541 -45
  1125. package/src/runtime/assistant-event.ts +16 -69
  1126. package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
  1127. package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
  1128. package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
  1129. package/src/runtime/auth/middleware.ts +5 -5
  1130. package/src/runtime/auth/route-policy.ts +205 -12
  1131. package/src/runtime/auth/token-service.ts +1 -111
  1132. package/src/runtime/capability-tokens.ts +89 -313
  1133. package/src/runtime/channel-approval-types.ts +1 -6
  1134. package/src/runtime/channel-approvals.ts +13 -81
  1135. package/src/runtime/channel-readiness-service.ts +2 -2
  1136. package/src/runtime/channel-reply-delivery.ts +2 -8
  1137. package/src/runtime/channel-retry-sweep.ts +20 -17
  1138. package/src/runtime/channel-verification-service.ts +3 -5
  1139. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
  1140. package/src/runtime/gateway-client.ts +37 -378
  1141. package/src/runtime/guardian-action-grant-minter.ts +2 -3
  1142. package/src/runtime/guardian-action-message-composer.ts +11 -52
  1143. package/src/runtime/guardian-action-service.ts +19 -7
  1144. package/src/runtime/guardian-decision-types.ts +4 -65
  1145. package/src/runtime/guardian-reply-router.ts +10 -19
  1146. package/src/runtime/guardian-vellum-migration.ts +5 -64
  1147. package/src/runtime/http-errors.ts +1 -32
  1148. package/src/runtime/http-router.ts +54 -8
  1149. package/src/runtime/http-server.ts +362 -1187
  1150. package/src/runtime/http-types.ts +20 -98
  1151. package/src/runtime/interactive-ui-types.ts +145 -0
  1152. package/src/runtime/interactive-ui.ts +37 -196
  1153. package/src/runtime/invite-redemption-service.ts +1 -1
  1154. package/src/runtime/invite-redemption-templates.ts +1 -1
  1155. package/src/runtime/local-actor-identity.ts +13 -43
  1156. package/src/runtime/message-composer-types.ts +134 -0
  1157. package/src/runtime/middleware/auth.ts +0 -20
  1158. package/src/runtime/middleware/rate-limiter.ts +1 -1
  1159. package/src/runtime/middleware/request-logger.ts +5 -2
  1160. package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
  1161. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  1162. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  1163. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  1164. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  1165. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  1166. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  1167. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  1168. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  1169. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +18 -2
  1170. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  1171. package/src/runtime/migrations/job-registry.ts +281 -0
  1172. package/src/runtime/migrations/migration-transport.ts +46 -13
  1173. package/src/runtime/migrations/migration-wizard.ts +2 -2
  1174. package/src/runtime/migrations/origin-mode.ts +40 -0
  1175. package/src/runtime/migrations/vbundle-builder.ts +133 -80
  1176. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  1177. package/src/runtime/migrations/vbundle-importer.ts +8 -8
  1178. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  1179. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -16
  1180. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  1181. package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
  1182. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  1183. package/src/runtime/nl-approval-parser.ts +16 -21
  1184. package/src/runtime/pending-interactions.ts +42 -16
  1185. package/src/runtime/routes/__tests__/acp-routes.test.ts +394 -0
  1186. package/src/runtime/routes/__tests__/backup-routes.test.ts +232 -339
  1187. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  1188. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
  1189. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  1190. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  1191. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  1192. package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
  1193. package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
  1194. package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
  1195. package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
  1196. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  1197. package/src/runtime/routes/access-request-decision.ts +25 -50
  1198. package/src/runtime/routes/acp-routes.test.ts +368 -0
  1199. package/src/runtime/routes/acp-routes.ts +392 -170
  1200. package/src/runtime/routes/app-management-routes.ts +475 -662
  1201. package/src/runtime/routes/app-routes.ts +192 -177
  1202. package/src/runtime/routes/approval-routes.ts +163 -440
  1203. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
  1204. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
  1205. package/src/runtime/routes/attachment-routes.ts +409 -253
  1206. package/src/runtime/routes/audio-routes.ts +51 -18
  1207. package/src/runtime/routes/avatar-routes.ts +81 -76
  1208. package/src/runtime/routes/background-tool-routes.ts +94 -0
  1209. package/src/runtime/routes/backup-routes.ts +154 -336
  1210. package/src/runtime/routes/brain-graph-routes.ts +83 -110
  1211. package/src/runtime/routes/browser-routes.ts +127 -0
  1212. package/src/runtime/routes/btw-routes.ts +62 -106
  1213. package/src/runtime/routes/cache-routes.ts +96 -0
  1214. package/src/runtime/routes/call-routes.ts +208 -247
  1215. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
  1216. package/src/runtime/routes/channel-delivery-routes.ts +25 -27
  1217. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  1218. package/src/runtime/routes/channel-readiness-routes.ts +79 -120
  1219. package/src/runtime/routes/channel-route-definitions.ts +62 -0
  1220. package/src/runtime/routes/channel-route-shared.ts +15 -45
  1221. package/src/runtime/routes/channel-verification-routes.ts +207 -187
  1222. package/src/runtime/routes/client-routes.ts +81 -0
  1223. package/src/runtime/routes/consolidation-routes.ts +115 -0
  1224. package/src/runtime/routes/contact-routes.ts +533 -407
  1225. package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
  1226. package/src/runtime/routes/conversation-attention-routes.ts +55 -67
  1227. package/src/runtime/routes/conversation-list-routes.ts +248 -0
  1228. package/src/runtime/routes/conversation-management-routes.ts +591 -717
  1229. package/src/runtime/routes/conversation-query-routes.ts +621 -459
  1230. package/src/runtime/routes/conversation-routes.ts +396 -792
  1231. package/src/runtime/routes/conversation-starter-routes.ts +137 -108
  1232. package/src/runtime/routes/credential-prompt-routes.ts +124 -0
  1233. package/src/runtime/routes/debug-routes.ts +34 -39
  1234. package/src/runtime/routes/defer-routes.ts +230 -0
  1235. package/src/runtime/routes/diagnostics-routes.ts +79 -70
  1236. package/src/runtime/routes/documents-routes.ts +163 -117
  1237. package/src/runtime/routes/errors.ts +132 -0
  1238. package/src/runtime/routes/events-routes.ts +126 -119
  1239. package/src/runtime/routes/filing-routes.ts +80 -76
  1240. package/src/runtime/routes/global-search-routes.ts +51 -57
  1241. package/src/runtime/routes/group-routes.ts +199 -181
  1242. package/src/runtime/routes/guardian-action-routes.ts +100 -171
  1243. package/src/runtime/routes/guardian-approval-interception.ts +27 -58
  1244. package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
  1245. package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
  1246. package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
  1247. package/src/runtime/routes/heartbeat-routes.ts +194 -209
  1248. package/src/runtime/routes/home-feed-routes.ts +85 -187
  1249. package/src/runtime/routes/home-state-routes.ts +27 -24
  1250. package/src/runtime/routes/host-bash-routes.ts +45 -54
  1251. package/src/runtime/routes/host-browser-routes.ts +44 -99
  1252. package/src/runtime/routes/host-cu-routes.ts +80 -71
  1253. package/src/runtime/routes/host-file-routes.ts +53 -62
  1254. package/src/runtime/routes/host-transfer-routes.ts +216 -0
  1255. package/src/runtime/routes/http-adapter.ts +172 -0
  1256. package/src/runtime/routes/identity-routes.ts +161 -85
  1257. package/src/runtime/routes/inbound-conversation.ts +11 -18
  1258. package/src/runtime/routes/inbound-message-handler.ts +639 -232
  1259. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +81 -226
  1260. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
  1261. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -90
  1262. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
  1263. package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
  1264. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
  1265. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
  1266. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
  1267. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
  1268. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
  1269. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
  1270. package/src/runtime/routes/index.ts +201 -0
  1271. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
  1272. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
  1273. package/src/runtime/routes/integrations/slack/channel.ts +50 -71
  1274. package/src/runtime/routes/integrations/slack/share.ts +49 -58
  1275. package/src/runtime/routes/integrations/telegram.ts +91 -74
  1276. package/src/runtime/routes/integrations/twilio.ts +163 -240
  1277. package/src/runtime/routes/integrations/vercel.ts +57 -54
  1278. package/src/runtime/routes/interface-routes.ts +43 -0
  1279. package/src/runtime/routes/internal-oauth-routes.ts +56 -0
  1280. package/src/runtime/routes/internal-twilio-routes.ts +46 -0
  1281. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  1282. package/src/runtime/routes/llm-context-normalization.ts +4 -2
  1283. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  1284. package/src/runtime/routes/log-export-routes.ts +90 -100
  1285. package/src/runtime/routes/memory-item-routes.test.ts +152 -175
  1286. package/src/runtime/routes/memory-item-routes.ts +243 -323
  1287. package/src/runtime/routes/memory-v2-routes.ts +188 -0
  1288. package/src/runtime/routes/migration-rollback-routes.ts +167 -212
  1289. package/src/runtime/routes/migration-routes.ts +1037 -377
  1290. package/src/runtime/routes/notification-routes.ts +199 -70
  1291. package/src/runtime/routes/oauth-apps.ts +254 -251
  1292. package/src/runtime/routes/oauth-providers.ts +66 -57
  1293. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +60 -120
  1294. package/src/runtime/routes/playground/__tests__/guard.test.ts +34 -54
  1295. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +107 -151
  1296. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +41 -117
  1297. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +95 -138
  1298. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +115 -217
  1299. package/src/runtime/routes/playground/__tests__/state.test.ts +41 -90
  1300. package/src/runtime/routes/playground/conversation-not-found.ts +9 -11
  1301. package/src/runtime/routes/playground/force-compact.ts +41 -54
  1302. package/src/runtime/routes/playground/guard.ts +18 -19
  1303. package/src/runtime/routes/playground/helpers.ts +103 -0
  1304. package/src/runtime/routes/playground/index.ts +15 -27
  1305. package/src/runtime/routes/playground/inject-failures.ts +48 -64
  1306. package/src/runtime/routes/playground/reset-circuit.ts +31 -57
  1307. package/src/runtime/routes/playground/seed-conversation.ts +66 -92
  1308. package/src/runtime/routes/playground/seeded-conversations.ts +60 -64
  1309. package/src/runtime/routes/playground/state.ts +23 -24
  1310. package/src/runtime/routes/profiler-routes.ts +132 -167
  1311. package/src/runtime/routes/ps-routes.ts +120 -0
  1312. package/src/runtime/routes/recording-routes.ts +189 -270
  1313. package/src/runtime/routes/rename-conversation-routes.ts +85 -0
  1314. package/src/runtime/routes/schedule-routes.ts +239 -246
  1315. package/src/runtime/routes/secret-routes.ts +305 -282
  1316. package/src/runtime/routes/secrets-deps.ts +24 -0
  1317. package/src/runtime/routes/settings-routes.ts +370 -449
  1318. package/src/runtime/routes/skills-routes.ts +417 -471
  1319. package/src/runtime/routes/stt-routes.ts +196 -206
  1320. package/src/runtime/routes/subagents-routes.ts +125 -141
  1321. package/src/runtime/routes/suggest-trust-rule-routes.ts +275 -0
  1322. package/src/runtime/routes/surface-action-routes.ts +135 -190
  1323. package/src/runtime/routes/surface-content-routes.ts +84 -118
  1324. package/src/runtime/routes/task-routes.ts +354 -0
  1325. package/src/runtime/routes/telemetry-routes.ts +33 -49
  1326. package/src/runtime/routes/trace-event-routes.ts +55 -74
  1327. package/src/runtime/routes/trust-rules-routes.ts +61 -244
  1328. package/src/runtime/routes/tts-routes.ts +187 -169
  1329. package/src/runtime/routes/types.ts +139 -0
  1330. package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
  1331. package/src/runtime/routes/upgrade-broadcast-routes.ts +150 -198
  1332. package/src/runtime/routes/usage-routes.ts +222 -171
  1333. package/src/runtime/routes/user-routes.ts +88 -18
  1334. package/src/runtime/routes/wake-conversation-routes.ts +49 -0
  1335. package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
  1336. package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
  1337. package/src/runtime/routes/work-items-routes.test.ts +10 -20
  1338. package/src/runtime/routes/work-items-routes.ts +419 -437
  1339. package/src/runtime/routes/workspace-commit-routes.ts +30 -61
  1340. package/src/runtime/routes/workspace-routes.test.ts +254 -381
  1341. package/src/runtime/routes/workspace-routes.ts +238 -246
  1342. package/src/runtime/runtime-mode.ts +8 -1
  1343. package/src/runtime/services/__tests__/analyze-conversation.test.ts +82 -120
  1344. package/src/runtime/services/analyze-conversation.ts +18 -55
  1345. package/src/runtime/services/conversation-serializer.ts +179 -0
  1346. package/src/runtime/trust-context-resolver.ts +3 -2
  1347. package/src/runtime/verification-outbound-actions.ts +14 -50
  1348. package/src/runtime/verification-rate-limiter.ts +1 -1
  1349. package/src/schedule/schedule-store.ts +64 -18
  1350. package/src/schedule/scheduler.ts +101 -0
  1351. package/src/security/ces-credential-client.ts +32 -169
  1352. package/src/security/ces-rpc-credential-backend.ts +1 -1
  1353. package/src/security/credential-backend.ts +6 -6
  1354. package/src/security/oauth-completion-page.ts +1 -1
  1355. package/src/security/oauth2.ts +3 -6
  1356. package/src/security/secret-scanner.ts +14 -547
  1357. package/src/security/secure-keys.ts +31 -11
  1358. package/src/security/token-manager.ts +7 -3
  1359. package/src/sequence/analytics.ts +1 -1
  1360. package/src/sequence/guardrails.ts +3 -3
  1361. package/src/sequence/store.ts +2 -1
  1362. package/src/signals/bash.ts +1 -1
  1363. package/src/signals/cancel.ts +16 -25
  1364. package/src/signals/conversation-undo.ts +2 -27
  1365. package/src/signals/emit-event.ts +1 -2
  1366. package/src/signals/event-stream.ts +1 -1
  1367. package/src/signals/user-message.ts +108 -22
  1368. package/src/skills/catalog-cache.ts +7 -0
  1369. package/src/skills/catalog-files.ts +0 -5
  1370. package/src/skills/catalog-install.ts +29 -18
  1371. package/src/skills/category-inference.ts +0 -11
  1372. package/src/skills/clawhub.ts +4 -4
  1373. package/src/skills/inline-command-runner.ts +1 -7
  1374. package/src/skills/managed-store.ts +2 -2
  1375. package/src/skills/remote-skill-policy.ts +6 -7
  1376. package/src/subagent/index.ts +2 -6
  1377. package/src/subagent/manager.ts +94 -107
  1378. package/src/subagent/types.ts +9 -0
  1379. package/src/tasks/SPEC.md +2 -2
  1380. package/src/tasks/task-compiler.ts +1 -1
  1381. package/src/tasks/task-runner.ts +2 -22
  1382. package/src/tasks/task-store.ts +2 -29
  1383. package/src/telemetry/types.ts +6 -0
  1384. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  1385. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  1386. package/src/tools/acp/list-agents.test.ts +115 -0
  1387. package/src/tools/acp/list-agents.ts +31 -0
  1388. package/src/tools/acp/spawn.test.ts +378 -0
  1389. package/src/tools/acp/spawn.ts +142 -62
  1390. package/src/tools/acp/steer.test.ts +100 -0
  1391. package/src/tools/acp/steer.ts +38 -0
  1392. package/src/tools/background-tool-registry.ts +98 -0
  1393. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  1394. package/src/tools/browser/browser-execution.ts +38 -127
  1395. package/src/tools/browser/browser-manager.ts +1 -8
  1396. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  1397. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
  1398. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
  1399. package/src/tools/browser/cdp-client/factory.ts +48 -76
  1400. package/src/tools/browser/cdp-client/index.ts +1 -14
  1401. package/src/tools/browser/cdp-client/types.ts +4 -1
  1402. package/src/tools/computer-use/definitions.ts +1 -1
  1403. package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
  1404. package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
  1405. package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
  1406. package/src/tools/credentials/broker-types.ts +2 -1
  1407. package/src/tools/document/editor-template.ts +1 -1
  1408. package/src/tools/execution-timeout.ts +1 -1
  1409. package/src/tools/executor.ts +53 -45
  1410. package/src/tools/host-filesystem/edit.ts +3 -2
  1411. package/src/tools/host-filesystem/read.ts +3 -2
  1412. package/src/tools/host-filesystem/transfer.test.ts +271 -0
  1413. package/src/tools/host-filesystem/transfer.ts +235 -0
  1414. package/src/tools/host-filesystem/write.ts +3 -2
  1415. package/src/tools/host-terminal/host-shell.ts +192 -13
  1416. package/src/tools/mcp/mcp-tool-factory.ts +1 -1
  1417. package/src/tools/memory/register.test.ts +161 -1
  1418. package/src/tools/memory/register.ts +19 -34
  1419. package/src/tools/network/script-proxy/index.ts +1 -10
  1420. package/src/tools/permission-checker.ts +84 -220
  1421. package/src/tools/policy-context.ts +1 -8
  1422. package/src/tools/registry.ts +16 -1
  1423. package/src/tools/shared/shell-output.ts +4 -1
  1424. package/src/tools/side-effects.ts +2 -2
  1425. package/src/tools/skills/execute.ts +1 -1
  1426. package/src/tools/skills/sandbox-runner.ts +1 -6
  1427. package/src/tools/skills/skill-tool-factory.ts +32 -0
  1428. package/src/tools/subagent/spawn.ts +35 -11
  1429. package/src/tools/terminal/safe-env.ts +10 -1
  1430. package/src/tools/terminal/shell.ts +142 -88
  1431. package/src/tools/tool-approval-handler.ts +4 -70
  1432. package/src/tools/tool-input-summary.ts +10 -0
  1433. package/src/tools/types.ts +136 -183
  1434. package/src/tools/ui-surface/definitions.ts +2 -2
  1435. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  1436. package/src/tts/provider-catalog.ts +1 -1
  1437. package/src/usage/actors.ts +2 -1
  1438. package/src/usage/attribution.ts +185 -0
  1439. package/src/usage/pricing.ts +166 -0
  1440. package/src/usage/types.ts +14 -0
  1441. package/src/util/debounce.ts +0 -21
  1442. package/src/util/errors.ts +0 -8
  1443. package/src/util/json.ts +13 -0
  1444. package/src/util/log-redact.ts +0 -1
  1445. package/src/util/logger.ts +3 -3
  1446. package/src/util/platform.ts +85 -124
  1447. package/src/util/pricing.ts +158 -8
  1448. package/src/watcher/engine.ts +42 -20
  1449. package/src/watcher/watcher-store.ts +2 -1
  1450. package/src/work-items/work-item-runner.ts +15 -42
  1451. package/src/work-items/work-item-store.ts +1 -1
  1452. package/src/workspace/git-service.ts +1 -6
  1453. package/src/workspace/migrations/006-services-config.ts +10 -1
  1454. package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
  1455. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
  1456. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
  1457. package/src/workspace/migrations/031-drop-user-md.ts +1 -1
  1458. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
  1459. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  1460. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
  1461. package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
  1462. package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
  1463. package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
  1464. package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
  1465. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
  1466. package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
  1467. package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
  1468. package/src/workspace/migrations/060-memory-v2-init.ts +37 -0
  1469. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  1470. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  1471. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  1472. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  1473. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
  1474. package/src/workspace/migrations/registry.ts +26 -0
  1475. package/src/workspace/migrations/runner.ts +2 -2
  1476. package/src/workspace/provider-commit-message-generator.ts +4 -4
  1477. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  1478. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  1479. package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
  1480. package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
  1481. package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
  1482. package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
  1483. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
  1484. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
  1485. package/src/__tests__/ephemeral-permissions.test.ts +0 -474
  1486. package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
  1487. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
  1488. package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
  1489. package/src/__tests__/pairing-concurrent.test.ts +0 -84
  1490. package/src/__tests__/pairing-routes.test.ts +0 -181
  1491. package/src/__tests__/parser.test.ts +0 -595
  1492. package/src/__tests__/permission-checker-host-gate.test.ts +0 -488
  1493. package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
  1494. package/src/__tests__/permission-mode.test.ts +0 -89
  1495. package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
  1496. package/src/__tests__/risk-classifier-parity.test.ts +0 -230
  1497. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  1498. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  1499. package/src/__tests__/secret-detection-handler.test.ts +0 -74
  1500. package/src/__tests__/secret-scanner-executor.test.ts +0 -451
  1501. package/src/__tests__/shell-identity.test.ts +0 -236
  1502. package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
  1503. package/src/__tests__/shell-parser-property.test.ts +0 -936
  1504. package/src/__tests__/starter-bundle.test.ts +0 -173
  1505. package/src/__tests__/stt-catalog-parity.test.ts +0 -282
  1506. package/src/__tests__/task-runner.test.ts +0 -224
  1507. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  1508. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  1509. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -354
  1510. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  1511. package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
  1512. package/src/__tests__/trust-store.test.ts +0 -2013
  1513. package/src/__tests__/v2-consent-policy.test.ts +0 -103
  1514. package/src/browser/identifiers.ts +0 -51
  1515. package/src/cli/db.ts +0 -1
  1516. package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
  1517. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
  1518. package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
  1519. package/src/context/__tests__/microcompact.test.ts +0 -805
  1520. package/src/context/microcompact.ts +0 -443
  1521. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
  1522. package/src/daemon/approved-devices-store.ts +0 -110
  1523. package/src/daemon/external-skills-bootstrap.ts +0 -41
  1524. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  1525. package/src/daemon/message-types/trust.ts +0 -71
  1526. package/src/daemon/pairing-store.ts +0 -229
  1527. package/src/events/tool-notification-listener.ts +0 -17
  1528. package/src/ipc/cli-server.ts +0 -252
  1529. package/src/ipc/routes/attachment.ts +0 -114
  1530. package/src/ipc/routes/browser-context.ts +0 -63
  1531. package/src/ipc/routes/browser.ts +0 -97
  1532. package/src/ipc/routes/cache.ts +0 -96
  1533. package/src/ipc/routes/get-contact.ts +0 -16
  1534. package/src/ipc/routes/index.ts +0 -35
  1535. package/src/ipc/routes/list-clients.ts +0 -31
  1536. package/src/ipc/routes/merge-contacts.ts +0 -17
  1537. package/src/ipc/routes/notification.ts +0 -133
  1538. package/src/ipc/routes/rename-conversation.ts +0 -59
  1539. package/src/ipc/routes/search-contacts.ts +0 -19
  1540. package/src/ipc/routes/task-queue.ts +0 -226
  1541. package/src/ipc/routes/task.ts +0 -173
  1542. package/src/ipc/routes/upsert-contact.ts +0 -25
  1543. package/src/ipc/routes/wake-conversation.ts +0 -19
  1544. package/src/memory/db.ts +0 -23
  1545. package/src/permissions/arg-parser.test.ts +0 -161
  1546. package/src/permissions/arg-parser.ts +0 -141
  1547. package/src/permissions/bash-risk-classifier.test.ts +0 -1620
  1548. package/src/permissions/bash-risk-classifier.ts +0 -950
  1549. package/src/permissions/command-registry.test.ts +0 -774
  1550. package/src/permissions/command-registry.ts +0 -1005
  1551. package/src/permissions/defaults.ts +0 -314
  1552. package/src/permissions/file-risk-classifier.test.ts +0 -535
  1553. package/src/permissions/file-risk-classifier.ts +0 -274
  1554. package/src/permissions/permission-mode.ts +0 -24
  1555. package/src/permissions/schedule-risk-classifier.test.ts +0 -129
  1556. package/src/permissions/schedule-risk-classifier.ts +0 -85
  1557. package/src/permissions/shell-identity.ts +0 -297
  1558. package/src/permissions/skill-risk-classifier.test.ts +0 -311
  1559. package/src/permissions/skill-risk-classifier.ts +0 -214
  1560. package/src/permissions/trust-client.ts +0 -359
  1561. package/src/permissions/trust-store-interface.ts +0 -100
  1562. package/src/permissions/trust-store.ts +0 -1330
  1563. package/src/permissions/v2-consent-policy.ts +0 -87
  1564. package/src/permissions/web-risk-classifier.test.ts +0 -170
  1565. package/src/permissions/web-risk-classifier.ts +0 -89
  1566. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
  1567. package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
  1568. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  1569. package/src/runtime/__tests__/client-registry.test.ts +0 -293
  1570. package/src/runtime/actor-refresh-token-store.ts +0 -156
  1571. package/src/runtime/actor-token-store.ts +0 -207
  1572. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
  1573. package/src/runtime/auth/credential-service.ts +0 -352
  1574. package/src/runtime/chrome-extension-registry.ts +0 -368
  1575. package/src/runtime/client-registry.ts +0 -261
  1576. package/src/runtime/conversation-approval-overrides.ts +0 -86
  1577. package/src/runtime/routes/browser-extension-pair-routes.ts +0 -575
  1578. package/src/runtime/routes/channel-routes.ts +0 -112
  1579. package/src/runtime/routes/contact-routes.test.ts +0 -298
  1580. package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
  1581. package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
  1582. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -336
  1583. package/src/runtime/routes/invite-routes.ts +0 -280
  1584. package/src/runtime/routes/pairing-routes.ts +0 -431
  1585. package/src/runtime/routes/playground/deps.ts +0 -56
  1586. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
  1587. package/src/runtime/services/analyze-deps-singleton.ts +0 -32
  1588. package/src/tasks/ephemeral-permissions.ts +0 -55
  1589. package/src/tools/secret-detection-handler.ts +0 -359
  1590. package/src/tools/terminal/backends/native.ts +0 -327
  1591. package/src/tools/terminal/backends/types.ts +0 -37
  1592. package/src/tools/terminal/parser.ts +0 -623
  1593. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  1594. package/src/tools/terminal/sandbox.ts +0 -40
  1595. package/src/types/qrcode.d.ts +0 -13
  1596. package/src/util/network-info.ts +0 -55
  1597. /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
  1598. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  1599. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  1600. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  1601. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  1602. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  1603. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
@@ -12,9 +12,14 @@ import {
12
12
  parseInterfaceId,
13
13
  } from "../../channels/types.js";
14
14
  import { touchContactInteraction } from "../../contacts/contacts-write.js";
15
- import type { TrustContext } from "../../daemon/conversation-runtime-assembly.js";
16
- import type { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
17
- import * as attachmentsStore from "../../memory/attachments-store.js";
15
+ import {
16
+ createApprovalConversationGenerator,
17
+ createApprovalCopyGenerator,
18
+ } from "../../daemon/approval-generators.js";
19
+ import { processMessage } from "../../daemon/process-message.js";
20
+ import type { TrustContext } from "../../daemon/trust-context.js";
21
+ import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
22
+ import { getAttachmentsByIds } from "../../memory/attachments-store.js";
18
23
  import {
19
24
  recordConversationSeenSignal,
20
25
  type SignalType,
@@ -26,18 +31,27 @@ import {
26
31
  selectSlackMetaCandidateMetadata,
27
32
  updateMessageMetadata,
28
33
  } from "../../memory/conversation-crud.js";
29
- import * as deliveryChannels from "../../memory/delivery-channels.js";
30
- import * as deliveryCrud from "../../memory/delivery-crud.js";
31
- import * as deliveryStatus from "../../memory/delivery-status.js";
32
- import * as externalConversationStore from "../../memory/external-conversation-store.js";
34
+ import {
35
+ clearPendingVerificationReply,
36
+ getPendingVerificationReply,
37
+ } from "../../memory/delivery-channels.js";
38
+ import {
39
+ findMessageBySourceId,
40
+ linkMessage,
41
+ recordInbound,
42
+ } from "../../memory/delivery-crud.js";
43
+ import { markProcessed } from "../../memory/delivery-status.js";
44
+ import { upsertBinding } from "../../memory/external-conversation-store.js";
33
45
  import type { Message as ProviderMessage } from "../../messaging/provider-types.js";
34
46
  import {
35
47
  backfillDm,
36
- backfillThread,
48
+ backfillThreadWindowPage,
49
+ type SlackBackfillWindowPage,
37
50
  } from "../../messaging/providers/slack/backfill.js";
38
51
  import {
39
52
  mergeSlackMetadata,
40
53
  readSlackMetadata,
54
+ type SlackFileMetadata,
41
55
  type SlackMessageMetadata,
42
56
  writeSlackMetadata,
43
57
  } from "../../messaging/providers/slack/message-metadata.js";
@@ -45,18 +59,10 @@ import { wrapUntrustedContent } from "../../security/untrusted-content.js";
45
59
  import { canonicalizeInboundIdentity } from "../../util/canonicalize-identity.js";
46
60
  import { getLogger } from "../../util/logger.js";
47
61
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
48
- import { mintDaemonDeliveryToken } from "../auth/token-service.js";
49
62
  import { deliverChannelReply } from "../gateway-client.js";
50
- import { httpError } from "../http-errors.js";
51
- import type {
52
- ApprovalConversationGenerator,
53
- ApprovalCopyGenerator,
54
- GuardianActionCopyGenerator,
55
- GuardianFollowUpConversationGenerator,
56
- MessageProcessor,
57
- } from "../http-types.js";
58
63
  import { resolveTrustContext } from "../trust-context-resolver.js";
59
64
  import { canonicalChannelAssistantId } from "./channel-route-shared.js";
65
+ import { BadRequestError } from "./errors.js";
60
66
  import { handleApprovalInterception } from "./guardian-approval-interception.js";
61
67
  import { enforceIngressAcl } from "./inbound-stages/acl-enforcement.js";
62
68
  import { processChannelMessageInBackground } from "./inbound-stages/background-dispatch.js";
@@ -67,7 +73,7 @@ import { handleGuardianActivationIntercept } from "./inbound-stages/guardian-act
67
73
  import { handleGuardianReplyIntercept } from "./inbound-stages/guardian-reply-intercept.js";
68
74
  import { runSecretIngressCheck } from "./inbound-stages/secret-ingress-check.js";
69
75
  import { tryTranscribeAudioAttachments } from "./inbound-stages/transcribe-audio.js";
70
- import { handleVerificationIntercept } from "./inbound-stages/verification-intercept.js";
76
+ import type { RouteHandlerArgs } from "./types.js";
71
77
 
72
78
  const log = getLogger("runtime-http");
73
79
 
@@ -93,28 +99,19 @@ export function _setDeleteLookupConfigForTests(
93
99
  deleteLookupDelayMs = delayMs;
94
100
  }
95
101
 
96
- export async function handleChannelInbound(
97
- req: Request,
98
- processMessage?: MessageProcessor,
99
- assistantId: string = DAEMON_INTERNAL_ASSISTANT_ID,
100
- approvalCopyGenerator?: ApprovalCopyGenerator,
101
- approvalConversationGenerator?: ApprovalConversationGenerator,
102
- _guardianActionCopyGenerator?: GuardianActionCopyGenerator,
103
- _guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator,
104
- heartbeatService?: HeartbeatService,
105
- ): Promise<Response> {
102
+ export async function handleChannelInbound({
103
+ body: rawBody = {},
104
+ }: RouteHandlerArgs) {
106
105
  // Gateway-origin proof is enforced by route-policy middleware (svc_gateway
107
106
  // principal type required) before this handler runs. The exchange JWT
108
107
  // itself proves gateway origin.
109
108
 
110
- // Factory that mints a fresh short-lived JWT for each daemon-to-gateway
111
- // delivery callback. The JWT has a 60-second TTL, so long-running
112
- // background operations (typing heartbeats, approval watchers, reply
113
- // delivery) must call this at each delivery attempt rather than reusing
114
- // a single token from request start.
115
- const mintBearerToken = (): string => mintDaemonDeliveryToken();
109
+ const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
110
+ const approvalCopyGenerator = createApprovalCopyGenerator();
111
+ const approvalConversationGenerator = createApprovalConversationGenerator();
112
+ const heartbeatService = HeartbeatService.getInstance();
116
113
 
117
- const body = (await req.json()) as {
114
+ const body = rawBody as {
118
115
  sourceChannel?: string;
119
116
  interface?: string;
120
117
  conversationExternalId?: string;
@@ -141,53 +138,49 @@ export async function handleChannelInbound(
141
138
  } = body;
142
139
 
143
140
  if (!body.sourceChannel || typeof body.sourceChannel !== "string") {
144
- return httpError("BAD_REQUEST", "sourceChannel is required", 400);
141
+ throw new BadRequestError("sourceChannel is required");
145
142
  }
146
143
  // Validate and narrow to canonical ChannelId at the boundary — the gateway
147
144
  // only sends well-known channel strings, so an unknown value is rejected.
148
145
  if (!isChannelId(body.sourceChannel)) {
149
- return httpError(
150
- "BAD_REQUEST",
146
+ throw new BadRequestError(
151
147
  `Invalid sourceChannel: ${
152
148
  body.sourceChannel
153
149
  }. Valid values: ${CHANNEL_IDS.join(", ")}`,
154
- 400,
155
150
  );
156
151
  }
157
152
 
158
153
  const sourceChannel = body.sourceChannel;
159
154
 
160
155
  if (!body.interface || typeof body.interface !== "string") {
161
- return httpError("BAD_REQUEST", "interface is required", 400);
156
+ throw new BadRequestError("interface is required");
162
157
  }
163
158
  const sourceInterface = parseInterfaceId(body.interface);
164
159
  if (!sourceInterface) {
165
- return httpError(
166
- "BAD_REQUEST",
160
+ throw new BadRequestError(
167
161
  `Invalid interface: ${body.interface}. Valid values: ${INTERFACE_IDS.join(
168
162
  ", ",
169
163
  )}`,
170
- 400,
171
164
  );
172
165
  }
173
166
 
174
167
  if (!conversationExternalId || typeof conversationExternalId !== "string") {
175
- return httpError("BAD_REQUEST", "conversationExternalId is required", 400);
168
+ throw new BadRequestError("conversationExternalId is required");
176
169
  }
177
170
  if (
178
171
  !body.actorExternalId ||
179
172
  typeof body.actorExternalId !== "string" ||
180
173
  !body.actorExternalId.trim()
181
174
  ) {
182
- return httpError("BAD_REQUEST", "actorExternalId is required", 400);
175
+ throw new BadRequestError("actorExternalId is required");
183
176
  }
184
177
  if (!externalMessageId || typeof externalMessageId !== "string") {
185
- return httpError("BAD_REQUEST", "externalMessageId is required", 400);
178
+ throw new BadRequestError("externalMessageId is required");
186
179
  }
187
180
 
188
181
  // Reject non-string content regardless of whether attachments are present.
189
182
  if (content != null && typeof content !== "string") {
190
- return httpError("BAD_REQUEST", "content must be a string", 400);
183
+ throw new BadRequestError("content must be a string");
191
184
  }
192
185
 
193
186
  let trimmedContent = typeof content === "string" ? content.trim() : "";
@@ -203,11 +196,7 @@ export async function handleChannelInbound(
203
196
  !isEdit &&
204
197
  !hasCallbackData
205
198
  ) {
206
- return httpError(
207
- "BAD_REQUEST",
208
- "content or attachmentIds is required",
209
- 400,
210
- );
199
+ throw new BadRequestError("content or attachmentIds is required");
211
200
  }
212
201
 
213
202
  // Canonicalize the assistant ID so all DB-facing operations use the
@@ -253,7 +242,6 @@ export async function handleChannelInbound(
253
242
  actorUsername: body.actorUsername,
254
243
  sourceMetadata: body.sourceMetadata,
255
244
  replyCallbackUrl: body.replyCallbackUrl,
256
- mintBearerToken,
257
245
  assistantId,
258
246
  externalMessageId,
259
247
  });
@@ -272,12 +260,11 @@ export async function handleChannelInbound(
272
260
  actorDisplayName: body.actorDisplayName,
273
261
  actorUsername: body.actorUsername,
274
262
  replyCallbackUrl: body.replyCallbackUrl,
275
- mintBearerToken,
276
263
  assistantId,
277
264
  externalMessageId,
278
265
  });
279
266
  if (aclResult.earlyResponse) return aclResult.earlyResponse;
280
- const { resolvedMember, guardianVerifyCode } = aclResult;
267
+ const { resolvedMember } = aclResult;
281
268
 
282
269
  // ── Slack delete propagation ──
283
270
  // Slack message_deleted events are forwarded by the gateway with the
@@ -300,7 +287,7 @@ export async function handleChannelInbound(
300
287
  { conversationExternalId },
301
288
  "Slack message_deleted event missing sourceMetadata.messageId; ignoring",
302
289
  );
303
- return Response.json({ accepted: true, deleted: false });
290
+ return { accepted: true, deleted: false };
304
291
  }
305
292
 
306
293
  // Look up the stored message via the existing channel-event lookup.
@@ -314,7 +301,7 @@ export async function handleChannelInbound(
314
301
  // that window is silently dropped and the deletion signal is lost.
315
302
  let original: { messageId: string; conversationId: string } | null = null;
316
303
  for (let attempt = 0; attempt <= deleteLookupRetries; attempt++) {
317
- original = deliveryCrud.findMessageBySourceId(
304
+ original = findMessageBySourceId(
318
305
  sourceChannel,
319
306
  conversationExternalId,
320
307
  deletedMessageTs,
@@ -341,7 +328,7 @@ export async function handleChannelInbound(
341
328
  { conversationExternalId, deletedMessageTs },
342
329
  "No stored message found for Slack delete after retries; ignoring",
343
330
  );
344
- return Response.json({ accepted: true, deleted: false });
331
+ return { accepted: true, deleted: false };
345
332
  }
346
333
 
347
334
  // Merge deletedAt into the existing slackMeta sub-key. If the row has
@@ -359,7 +346,7 @@ export async function handleChannelInbound(
359
346
  },
360
347
  "Stored Slack message has no metadata; skipping delete marker",
361
348
  );
362
- return Response.json({ accepted: true, deleted: false });
349
+ return { accepted: true, deleted: false };
363
350
  }
364
351
 
365
352
  let parentMetadata: Record<string, unknown>;
@@ -379,7 +366,7 @@ export async function handleChannelInbound(
379
366
  },
380
367
  "Failed to parse stored metadata; skipping delete marker",
381
368
  );
382
- return Response.json({ accepted: true, deleted: false });
369
+ return { accepted: true, deleted: false };
383
370
  }
384
371
 
385
372
  const existingSlackMeta =
@@ -396,7 +383,7 @@ export async function handleChannelInbound(
396
383
  },
397
384
  "Stored Slack message has no slackMeta; skipping delete marker",
398
385
  );
399
- return Response.json({ accepted: true, deleted: false });
386
+ return { accepted: true, deleted: false };
400
387
  }
401
388
 
402
389
  const updatedSlackMeta = mergeSlackMetadata(existingSlackMeta, {
@@ -418,21 +405,20 @@ export async function handleChannelInbound(
418
405
  "Marked Slack message as deleted",
419
406
  );
420
407
 
421
- return Response.json({
408
+ return {
422
409
  accepted: true,
423
410
  deleted: true,
424
411
  messageId: original.messageId,
425
- });
412
+ };
426
413
  }
427
414
 
428
415
  if (hasAttachments) {
429
- const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds);
416
+ const resolved = getAttachmentsByIds(attachmentIds);
430
417
  if (resolved.length !== attachmentIds.length) {
431
418
  const resolvedIds = new Set(resolved.map((a) => a.id));
432
419
  const missing = attachmentIds.filter((id) => !resolvedIds.has(id));
433
- return Response.json(
434
- { error: `Attachment IDs not found: ${missing.join(", ")}` },
435
- { status: 400 },
420
+ throw new BadRequestError(
421
+ `Attachment IDs not found: ${missing.join(", ")}`,
436
422
  );
437
423
  }
438
424
  }
@@ -466,11 +452,7 @@ export async function handleChannelInbound(
466
452
  : undefined;
467
453
 
468
454
  if (isEdit && !sourceMessageId) {
469
- return httpError(
470
- "BAD_REQUEST",
471
- "sourceMetadata.messageId is required for edits",
472
- 400,
473
- );
455
+ throw new BadRequestError("sourceMetadata.messageId is required for edits");
474
456
  }
475
457
 
476
458
  // ── Edit path: update existing message content, no new agent loop ──
@@ -488,7 +470,7 @@ export async function handleChannelInbound(
488
470
  }
489
471
 
490
472
  // ── New message path ──
491
- const result = deliveryCrud.recordInbound(
473
+ const result = recordInbound(
492
474
  sourceChannel,
493
475
  conversationExternalId,
494
476
  externalMessageId,
@@ -502,21 +484,15 @@ export async function handleChannelInbound(
502
484
  // gateway retries (duplicates) re-attempt delivery here. On success the
503
485
  // pending marker is cleared so further duplicates short-circuit normally.
504
486
  if (result.duplicate && replyCallbackUrl) {
505
- const pendingReply = deliveryChannels.getPendingVerificationReply(
506
- result.eventId,
507
- );
487
+ const pendingReply = getPendingVerificationReply(result.eventId);
508
488
  if (pendingReply) {
509
489
  try {
510
- await deliverChannelReply(
511
- replyCallbackUrl,
512
- {
513
- chatId: pendingReply.chatId,
514
- text: pendingReply.text,
515
- assistantId: pendingReply.assistantId,
516
- },
517
- mintBearerToken(),
518
- );
519
- deliveryChannels.clearPendingVerificationReply(result.eventId);
490
+ await deliverChannelReply(replyCallbackUrl, {
491
+ chatId: pendingReply.chatId,
492
+ text: pendingReply.text,
493
+ assistantId: pendingReply.assistantId,
494
+ });
495
+ clearPendingVerificationReply(result.eventId);
520
496
  log.info(
521
497
  { eventId: result.eventId },
522
498
  "Retried pending verification reply: delivered",
@@ -527,11 +503,11 @@ export async function handleChannelInbound(
527
503
  "Retry of pending verification reply failed; will retry on next duplicate",
528
504
  );
529
505
  }
530
- return Response.json({
506
+ return {
531
507
  accepted: true,
532
508
  duplicate: true,
533
509
  eventId: result.eventId,
534
- });
510
+ };
535
511
  }
536
512
  }
537
513
 
@@ -546,7 +522,7 @@ export async function handleChannelInbound(
546
522
  // self so assistant-scoped legacy routes do not overwrite each other's
547
523
  // channel binding metadata for the same chat.
548
524
  if (canonicalAssistantId === DAEMON_INTERNAL_ASSISTANT_ID) {
549
- externalConversationStore.upsertBinding({
525
+ upsertBinding({
550
526
  conversationId: result.conversationId,
551
527
  sourceChannel,
552
528
  externalChatId: conversationExternalId,
@@ -568,10 +544,10 @@ export async function handleChannelInbound(
568
544
  // guardian approval reactions have no transcript representation.
569
545
  // 2. All other reactions (non-guardian, no pending approval, stale,
570
546
  // and any `reaction_removed:` event regardless of actor) fall
571
- // through to `persistSlackReactionAsMessage` so the chronological
572
- // renderer (PR 18) can surface them inline. Reactions never
573
- // trigger an agent response, so we short-circuit before
574
- // escalation and agent-loop dispatch in both cases.
547
+ // through to `persistSlackReactionAsMessage` so Slack transcript
548
+ // rendering can surface them inline. Reactions never trigger an
549
+ // agent response, so we short-circuit before escalation and
550
+ // agent-loop dispatch in both cases.
575
551
  if (isSlackReactionEvent(body)) {
576
552
  // Approval interception runs only for reactions (added) — `reaction_removed`
577
553
  // never expresses an approval intent, so un-reacting is left as a pure
@@ -601,7 +577,6 @@ export async function handleChannelInbound(
601
577
  sourceChannel,
602
578
  actorExternalId: canonicalSenderId ?? rawSenderId,
603
579
  replyCallbackUrl,
604
- bearerToken: mintBearerToken(),
605
580
  trustCtx: trustCtxForReaction,
606
581
  assistantId: canonicalAssistantId,
607
582
  approvalCopyGenerator,
@@ -614,12 +589,12 @@ export async function handleChannelInbound(
614
589
  // transcript line. All other interception outcomes (stale_ignored,
615
590
  // non-guardian, no pending approval) fall through to persistence.
616
591
  if (reactionApprovalResult.type === "guardian_decision_applied") {
617
- return Response.json({
592
+ return {
618
593
  accepted: true,
619
594
  duplicate: false,
620
595
  eventId: result.eventId,
621
596
  approval: reactionApprovalResult.type,
622
- });
597
+ };
623
598
  }
624
599
  }
625
600
 
@@ -632,11 +607,11 @@ export async function handleChannelInbound(
632
607
  { conversationId: result.conversationId, eventId: result.eventId },
633
608
  "Skipping reaction persistence: missing sourceMetadata.messageId",
634
609
  );
635
- return Response.json({
610
+ return {
636
611
  accepted: result.accepted,
637
612
  duplicate: result.duplicate,
638
613
  eventId: result.eventId,
639
- });
614
+ };
640
615
  }
641
616
 
642
617
  const threadTs =
@@ -662,11 +637,11 @@ export async function handleChannelInbound(
662
637
  );
663
638
  }
664
639
 
665
- return Response.json({
640
+ return {
666
641
  accepted: result.accepted,
667
642
  duplicate: result.duplicate,
668
643
  eventId: result.eventId,
669
- });
644
+ };
670
645
  }
671
646
 
672
647
  // ── Ingress escalation ──
@@ -698,6 +673,7 @@ export async function handleChannelInbound(
698
673
  typeof hint === "string" && hint.trim().length > 0,
699
674
  )
700
675
  : [];
676
+ let slackRuntimeContextNotice: string | undefined;
701
677
 
702
678
  // Inject channel-scoped permission hints for Slack channel messages
703
679
  if (sourceChannel === "slack") {
@@ -762,25 +738,6 @@ export async function handleChannelInbound(
762
738
  });
763
739
  if (bootstrapResponse) return bootstrapResponse;
764
740
 
765
- // ── Guardian verification code intercept (deterministic) ──
766
- const verificationResponse = await handleVerificationIntercept({
767
- isDuplicate: result.duplicate,
768
- guardianVerifyCode,
769
- rawSenderId,
770
- canonicalSenderId,
771
- canonicalAssistantId,
772
- sourceChannel,
773
- conversationExternalId,
774
- conversationId: result.conversationId,
775
- eventId: result.eventId,
776
- replyCallbackUrl,
777
- mintBearerToken,
778
- assistantId,
779
- actorDisplayName: body.actorDisplayName,
780
- actorUsername: body.actorUsername,
781
- });
782
- if (verificationResponse) return verificationResponse;
783
-
784
741
  // Legacy voice guardian action interception removed — all guardian reply
785
742
  // routing now flows through the canonical router below (routeGuardianReply),
786
743
  // which handles request code matching, callback parsing, and NL classification
@@ -812,7 +769,6 @@ export async function handleChannelInbound(
812
769
  conversationId: result.conversationId,
813
770
  eventId: result.eventId,
814
771
  replyCallbackUrl,
815
- mintBearerToken,
816
772
  trustClass: trustCtx.trustClass,
817
773
  guardianPrincipalId: trustCtx.guardianPrincipalId,
818
774
  approvalConversationGenerator,
@@ -846,7 +802,6 @@ export async function handleChannelInbound(
846
802
  sourceChannel,
847
803
  actorExternalId: canonicalSenderId ?? rawSenderId,
848
804
  replyCallbackUrl,
849
- bearerToken: mintBearerToken(),
850
805
  trustCtx,
851
806
  assistantId: canonicalAssistantId,
852
807
  approvalCopyGenerator,
@@ -893,12 +848,12 @@ export async function handleChannelInbound(
893
848
  }
894
849
  }
895
850
 
896
- return Response.json({
851
+ return {
897
852
  accepted: true,
898
853
  duplicate: false,
899
854
  eventId: result.eventId,
900
855
  approval: approvalResult.type,
901
- });
856
+ };
902
857
  }
903
858
 
904
859
  // When a callback payload was not handled by approval interception, it's
@@ -940,16 +895,12 @@ export async function handleChannelInbound(
940
895
  // and deliver an ephemeral error so the user gets visible feedback
941
896
  // instead of a silent no-op (JARVIS-299).
942
897
  if (sourceChannel === "slack" && replyCallbackUrl && approvalMessageTs) {
943
- deliverChannelReply(
944
- replyCallbackUrl,
945
- {
946
- chatId: conversationExternalId,
947
- text: "This approval request has been resolved.",
948
- messageTs: approvalMessageTs,
949
- assistantId: canonicalAssistantId,
950
- },
951
- mintBearerToken(),
952
- ).catch((err) => {
898
+ deliverChannelReply(replyCallbackUrl, {
899
+ chatId: conversationExternalId,
900
+ text: "This approval request has been resolved.",
901
+ messageTs: approvalMessageTs,
902
+ assistantId: canonicalAssistantId,
903
+ }).catch((err) => {
953
904
  log.error(
954
905
  { err, conversationId: result.conversationId },
955
906
  "Failed to edit stale Slack approval message",
@@ -957,18 +908,18 @@ export async function handleChannelInbound(
957
908
  });
958
909
  }
959
910
 
960
- return Response.json({
911
+ return {
961
912
  accepted: true,
962
913
  duplicate: false,
963
914
  eventId: result.eventId,
964
915
  approval: "stale_ignored",
965
- });
916
+ };
966
917
  }
967
918
  }
968
919
 
969
920
  // For new (non-duplicate) messages, run the secret ingress check
970
921
  // synchronously, then fire off the agent loop in the background.
971
- if (!result.duplicate && processMessage) {
922
+ if (!result.duplicate) {
972
923
  const ingressResult = runSecretIngressCheck({
973
924
  eventId: result.eventId,
974
925
  sourceChannel,
@@ -989,7 +940,7 @@ export async function handleChannelInbound(
989
940
 
990
941
  if (ingressResult.blocked) {
991
942
  // Intentional block — mark the event as processed (not failed/dead-lettered).
992
- deliveryStatus.markProcessed(result.eventId);
943
+ markProcessed(result.eventId);
993
944
  log.info(
994
945
  {
995
946
  eventId: result.eventId,
@@ -1067,25 +1018,27 @@ export async function handleChannelInbound(
1067
1018
  });
1068
1019
  }
1069
1020
 
1070
- // ── Thread-ancestor backfill ──
1071
- // When a Slack reply arrives for a thread the daemon never saw the
1072
- // parent of, fetch the thread's recent history from Slack and persist
1073
- // the missing messages so the chronological renderer (PR 18) has the
1074
- // full conversation. Awaited (mirrors the DM cold-start path above)
1075
- // so the agent loop dispatched immediately afterwards observes the
1076
- // backfilled parent without this, `loadSlackChronologicalMessages`
1077
- // can race the persist and miss thread context. Backfill is bounded
1078
- // (parent + ~50 messages) and the agent latency is dominated by the
1079
- // LLM call, so the added latency is negligible. Failures are
1080
- // swallowed inside the helper so they never block dispatch.
1021
+ // ── Thread gap/delta backfill ──
1022
+ // When a Slack thread reply arrives, compare the stored thread state
1023
+ // with the inbound message's ts and fetch only the bounded unseen
1024
+ // window. Initial late-join turns hydrate the earliest thread messages
1025
+ // plus a recent window adjacent to the inbound reply; later turns use
1026
+ // a delta window after the latest stored thread ts and before the
1027
+ // inbound ts. Awaited (mirrors the DM cold-start path above) so the
1028
+ // agent loop dispatched immediately afterwards observes hydrated
1029
+ // context. A late-join notice is added only to the current turn's
1030
+ // runtime context, not persisted as durable Slack metadata. Failures
1031
+ // are swallowed inside the helper so they never block dispatch.
1081
1032
  if (slackThreadTs) {
1082
- await triggerSlackThreadBackfillIfNeeded({
1033
+ const backfillResult = await triggerSlackThreadBackfillIfNeeded({
1083
1034
  conversationId: result.conversationId,
1084
1035
  channelId: conversationExternalId,
1085
1036
  threadTs: slackThreadTs,
1086
1037
  excludeChannelTs: slackInbound?.channelTs,
1087
1038
  account: slackAccount,
1088
1039
  });
1040
+ const lateJoinNotice = buildSlackLateJoinNotice(backfillResult);
1041
+ if (lateJoinNotice) slackRuntimeContextNotice = lateJoinNotice;
1089
1042
  }
1090
1043
 
1091
1044
  // Wrap non-guardian inbound content in external_content boundaries so
@@ -1113,11 +1066,11 @@ export async function handleChannelInbound(
1113
1066
  externalChatId: conversationExternalId,
1114
1067
  trustCtx,
1115
1068
  metadataHints,
1069
+ slackRuntimeContextNotice,
1116
1070
  metadataUxBrief,
1117
1071
  commandIntent,
1118
1072
  sourceLanguageCode,
1119
1073
  replyCallbackUrl,
1120
- mintBearerToken,
1121
1074
  assistantId: canonicalAssistantId,
1122
1075
  approvalCopyGenerator,
1123
1076
  chatType: sourceChatType,
@@ -1126,11 +1079,11 @@ export async function handleChannelInbound(
1126
1079
  }
1127
1080
  }
1128
1081
 
1129
- return Response.json({
1082
+ return {
1130
1083
  accepted: result.accepted,
1131
1084
  duplicate: result.duplicate,
1132
1085
  eventId: result.eventId,
1133
- });
1086
+ };
1134
1087
  }
1135
1088
 
1136
1089
  /**
@@ -1229,8 +1182,8 @@ async function persistSlackReactionAsMessage(params: {
1229
1182
  },
1230
1183
  };
1231
1184
 
1232
- // Sentinel content — renderers (PR 18) read `slackMeta` to format the
1233
- // reaction line; the literal text is never displayed to the model.
1185
+ // Sentinel content — Slack transcript renderers read `slackMeta` to format
1186
+ // the reaction line; the literal text is never displayed to the model.
1234
1187
  const persisted = await addMessage(
1235
1188
  params.conversationId,
1236
1189
  "user",
@@ -1238,8 +1191,8 @@ async function persistSlackReactionAsMessage(params: {
1238
1191
  { slackMeta: writeSlackMetadata(slackMeta) },
1239
1192
  { skipIndexing: true },
1240
1193
  );
1241
- deliveryCrud.linkMessage(params.eventId, persisted.id);
1242
- deliveryStatus.markProcessed(params.eventId);
1194
+ linkMessage(params.eventId, persisted.id);
1195
+ markProcessed(params.eventId);
1243
1196
  }
1244
1197
 
1245
1198
  /**
@@ -1309,19 +1262,7 @@ function countSlackMetaMessages(conversationId: string): number {
1309
1262
  );
1310
1263
  if (candidates.length === 0) return count;
1311
1264
  for (const raw of candidates) {
1312
- let parent: Record<string, unknown> | null = null;
1313
- try {
1314
- const parsed = JSON.parse(raw) as unknown;
1315
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1316
- parent = parsed as Record<string, unknown>;
1317
- }
1318
- } catch {
1319
- continue;
1320
- }
1321
- if (!parent) continue;
1322
- const inner = parent.slackMeta;
1323
- if (typeof inner !== "string") continue;
1324
- if (readSlackMetadata(inner)) {
1265
+ if (readSlackMetadataFromMessageMetadata(raw)) {
1325
1266
  count++;
1326
1267
  if (count >= SLACK_DM_BACKFILL_WARM_THRESHOLD) return count;
1327
1268
  }
@@ -1332,44 +1273,110 @@ function countSlackMetaMessages(conversationId: string): number {
1332
1273
  return count;
1333
1274
  }
1334
1275
 
1276
+ function readSlackMetadataFromMessageMetadata(
1277
+ metadata: string | null | undefined,
1278
+ ): SlackMessageMetadata | null {
1279
+ if (!metadata) return null;
1280
+ let parent: Record<string, unknown> | null = null;
1281
+ try {
1282
+ const parsed = JSON.parse(metadata) as unknown;
1283
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1284
+ parent = parsed as Record<string, unknown>;
1285
+ }
1286
+ } catch {
1287
+ return null;
1288
+ }
1289
+ if (!parent) return null;
1290
+ const raw = parent.slackMeta;
1291
+ if (typeof raw !== "string") return null;
1292
+ return readSlackMetadata(raw);
1293
+ }
1294
+
1335
1295
  /**
1336
1296
  * Build the set of `slackMeta.channelTs` values already stored on a
1337
- * conversation. Used by both DM cold-start backfill and thread-ancestor
1297
+ * conversation. Used by both DM cold-start backfill and thread gap/delta
1338
1298
  * backfill to dedupe rows so a partial prior backfill (or a single message
1339
1299
  * that was already persisted via the live ingress path) does not double-write.
1340
1300
  */
1341
1301
  function readStoredSlackChannelTs(conversationId: string): Set<string> {
1342
1302
  const seen = new Set<string>();
1343
1303
  for (const row of getMessages(conversationId)) {
1344
- if (!row.metadata) continue;
1345
- let parent: Record<string, unknown> | null = null;
1346
- try {
1347
- const parsed = JSON.parse(row.metadata) as unknown;
1348
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1349
- parent = parsed as Record<string, unknown>;
1350
- }
1351
- } catch {
1352
- continue;
1353
- }
1354
- if (!parent) continue;
1355
- const raw = parent.slackMeta;
1356
- if (typeof raw !== "string") continue;
1357
- const meta = readSlackMetadata(raw);
1304
+ const meta = readSlackMetadataFromMessageMetadata(row.metadata);
1358
1305
  // Only message rows represent stored Slack messages. Reaction rows carry
1359
1306
  // `channelTs` equal to the target message's ts, so including them would
1360
- // make a reaction on a thread parent wrongly short-circuit ancestor
1307
+ // make a reaction on a thread parent wrongly short-circuit thread
1361
1308
  // backfill (the parent itself may still be unseen).
1362
1309
  if (meta && meta.eventKind === "message") seen.add(meta.channelTs);
1363
1310
  }
1364
1311
  return seen;
1365
1312
  }
1366
1313
 
1314
+ interface ParsedSlackTimestamp {
1315
+ seconds: bigint;
1316
+ micros: bigint;
1317
+ }
1318
+
1319
+ function parseSlackTimestamp(
1320
+ ts: string | undefined,
1321
+ ): ParsedSlackTimestamp | null {
1322
+ if (!ts) return null;
1323
+ const match = /^(\d+)\.(\d{1,6})$/.exec(ts);
1324
+ if (!match) return null;
1325
+ const micros = BigInt(match[2]);
1326
+ if (micros > 999_999n) return null;
1327
+ return {
1328
+ seconds: BigInt(match[1]),
1329
+ micros,
1330
+ };
1331
+ }
1332
+
1333
+ function compareSlackTimestamps(left: string, right: string): number | null {
1334
+ const parsedLeft = parseSlackTimestamp(left);
1335
+ const parsedRight = parseSlackTimestamp(right);
1336
+ if (!parsedLeft || !parsedRight) return null;
1337
+ if (parsedLeft.seconds < parsedRight.seconds) return -1;
1338
+ if (parsedLeft.seconds > parsedRight.seconds) return 1;
1339
+ if (parsedLeft.micros < parsedRight.micros) return -1;
1340
+ if (parsedLeft.micros > parsedRight.micros) return 1;
1341
+ return 0;
1342
+ }
1343
+
1344
+ interface StoredSlackThreadState {
1345
+ storedChannelTs: Set<string>;
1346
+ latestStoredThreadTs: string | undefined;
1347
+ }
1348
+
1349
+ function readStoredSlackThreadState(
1350
+ conversationId: string,
1351
+ threadTs: string,
1352
+ ): StoredSlackThreadState {
1353
+ const storedChannelTs = new Set<string>();
1354
+ let latestStoredThreadTs: string | undefined;
1355
+
1356
+ for (const row of getMessages(conversationId)) {
1357
+ const meta = readSlackMetadataFromMessageMetadata(row.metadata);
1358
+ if (!meta || meta.eventKind !== "message") continue;
1359
+ if (meta.channelTs !== threadTs && meta.threadTs !== threadTs) continue;
1360
+
1361
+ storedChannelTs.add(meta.channelTs);
1362
+ if (!parseSlackTimestamp(meta.channelTs)) continue;
1363
+ if (
1364
+ latestStoredThreadTs === undefined ||
1365
+ compareSlackTimestamps(meta.channelTs, latestStoredThreadTs) === 1
1366
+ ) {
1367
+ latestStoredThreadTs = meta.channelTs;
1368
+ }
1369
+ }
1370
+
1371
+ return { storedChannelTs, latestStoredThreadTs };
1372
+ }
1373
+
1367
1374
  /**
1368
1375
  * Persist a single backfilled Slack message as a `messages` row with a
1369
1376
  * `slackMeta` envelope.
1370
1377
  *
1371
1378
  * Shared insertion point for any path that hydrates Slack history lazily
1372
- * (DM cold-start backfill, thread-ancestor backfill, etc.). Role is derived
1379
+ * (DM cold-start backfill, thread gap/delta backfill, etc.). Role is derived
1373
1380
  * from `message.metadata.isBot` — bot-authored rows map to `"assistant"` so
1374
1381
  * our own prior replies (and any other bot traffic) are not rehydrated as
1375
1382
  * user turns, which would otherwise corrupt speaker attribution and make
@@ -1383,6 +1390,7 @@ async function persistBackfilledSlackMessage(params: {
1383
1390
  message: ProviderMessage;
1384
1391
  }): Promise<void> {
1385
1392
  const { message } = params;
1393
+ const slackFiles = readSlackFilesFromProviderMetadata(message.metadata);
1386
1394
  const slackMeta: SlackMessageMetadata = {
1387
1395
  source: "slack",
1388
1396
  channelId: params.channelId,
@@ -1390,6 +1398,7 @@ async function persistBackfilledSlackMessage(params: {
1390
1398
  eventKind: "message",
1391
1399
  ...(message.threadId ? { threadTs: message.threadId } : {}),
1392
1400
  ...(message.sender?.name ? { displayName: message.sender.name } : {}),
1401
+ ...(slackFiles.length > 0 ? { slackFiles } : {}),
1393
1402
  };
1394
1403
  const role = message.metadata?.isBot === true ? "assistant" : "user";
1395
1404
  await addMessage(params.conversationId, role, message.text ?? "", {
@@ -1397,6 +1406,32 @@ async function persistBackfilledSlackMessage(params: {
1397
1406
  });
1398
1407
  }
1399
1408
 
1409
+ function readSlackFilesFromProviderMetadata(
1410
+ metadata: Record<string, unknown> | undefined,
1411
+ ): SlackFileMetadata[] {
1412
+ const raw = metadata?.slackFiles;
1413
+ if (!Array.isArray(raw)) return [];
1414
+ const files: SlackFileMetadata[] = [];
1415
+ for (const item of raw) {
1416
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
1417
+ continue;
1418
+ }
1419
+ const record = item as Record<string, unknown>;
1420
+ const name = typeof record.name === "string" ? record.name.trim() : "";
1421
+ if (!name) continue;
1422
+ files.push({
1423
+ ...(typeof record.id === "string" && record.id.length > 0
1424
+ ? { id: record.id }
1425
+ : {}),
1426
+ name,
1427
+ ...(typeof record.mimetype === "string" && record.mimetype.length > 0
1428
+ ? { mimetype: record.mimetype }
1429
+ : {}),
1430
+ });
1431
+ }
1432
+ return files;
1433
+ }
1434
+
1400
1435
  /**
1401
1436
  * In-memory map of in-flight DM cold-start backfills keyed by conversationId.
1402
1437
  * Concurrent inbound DMs to the same cold conversation share a single
@@ -1539,13 +1574,11 @@ async function runBackfillSlackDmIfCold(params: {
1539
1574
  // ---------------------------------------------------------------------------
1540
1575
 
1541
1576
  /**
1542
- * In-memory TTL cache keyed by `<conversationId>:<threadTs>`. Tracks recent
1543
- * thread-backfill triggers so a burst of replies inside the same Slack
1544
- * thread (e.g. a guardian rapidly typing several lines) does not re-fetch
1545
- * the same parent messages from Slack repeatedly. Entries naturally fall
1546
- * out after the TTL — if the thread is still active later, a fresh
1547
- * backfill becomes a cheap "are the parents already stored?" DB lookup
1548
- * that short-circuits before the Slack API is touched.
1577
+ * In-memory TTL cache keyed by
1578
+ * `<conversationId>:<threadTs>:<lowerBoundTs>:<upperBoundTs>`. Tracks recent
1579
+ * thread-backfill windows so repeated triggers for the same Slack gap do not
1580
+ * re-fetch identical rows while later replies in the same thread can still
1581
+ * request newer unseen windows.
1549
1582
  *
1550
1583
  * Exported only for tests; production callers should use
1551
1584
  * {@link triggerSlackThreadBackfillIfNeeded}.
@@ -1554,6 +1587,39 @@ export const _backfillTriggerCache = new Map<string, number>();
1554
1587
 
1555
1588
  const BACKFILL_TRIGGER_TTL_MS = 10 * 60 * 1000; // 10 minutes
1556
1589
  const BACKFILL_TRIGGER_CACHE_MAX = 1_000;
1590
+ const SLACK_THREAD_INITIAL_EARLY_LIMIT = 25;
1591
+ const SLACK_THREAD_INITIAL_RECENT_LIMIT = 50;
1592
+ const SLACK_THREAD_INITIAL_RECENT_MAX_PAGES = 5;
1593
+ const SLACK_THREAD_DELTA_LIMIT = 50;
1594
+ const SLACK_THREAD_UPPER_ADJACENT_MAX_ATTEMPTS = 5;
1595
+ const MICROS_PER_SECOND = 1_000_000n;
1596
+ const SLACK_UPPER_ADJACENT_EXPANDING_WINDOWS_MICROS = [
1597
+ 5n * 60n * MICROS_PER_SECOND,
1598
+ 60n * 60n * MICROS_PER_SECOND,
1599
+ 24n * 60n * 60n * MICROS_PER_SECOND,
1600
+ 7n * 24n * 60n * 60n * MICROS_PER_SECOND,
1601
+ 30n * 24n * 60n * 60n * MICROS_PER_SECOND,
1602
+ ];
1603
+ const SLACK_UPPER_ADJACENT_SHRINKING_WINDOWS_MICROS = [
1604
+ 60n * MICROS_PER_SECOND,
1605
+ 10n * MICROS_PER_SECOND,
1606
+ MICROS_PER_SECOND,
1607
+ 100_000n,
1608
+ 1_000n,
1609
+ ];
1610
+
1611
+ export interface SlackThreadBackfillResult {
1612
+ fetched: number;
1613
+ persisted: number;
1614
+ reason?: SlackBackfillReason;
1615
+ omittedMiddle: boolean;
1616
+ }
1617
+
1618
+ type SlackBackfillReason = "thread_late_join" | "thread_delta";
1619
+
1620
+ function emptySlackThreadBackfillResult(): SlackThreadBackfillResult {
1621
+ return { fetched: 0, persisted: 0, omittedMiddle: false };
1622
+ }
1557
1623
 
1558
1624
  function pruneBackfillCacheIfNeeded(): void {
1559
1625
  if (_backfillTriggerCache.size < BACKFILL_TRIGGER_CACHE_MAX) return;
@@ -1588,23 +1654,315 @@ function isBackfillRecentlyTriggered(cacheKey: string): boolean {
1588
1654
  return true;
1589
1655
  }
1590
1656
 
1657
+ interface SlackInitialThreadWindowsResult {
1658
+ messages: ProviderMessage[];
1659
+ omittedMiddle: boolean;
1660
+ }
1661
+
1662
+ interface SlackUpperAdjacentWindowResult {
1663
+ messages: ProviderMessage[];
1664
+ omittedEarlierContent: boolean;
1665
+ truncatedBeforeUpperBound: boolean;
1666
+ }
1667
+
1668
+ function slackPageHasMore(page: SlackBackfillWindowPage): boolean {
1669
+ return page.hasMore || page.nextCursor !== undefined;
1670
+ }
1671
+
1672
+ function minSlackMessageTs(messages: ProviderMessage[]): string | undefined {
1673
+ return sortSlackProviderMessages(messages)[0]?.id;
1674
+ }
1675
+
1676
+ function maxSlackMessageTs(messages: ProviderMessage[]): string | undefined {
1677
+ const sorted = sortSlackProviderMessages(messages);
1678
+ return sorted[sorted.length - 1]?.id;
1679
+ }
1680
+
1681
+ function slackTimestampToMicros(ts: string | undefined): bigint | null {
1682
+ const parsed = parseSlackTimestamp(ts);
1683
+ if (!parsed) return null;
1684
+ return parsed.seconds * MICROS_PER_SECOND + parsed.micros;
1685
+ }
1686
+
1687
+ function slackTimestampFromMicros(totalMicros: bigint): string | undefined {
1688
+ if (totalMicros < 0n) return undefined;
1689
+ const seconds = totalMicros / MICROS_PER_SECOND;
1690
+ const micros = totalMicros % MICROS_PER_SECOND;
1691
+ return `${seconds.toString()}.${micros.toString().padStart(6, "0")}`;
1692
+ }
1693
+
1694
+ function didInitialWindowsLeaveGap(params: {
1695
+ early: SlackBackfillWindowPage;
1696
+ recent: SlackBackfillWindowPage;
1697
+ recentScanTruncated: boolean;
1698
+ }): boolean {
1699
+ if (params.recentScanTruncated) return true;
1700
+ if (!slackPageHasMore(params.early)) return false;
1701
+ const earlyMax = maxSlackMessageTs(params.early.messages);
1702
+ const recentMin = minSlackMessageTs(params.recent.messages);
1703
+ if (!earlyMax || !recentMin) return false;
1704
+ const compared = compareSlackTimestamps(earlyMax, recentMin);
1705
+ return compared !== null && compared < 0;
1706
+ }
1707
+
1708
+ async function fetchSlackThreadUpperAdjacentWindow(params: {
1709
+ channelId: string;
1710
+ threadTs: string;
1711
+ upperBoundTs: string;
1712
+ lowerBoundTs?: string;
1713
+ limit: number;
1714
+ account?: string;
1715
+ maxAttempts?: number;
1716
+ }): Promise<SlackUpperAdjacentWindowResult> {
1717
+ // Slack returns bounded conversations.replies pages earliest-first. To keep
1718
+ // the context closest to the inbound mention, narrow by timestamp instead
1719
+ // of cursoring forward from the oldest page in the bounded range.
1720
+ const upperMicros = slackTimestampToMicros(params.upperBoundTs);
1721
+ if (upperMicros === null) {
1722
+ const page = await backfillThreadWindowPage(
1723
+ params.channelId,
1724
+ params.threadTs,
1725
+ {
1726
+ limit: params.limit,
1727
+ account: params.account,
1728
+ before: params.upperBoundTs,
1729
+ ...(params.lowerBoundTs !== undefined
1730
+ ? { after: params.lowerBoundTs }
1731
+ : {}),
1732
+ },
1733
+ );
1734
+ return {
1735
+ messages: page.messages,
1736
+ omittedEarlierContent: slackPageHasMore(page),
1737
+ truncatedBeforeUpperBound: slackPageHasMore(page),
1738
+ };
1739
+ }
1740
+
1741
+ const lowerMicros = slackTimestampToMicros(params.lowerBoundTs);
1742
+ const maxAttempts =
1743
+ params.maxAttempts ?? SLACK_THREAD_UPPER_ADJACENT_MAX_ATTEMPTS;
1744
+ let attempts = 0;
1745
+ let safePage: SlackBackfillWindowPage | undefined;
1746
+ let safeAfterTs: string | undefined;
1747
+ let truncatedBeforeUpperBound = false;
1748
+
1749
+ const fetchWindow = async (
1750
+ windowMicros: bigint,
1751
+ ): Promise<{
1752
+ page: SlackBackfillWindowPage;
1753
+ after?: string;
1754
+ reachedLowerBound: boolean;
1755
+ }> => {
1756
+ let candidateMicros = upperMicros - windowMicros;
1757
+ let reachedLowerBound = false;
1758
+ if (lowerMicros !== null && candidateMicros <= lowerMicros) {
1759
+ candidateMicros = lowerMicros;
1760
+ reachedLowerBound = true;
1761
+ }
1762
+ const after = reachedLowerBound
1763
+ ? params.lowerBoundTs
1764
+ : slackTimestampFromMicros(candidateMicros);
1765
+ const page = await backfillThreadWindowPage(
1766
+ params.channelId,
1767
+ params.threadTs,
1768
+ {
1769
+ limit: params.limit,
1770
+ account: params.account,
1771
+ before: params.upperBoundTs,
1772
+ ...(after !== undefined ? { after } : {}),
1773
+ },
1774
+ );
1775
+ attempts++;
1776
+ return { page, after, reachedLowerBound };
1777
+ };
1778
+
1779
+ const considerWindow = async (windowMicros: bigint): Promise<boolean> => {
1780
+ const { page, after, reachedLowerBound } = await fetchWindow(windowMicros);
1781
+ if (slackPageHasMore(page)) {
1782
+ truncatedBeforeUpperBound = true;
1783
+ return false;
1784
+ }
1785
+
1786
+ safePage = page;
1787
+ safeAfterTs = after;
1788
+ return page.messages.length < params.limit && !reachedLowerBound;
1789
+ };
1790
+
1791
+ for (const windowMicros of SLACK_UPPER_ADJACENT_EXPANDING_WINDOWS_MICROS) {
1792
+ if (attempts >= maxAttempts) break;
1793
+ const shouldExpand = await considerWindow(windowMicros);
1794
+ if (!shouldExpand) break;
1795
+ }
1796
+
1797
+ if (truncatedBeforeUpperBound && !safePage && attempts < maxAttempts) {
1798
+ for (const windowMicros of SLACK_UPPER_ADJACENT_SHRINKING_WINDOWS_MICROS) {
1799
+ if (attempts >= maxAttempts) break;
1800
+ await considerWindow(windowMicros);
1801
+ if (safePage) break;
1802
+ }
1803
+ }
1804
+
1805
+ if (!safePage) {
1806
+ const after = slackTimestampFromMicros(upperMicros - 2n);
1807
+ const page = await backfillThreadWindowPage(
1808
+ params.channelId,
1809
+ params.threadTs,
1810
+ {
1811
+ limit: params.limit,
1812
+ account: params.account,
1813
+ before: params.upperBoundTs,
1814
+ ...(after !== undefined ? { after } : {}),
1815
+ },
1816
+ );
1817
+ safePage = page;
1818
+ safeAfterTs = after;
1819
+ truncatedBeforeUpperBound =
1820
+ truncatedBeforeUpperBound || slackPageHasMore(page);
1821
+ }
1822
+ if (!safePage) {
1823
+ return {
1824
+ messages: [],
1825
+ omittedEarlierContent: true,
1826
+ truncatedBeforeUpperBound: true,
1827
+ };
1828
+ }
1829
+
1830
+ let omittedEarlierContent = truncatedBeforeUpperBound;
1831
+ if (
1832
+ !omittedEarlierContent &&
1833
+ params.lowerBoundTs !== undefined &&
1834
+ safeAfterTs !== undefined &&
1835
+ compareSlackTimestamps(params.lowerBoundTs, safeAfterTs) === -1
1836
+ ) {
1837
+ const coverageProbe = await backfillThreadWindowPage(
1838
+ params.channelId,
1839
+ params.threadTs,
1840
+ {
1841
+ limit: 1,
1842
+ account: params.account,
1843
+ after: params.lowerBoundTs,
1844
+ before: safeAfterTs,
1845
+ },
1846
+ );
1847
+ omittedEarlierContent =
1848
+ coverageProbe.messages.length > 0 || slackPageHasMore(coverageProbe);
1849
+ }
1850
+
1851
+ return {
1852
+ messages: safePage.messages,
1853
+ omittedEarlierContent,
1854
+ truncatedBeforeUpperBound,
1855
+ };
1856
+ }
1857
+
1858
+ async function fetchInitialSlackThreadWindows(params: {
1859
+ channelId: string;
1860
+ threadTs: string;
1861
+ upperBoundTs?: string;
1862
+ account?: string;
1863
+ }): Promise<SlackInitialThreadWindowsResult> {
1864
+ if (!params.upperBoundTs) {
1865
+ const early = await backfillThreadWindowPage(
1866
+ params.channelId,
1867
+ params.threadTs,
1868
+ {
1869
+ limit: SLACK_THREAD_INITIAL_EARLY_LIMIT,
1870
+ account: params.account,
1871
+ },
1872
+ );
1873
+ return {
1874
+ messages: sortSlackProviderMessages(
1875
+ dedupeSlackProviderMessages(early.messages),
1876
+ ),
1877
+ omittedMiddle: slackPageHasMore(early),
1878
+ };
1879
+ }
1880
+ const [early, recentResult] = await Promise.all([
1881
+ backfillThreadWindowPage(params.channelId, params.threadTs, {
1882
+ limit: SLACK_THREAD_INITIAL_EARLY_LIMIT,
1883
+ account: params.account,
1884
+ }),
1885
+ fetchSlackThreadUpperAdjacentWindow({
1886
+ channelId: params.channelId,
1887
+ threadTs: params.threadTs,
1888
+ account: params.account,
1889
+ upperBoundTs: params.upperBoundTs,
1890
+ limit: SLACK_THREAD_INITIAL_RECENT_LIMIT,
1891
+ maxAttempts: SLACK_THREAD_INITIAL_RECENT_MAX_PAGES,
1892
+ }),
1893
+ ]);
1894
+ const recent: SlackBackfillWindowPage = {
1895
+ messages: recentResult.messages,
1896
+ hasMore: recentResult.truncatedBeforeUpperBound,
1897
+ };
1898
+ return {
1899
+ messages: sortSlackProviderMessages(
1900
+ dedupeSlackProviderMessages([...early.messages, ...recent.messages]),
1901
+ ),
1902
+ omittedMiddle:
1903
+ recentResult.omittedEarlierContent ||
1904
+ didInitialWindowsLeaveGap({
1905
+ early,
1906
+ recent,
1907
+ recentScanTruncated: recentResult.truncatedBeforeUpperBound,
1908
+ }),
1909
+ };
1910
+ }
1911
+
1912
+ function dedupeSlackProviderMessages(
1913
+ messages: ProviderMessage[],
1914
+ ): ProviderMessage[] {
1915
+ const byTs = new Map<string, ProviderMessage>();
1916
+ for (const message of messages) {
1917
+ if (!message.id || byTs.has(message.id)) continue;
1918
+ byTs.set(message.id, message);
1919
+ }
1920
+ return [...byTs.values()];
1921
+ }
1922
+
1923
+ function sortSlackProviderMessages(
1924
+ messages: ProviderMessage[],
1925
+ ): ProviderMessage[] {
1926
+ return [...messages].sort((left, right) => {
1927
+ const compared = compareSlackTimestamps(left.id, right.id);
1928
+ if (compared !== null) return compared;
1929
+ return left.id.localeCompare(right.id);
1930
+ });
1931
+ }
1932
+
1933
+ function buildSlackLateJoinNotice(
1934
+ result: SlackThreadBackfillResult,
1935
+ ): string | null {
1936
+ if (result.reason !== "thread_late_join" || result.persisted === 0) {
1937
+ return null;
1938
+ }
1939
+ const omitted = result.omittedMiddle
1940
+ ? " Some middle thread messages were intentionally omitted from this turn's hydrated context to keep latency bounded."
1941
+ : "";
1942
+ return `Slack context note: this turn joined an existing thread. ${result.persisted} earlier thread message${result.persisted === 1 ? " was" : "s were"} backfilled before the current message.${omitted}`;
1943
+ }
1944
+
1591
1945
  /**
1592
- * Lazily backfill missing Slack thread ancestors for an inbound thread reply.
1946
+ * Lazily backfill Slack thread gaps for an inbound thread reply.
1593
1947
  *
1594
- * When a reply arrives for a thread the daemon has never seen (e.g. the bot
1595
- * was just added to the channel, or the parent message pre-dates the
1596
- * conversation), the daemon fetches the thread's recent history via
1597
- * {@link backfillThread}, persists each unseen message as a `messages` row
1598
- * with a `slackMeta` envelope, and skips duplicates whose `ts` already
1599
- * appears in the conversation.
1948
+ * When a reply arrives for a thread with unseen Slack history, the assistant
1949
+ * fetches bounded `conversations.replies` pages via
1950
+ * {@link backfillThreadWindowPage}, persists each unseen message as a
1951
+ * `messages` row with a `slackMeta` envelope, and skips duplicates whose `ts`
1952
+ * already appears in the conversation.
1600
1953
  *
1601
1954
  * Behavior contracts:
1602
- * - **No-op when the parent is already stored.** Looks up the conversation's
1603
- * messages and short-circuits if any row has `slackMeta.channelTs ===
1604
- * threadTs`. This keeps subsequent replies in the same thread cheap.
1605
- * - **TTL idempotency cache.** A 10-minute in-memory cache prevents bursts
1606
- * of replies in the same thread from re-running the DB lookup or the
1607
- * Slack API call.
1955
+ * - **Thread-state gap detection.** Looks up stored Slack message rows for
1956
+ * the same thread, excluding reactions, then fetches only the unseen
1957
+ * `(latestStoredThreadTs, excludeChannelTs)` window when the inbound Slack
1958
+ * timestamp is newer than local state.
1959
+ * - **Upper-bound windows.** Initial late-join backfill combines an early
1960
+ * thread page with a recent page adjacent to the inbound ts; delta backfill
1961
+ * fetches the page nearest the inbound upper bound so the current turn sees
1962
+ * the most relevant context while keeping latency bounded.
1963
+ * - **Exact-window TTL cache.** A 10-minute in-memory cache prevents repeated
1964
+ * fetches for the same exact lower/upper bounded window, without
1965
+ * suppressing later unseen windows in the same thread.
1608
1966
  * - **Failure-tolerant.** Any error (Slack API failure, DB error, malformed
1609
1967
  * payload) is logged at `warn` and swallowed — the inbound turn must
1610
1968
  * never block on backfill.
@@ -1619,65 +1977,106 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
1619
1977
  * `conversations.replies` returns it in the thread window. Necessary
1620
1978
  * because thread backfill runs concurrently with
1621
1979
  * `processChannelMessageInBackground`, so the inbound row may not yet be
1622
- * in the DB when `readStoredSlackChannelTs` snapshots the conversation.
1980
+ * in the DB when the thread-state scan snapshots the conversation.
1623
1981
  */
1624
1982
  excludeChannelTs?: string;
1625
1983
  /**
1626
1984
  * OAuth account identifier used to disambiguate which Slack workspace the
1627
1985
  * backfill should read from in multi-account setups. Passed through to
1628
- * `backfillThread` `resolveConnection`. Best-effort: if omitted, the
1629
- * resolver falls back to the default-active connection.
1986
+ * `backfillThreadWindowPage` page requests and then `resolveConnection`.
1987
+ * Best-effort: if omitted, the resolver falls back to the default-active
1988
+ * connection.
1630
1989
  */
1631
1990
  account?: string;
1632
- }): Promise<void> {
1991
+ }): Promise<SlackThreadBackfillResult> {
1633
1992
  const { conversationId, channelId, threadTs, excludeChannelTs, account } =
1634
1993
  params;
1635
- const cacheKey = `${conversationId}:${threadTs}`;
1636
1994
 
1637
1995
  try {
1638
- if (isBackfillRecentlyTriggered(cacheKey)) {
1639
- return;
1996
+ const upperBoundTs = parseSlackTimestamp(excludeChannelTs)
1997
+ ? excludeChannelTs
1998
+ : undefined;
1999
+ const threadState = readStoredSlackThreadState(conversationId, threadTs);
2000
+ const lowerBoundTs = threadState.latestStoredThreadTs;
2001
+
2002
+ // Pre-seed only after computing lowerBoundTs. The current inbound row
2003
+ // may not have reached the DB yet, and treating it as stored state would
2004
+ // hide the gap we need to fetch.
2005
+ if (excludeChannelTs) threadState.storedChannelTs.add(excludeChannelTs);
2006
+
2007
+ if (upperBoundTs && lowerBoundTs) {
2008
+ const lowerVsUpper = compareSlackTimestamps(lowerBoundTs, upperBoundTs);
2009
+ if (lowerVsUpper !== null && lowerVsUpper >= 0) {
2010
+ return emptySlackThreadBackfillResult();
2011
+ }
2012
+ } else if (!upperBoundTs && lowerBoundTs) {
2013
+ return emptySlackThreadBackfillResult();
1640
2014
  }
1641
2015
 
1642
- const storedChannelTs = readStoredSlackChannelTs(conversationId);
1643
- if (excludeChannelTs) storedChannelTs.add(excludeChannelTs);
1644
- if (storedChannelTs.has(threadTs)) {
1645
- // Parent is already in the conversation; mark the cache so a burst of
1646
- // replies in this thread does not redo the DB scan for each one.
1647
- _backfillTriggerCache.set(cacheKey, Date.now());
1648
- pruneBackfillCacheIfNeeded();
1649
- return;
2016
+ const cacheKey = `${conversationId}:${threadTs}:${
2017
+ lowerBoundTs ?? "none"
2018
+ }:${upperBoundTs ?? "unbounded"}`;
2019
+ if (isBackfillRecentlyTriggered(cacheKey)) {
2020
+ return emptySlackThreadBackfillResult();
1650
2021
  }
1651
2022
 
1652
2023
  // Mark the trigger before issuing the network call. Doing this first
1653
- // means a second concurrent reply in the same thread short-circuits
1654
- // immediately even while the first call is still awaiting the Slack
1655
- // API. The cost is a slightly larger window where a transient Slack
1656
- // failure suppresses a retry, which the next reply outside the TTL
1657
- // (or a daemon restart) will re-attempt anyway.
2024
+ // means a second concurrent request for the same window short-circuits
2025
+ // immediately even while the first call is still awaiting the Slack API.
2026
+ // The cost is a slightly larger window where a transient Slack failure
2027
+ // suppresses a retry, which the next reply outside the TTL (or a daemon
2028
+ // restart) will re-attempt anyway.
1658
2029
  _backfillTriggerCache.set(cacheKey, Date.now());
1659
2030
  pruneBackfillCacheIfNeeded();
1660
2031
 
1661
- const fetched = await backfillThread(channelId, threadTs, { account });
2032
+ const isInitialLateJoin =
2033
+ lowerBoundTs === undefined &&
2034
+ threadState.storedChannelTs.size === (excludeChannelTs ? 1 : 0);
2035
+ const reason: SlackBackfillReason = isInitialLateJoin
2036
+ ? "thread_late_join"
2037
+ : "thread_delta";
2038
+ let omittedMiddle = false;
2039
+ let fetched: ProviderMessage[];
2040
+ if (isInitialLateJoin) {
2041
+ const initial = await fetchInitialSlackThreadWindows({
2042
+ channelId,
2043
+ threadTs,
2044
+ upperBoundTs,
2045
+ account,
2046
+ });
2047
+ fetched = initial.messages;
2048
+ omittedMiddle = initial.omittedMiddle;
2049
+ } else {
2050
+ const window = await fetchSlackThreadUpperAdjacentWindow({
2051
+ channelId,
2052
+ threadTs,
2053
+ limit: SLACK_THREAD_DELTA_LIMIT,
2054
+ account,
2055
+ ...(lowerBoundTs !== undefined ? { lowerBoundTs } : {}),
2056
+ upperBoundTs: upperBoundTs ?? threadTs,
2057
+ });
2058
+ fetched = window.messages;
2059
+ omittedMiddle = window.omittedEarlierContent;
2060
+ }
1662
2061
  if (fetched.length === 0) {
1663
2062
  log.debug(
1664
2063
  { conversationId, channelId, threadTs },
1665
2064
  "Slack thread backfill returned no messages",
1666
2065
  );
1667
- return;
2066
+ return emptySlackThreadBackfillResult();
1668
2067
  }
1669
2068
 
1670
2069
  let persisted = 0;
1671
2070
  for (const message of fetched) {
1672
2071
  if (!message.id) continue;
1673
- if (storedChannelTs.has(message.id)) continue;
2072
+ if (threadState.storedChannelTs.has(message.id)) continue;
1674
2073
  try {
1675
2074
  await persistBackfilledSlackMessage({
1676
2075
  conversationId,
1677
2076
  channelId,
1678
2077
  message,
1679
2078
  });
1680
- storedChannelTs.add(message.id);
2079
+ threadState.storedChannelTs.add(message.id);
1681
2080
  persisted++;
1682
2081
  } catch (err) {
1683
2082
  log.warn(
@@ -1694,15 +2093,22 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
1694
2093
  threadTs,
1695
2094
  persisted,
1696
2095
  fetched: fetched.length,
2096
+ omittedMiddle,
1697
2097
  },
1698
- "Slack thread backfill persisted ancestor messages",
2098
+ "Slack thread backfill persisted thread messages",
1699
2099
  );
2100
+ return {
2101
+ fetched: fetched.length,
2102
+ persisted,
2103
+ reason,
2104
+ omittedMiddle,
2105
+ };
1700
2106
  } catch (err) {
1701
2107
  // `channel_not_found` almost always means the resolved connection is
1702
2108
  // pointing at the wrong Slack workspace (a real config bug), so log it
1703
2109
  // at ERROR to match backfill's rethrow contract. Other failures
1704
2110
  // (timeout, auth, ratelimited, …) stay at WARN — they're expected
1705
- // transient blips and dispatch proceeds without the ancestors.
2111
+ // transient blips and dispatch proceeds without the backfilled thread rows.
1706
2112
  const channelNotFound =
1707
2113
  err instanceof Error && /channel_not_found/i.test(err.message);
1708
2114
  const payload = { err, conversationId, channelId, threadTs, account };
@@ -1714,5 +2120,6 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
1714
2120
  } else {
1715
2121
  log.warn(payload, "Slack thread backfill failed; proceeding without it");
1716
2122
  }
2123
+ return emptySlackThreadBackfillResult();
1717
2124
  }
1718
2125
  }