@vellumai/assistant 0.6.4 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -312,6 +312,90 @@ describe("Cross-Provider Web Search — OpenAI (Responses API)", () => {
312
312
  });
313
313
  });
314
314
 
315
+ // ---------------------------------------------------------------------------
316
+ // OpenAI Responses API — native web search tool mapping
317
+ // ---------------------------------------------------------------------------
318
+
319
+ describe("Cross-Provider Web Search — OpenAI (Responses API, native mode)", () => {
320
+ beforeEach(() => {
321
+ lastOpenAIResponsesParams = null;
322
+ });
323
+
324
+ test("maps web_search to native web_search_preview tool when useNativeWebSearch is enabled", async () => {
325
+ const provider = new OpenAIResponsesProvider("sk-test", "gpt-4o", {
326
+ useNativeWebSearch: true,
327
+ });
328
+
329
+ const tools = [
330
+ {
331
+ name: "file_read",
332
+ description: "Read a file",
333
+ input_schema: {
334
+ type: "object",
335
+ properties: { path: { type: "string" } },
336
+ },
337
+ },
338
+ {
339
+ name: "web_search",
340
+ description: "Search the web",
341
+ input_schema: {
342
+ type: "object",
343
+ properties: { query: { type: "string" } },
344
+ },
345
+ },
346
+ ];
347
+
348
+ await provider.sendMessage([userMsg("Search for something")], tools);
349
+
350
+ const sentTools = lastOpenAIResponsesParams!.tools as Array<
351
+ Record<string, unknown>
352
+ >;
353
+ expect(sentTools).toHaveLength(2);
354
+ // Non-web-search tools stay as function tools
355
+ expect(sentTools[0]).toMatchObject({ type: "function", name: "file_read" });
356
+ // web_search is replaced with native hosted tool
357
+ expect(sentTools[1]).toEqual({ type: "web_search_preview" });
358
+ });
359
+
360
+ test("still degrades web search history blocks in native mode", async () => {
361
+ const provider = new OpenAIResponsesProvider("sk-test", "gpt-4o", {
362
+ useNativeWebSearch: true,
363
+ });
364
+ await provider.sendMessage(webSearchConversation());
365
+
366
+ const input = lastOpenAIResponsesParams!.input as Array<{
367
+ type: string;
368
+ role?: string;
369
+ content?: Array<{ type: string; text?: string }>;
370
+ }>;
371
+
372
+ // server_tool_use in assistant history is still degraded to text placeholder
373
+ const assistantItems = input.filter(
374
+ (item) => item.type === "message" && item.role === "assistant",
375
+ );
376
+ const hasWebSearchPlaceholder = assistantItems.some((item) =>
377
+ item.content?.some(
378
+ (part) =>
379
+ part.type === "output_text" &&
380
+ part.text?.includes("[Web search: web_search]"),
381
+ ),
382
+ );
383
+ expect(hasWebSearchPlaceholder).toBe(true);
384
+
385
+ // web_search_tool_result in user history is still degraded to text placeholder
386
+ const userItems = input.filter(
387
+ (item) => item.type === "message" && item.role === "user",
388
+ );
389
+ const hasWebSearchResult = userItems.some((item) =>
390
+ item.content?.some(
391
+ (part) =>
392
+ part.type === "input_text" && part.text === "[Web search results]",
393
+ ),
394
+ );
395
+ expect(hasWebSearchResult).toBe(true);
396
+ });
397
+ });
398
+
315
399
  // ---------------------------------------------------------------------------
316
400
  // OpenAI Chat Completions compatibility provider tests
317
401
  // ---------------------------------------------------------------------------
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Regression guard for PR #26115 follow-up: verifies that
3
+ * `DaemonServer.persistAndProcessMessage` threads `options.callSite`
4
+ * through to `conversation.runAgentLoop`, mirroring the threading already
5
+ * done in `DaemonServer.processMessage`.
6
+ *
7
+ * The fix is a one-line spread on the `runAgentLoop` options object:
8
+ *
9
+ * ...(options?.callSite ? { callSite: options.callSite } : {})
10
+ *
11
+ * Standing up a full `DaemonServer` for this assertion is impractical
12
+ * (heavy collaborator graph), so this test mirrors the contract instead —
13
+ * the same approach used by `secret-ingress-cli.test.ts`. If a future
14
+ * refactor drops the spread again, the mirrored helper here will fail.
15
+ *
16
+ * The complementary `conversation-process-callsite.test.ts` test exercises
17
+ * the threading end-to-end through `Conversation.processMessage`, so the
18
+ * `Conversation.runAgentLoop` half of the chain is already covered.
19
+ */
20
+ import { describe, expect, mock, test } from "bun:test";
21
+
22
+ import type { LLMCallSite } from "../config/schemas/llm.js";
23
+
24
+ interface RunAgentLoopOptions {
25
+ isInteractive?: boolean;
26
+ isUserMessage?: boolean;
27
+ callSite?: LLMCallSite;
28
+ }
29
+
30
+ /**
31
+ * Mirrors the `runAgentLoop` invocation in
32
+ * `DaemonServer.persistAndProcessMessage` (server.ts:1396-1400). Production
33
+ * callers pass `options?.callSite` from `ConversationCreateOptions`; this
34
+ * helper captures the resulting options object so tests can assert on it.
35
+ */
36
+ function buildLoopOptionsLikePersistAndProcess(
37
+ isInteractive: boolean | undefined,
38
+ callSite: LLMCallSite | undefined,
39
+ ): RunAgentLoopOptions {
40
+ return {
41
+ isInteractive: isInteractive ?? false,
42
+ isUserMessage: true,
43
+ ...(callSite ? { callSite } : {}),
44
+ };
45
+ }
46
+
47
+ describe("DaemonServer.persistAndProcessMessage — callSite threading", () => {
48
+ test("includes callSite in runAgentLoop options when provided", () => {
49
+ const runAgentLoopMock = mock<(opts: RunAgentLoopOptions) => void>(
50
+ () => {},
51
+ );
52
+
53
+ const opts = buildLoopOptionsLikePersistAndProcess(true, "heartbeatAgent");
54
+ runAgentLoopMock(opts);
55
+
56
+ expect(runAgentLoopMock).toHaveBeenCalledTimes(1);
57
+ expect(runAgentLoopMock.mock.calls[0][0]).toEqual({
58
+ isInteractive: true,
59
+ isUserMessage: true,
60
+ callSite: "heartbeatAgent",
61
+ });
62
+ });
63
+
64
+ test("omits callSite from runAgentLoop options when undefined", () => {
65
+ const runAgentLoopMock = mock<(opts: RunAgentLoopOptions) => void>(
66
+ () => {},
67
+ );
68
+
69
+ const opts = buildLoopOptionsLikePersistAndProcess(false, undefined);
70
+ runAgentLoopMock(opts);
71
+
72
+ expect(runAgentLoopMock).toHaveBeenCalledTimes(1);
73
+ expect(runAgentLoopMock.mock.calls[0][0]).toEqual({
74
+ isInteractive: false,
75
+ isUserMessage: true,
76
+ });
77
+ // Explicit: callSite key is absent, not just undefined — matches the
78
+ // production spread which never writes the key when it's falsy.
79
+ expect("callSite" in runAgentLoopMock.mock.calls[0][0]).toBe(false);
80
+ });
81
+
82
+ test("threads non-default callSite values (e.g. 'filingAgent')", () => {
83
+ const runAgentLoopMock = mock<(opts: RunAgentLoopOptions) => void>(
84
+ () => {},
85
+ );
86
+
87
+ const opts = buildLoopOptionsLikePersistAndProcess(false, "filingAgent");
88
+ runAgentLoopMock(opts);
89
+
90
+ expect(runAgentLoopMock.mock.calls[0][0].callSite).toBe("filingAgent");
91
+ });
92
+ });
@@ -0,0 +1,437 @@
1
+ /**
2
+ * Tests for Slack message_deleted propagation into stored messages.
3
+ *
4
+ * The gateway forwards delete events with `callbackData = "message_deleted"`
5
+ * and `sourceMetadata.messageId` set to the deleted message's ts. The daemon
6
+ * marks the corresponding stored row's `slackMeta.deletedAt` while leaving
7
+ * the `content` column untouched (audit retention; the renderer elides based
8
+ * on the deletedAt marker).
9
+ */
10
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
11
+
12
+ mock.module("../util/logger.js", () => ({
13
+ getLogger: () =>
14
+ new Proxy({} as Record<string, unknown>, {
15
+ get: () => () => {},
16
+ }),
17
+ }));
18
+
19
+ mock.module("../config/env.js", () => ({
20
+ isHttpAuthDisabled: () => true,
21
+ getGatewayInternalBaseUrl: () => "http://127.0.0.1:7830",
22
+ }));
23
+
24
+ import { eq } from "drizzle-orm";
25
+
26
+ import { upsertContactChannel } from "../contacts/contacts-write.js";
27
+ import { getDb, initializeDb } from "../memory/db.js";
28
+ import { linkMessage, recordInbound } from "../memory/delivery-crud.js";
29
+ import { messages } from "../memory/schema.js";
30
+ import {
31
+ readSlackMetadata,
32
+ writeSlackMetadata,
33
+ } from "../messaging/providers/slack/message-metadata.js";
34
+ import { handleChannelInbound } from "../runtime/routes/channel-routes.js";
35
+ import { _setDeleteLookupConfigForTests } from "../runtime/routes/inbound-message-handler.js";
36
+
37
+ initializeDb();
38
+
39
+ const TEST_BEARER_TOKEN = "test-token";
40
+ // Slack `message_deleted` events stamp the deleted message's original author
41
+ // as the actor (gateway: `event.previous_message.user`). The author must be a
42
+ // recognised member for the inbound ACL to admit the event — gating delete
43
+ // behind ACL is the contract under test.
44
+ const SLACK_DELETE_ACTOR_ID = "U_DELETE_ACTOR";
45
+ const SLACK_DELETE_ACTOR_DISPLAY_NAME = "Delete Actor";
46
+
47
+ function resetState(): void {
48
+ const db = getDb();
49
+ db.run("DELETE FROM channel_inbound_events");
50
+ db.run("DELETE FROM messages");
51
+ db.run("DELETE FROM conversations");
52
+ db.run("DELETE FROM conversation_keys");
53
+ db.run("DELETE FROM contact_channels");
54
+ db.run("DELETE FROM contacts");
55
+ }
56
+
57
+ function seedActiveDeleteActor(externalChatId: string): void {
58
+ upsertContactChannel({
59
+ sourceChannel: "slack",
60
+ externalUserId: SLACK_DELETE_ACTOR_ID,
61
+ externalChatId,
62
+ status: "active",
63
+ policy: "allow",
64
+ displayName: SLACK_DELETE_ACTOR_DISPLAY_NAME,
65
+ });
66
+ }
67
+
68
+ interface SeededMessage {
69
+ conversationId: string;
70
+ messageId: string;
71
+ originalTs: string;
72
+ externalChatId: string;
73
+ }
74
+
75
+ function seedSlackMessage(opts: {
76
+ externalChatId: string;
77
+ originalTs: string;
78
+ content?: string;
79
+ withSlackMeta?: boolean;
80
+ }): SeededMessage {
81
+ const db = getDb();
82
+ // Record the inbound event so channel_inbound_events has an entry
83
+ // (sourceMessageId = ts for the lookup join).
84
+ const inbound = recordInbound("slack", opts.externalChatId, opts.originalTs, {
85
+ sourceMessageId: opts.originalTs,
86
+ });
87
+
88
+ const messageId = `msg-${opts.originalTs}`;
89
+ const slackMeta = opts.withSlackMeta
90
+ ? writeSlackMetadata({
91
+ source: "slack",
92
+ channelId: opts.externalChatId,
93
+ channelTs: opts.originalTs,
94
+ eventKind: "message",
95
+ displayName: "Test User",
96
+ })
97
+ : undefined;
98
+ const metadata = slackMeta
99
+ ? JSON.stringify({
100
+ userMessageChannel: "slack",
101
+ userMessageInterface: "slack",
102
+ slackMeta,
103
+ })
104
+ : JSON.stringify({
105
+ userMessageChannel: "slack",
106
+ userMessageInterface: "slack",
107
+ });
108
+
109
+ db.insert(messages)
110
+ .values({
111
+ id: messageId,
112
+ conversationId: inbound.conversationId,
113
+ role: "user",
114
+ content: opts.content ?? "Original message text",
115
+ createdAt: Date.now(),
116
+ metadata,
117
+ })
118
+ .run();
119
+ linkMessage(inbound.eventId, messageId);
120
+
121
+ return {
122
+ conversationId: inbound.conversationId,
123
+ messageId,
124
+ originalTs: opts.originalTs,
125
+ externalChatId: opts.externalChatId,
126
+ };
127
+ }
128
+
129
+ function buildSlackDeleteRequest(opts: {
130
+ externalChatId: string;
131
+ deletedTs: string;
132
+ eventId?: string;
133
+ actorExternalId?: string;
134
+ }): Request {
135
+ const eventId = opts.eventId ?? `evt-del-${opts.deletedTs}`;
136
+ return new Request("http://localhost:8080/channels/inbound", {
137
+ method: "POST",
138
+ headers: {
139
+ "Content-Type": "application/json",
140
+ "X-Gateway-Origin": TEST_BEARER_TOKEN,
141
+ },
142
+ body: JSON.stringify({
143
+ sourceChannel: "slack",
144
+ interface: "slack",
145
+ conversationExternalId: opts.externalChatId,
146
+ // Delete events get a fresh externalMessageId per-event (PR 5).
147
+ externalMessageId: eventId,
148
+ content: "",
149
+ callbackData: "message_deleted",
150
+ actorExternalId: opts.actorExternalId ?? SLACK_DELETE_ACTOR_ID,
151
+ sourceMetadata: {
152
+ // The original (deleted) message's ts — the lookup key.
153
+ messageId: opts.deletedTs,
154
+ },
155
+ }),
156
+ });
157
+ }
158
+
159
+ describe("Slack delete propagation", () => {
160
+ beforeEach(() => {
161
+ resetState();
162
+ seedActiveDeleteActor("C0123CHANNEL");
163
+ // Keep the lookup retry-loop fast by default so the "no such message"
164
+ // paths don't pay the full production backoff. The race-test below
165
+ // overrides this to a longer delay so the first retry can observe
166
+ // the deferred linkMessage.
167
+ _setDeleteLookupConfigForTests(2, 20);
168
+ });
169
+
170
+ test("marks slackMeta.deletedAt and leaves content untouched", async () => {
171
+ const seeded = seedSlackMessage({
172
+ externalChatId: "C0123CHANNEL",
173
+ originalTs: "1234.5678",
174
+ content: "Original audited text",
175
+ withSlackMeta: true,
176
+ });
177
+
178
+ const before = Date.now();
179
+ const req = buildSlackDeleteRequest({
180
+ externalChatId: seeded.externalChatId,
181
+ deletedTs: seeded.originalTs,
182
+ });
183
+ const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
184
+ const json = (await resp.json()) as Record<string, unknown>;
185
+ const after = Date.now();
186
+
187
+ expect(resp.status).toBe(200);
188
+ expect(json.accepted).toBe(true);
189
+ expect(json.deleted).toBe(true);
190
+ expect(json.messageId).toBe(seeded.messageId);
191
+
192
+ const db = getDb();
193
+ const row = db
194
+ .select()
195
+ .from(messages)
196
+ .where(eq(messages.id, seeded.messageId))
197
+ .get();
198
+
199
+ expect(row).toBeDefined();
200
+ // Content column MUST be unchanged for audit.
201
+ expect(row!.content).toBe("Original audited text");
202
+
203
+ // Parent metadata still has its sibling keys intact.
204
+ const parsed = JSON.parse(row!.metadata!) as Record<string, unknown>;
205
+ expect(parsed.userMessageChannel).toBe("slack");
206
+ expect(parsed.userMessageInterface).toBe("slack");
207
+ expect(typeof parsed.slackMeta).toBe("string");
208
+
209
+ // slackMeta.deletedAt is set to a recent timestamp.
210
+ const slackMeta = readSlackMetadata(parsed.slackMeta as string);
211
+ expect(slackMeta).not.toBeNull();
212
+ expect(slackMeta!.deletedAt).toBeDefined();
213
+ expect(slackMeta!.deletedAt!).toBeGreaterThanOrEqual(before);
214
+ expect(slackMeta!.deletedAt!).toBeLessThanOrEqual(after);
215
+ // Existing slackMeta fields are preserved.
216
+ expect(slackMeta!.channelId).toBe("C0123CHANNEL");
217
+ expect(slackMeta!.channelTs).toBe("1234.5678");
218
+ expect(slackMeta!.eventKind).toBe("message");
219
+ expect(slackMeta!.displayName).toBe("Test User");
220
+ });
221
+
222
+ test("delete for unknown ts is a no-op", async () => {
223
+ // Seed an unrelated message so the conversation exists but ts mismatches.
224
+ const seeded = seedSlackMessage({
225
+ externalChatId: "C0123CHANNEL",
226
+ originalTs: "1111.1111",
227
+ content: "Should remain untouched",
228
+ withSlackMeta: true,
229
+ });
230
+
231
+ const req = buildSlackDeleteRequest({
232
+ externalChatId: seeded.externalChatId,
233
+ deletedTs: "9999.9999", // not seeded
234
+ });
235
+ const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
236
+ const json = (await resp.json()) as Record<string, unknown>;
237
+
238
+ expect(resp.status).toBe(200);
239
+ expect(json.accepted).toBe(true);
240
+ expect(json.deleted).toBe(false);
241
+
242
+ // Original message must not be modified.
243
+ const db = getDb();
244
+ const row = db
245
+ .select()
246
+ .from(messages)
247
+ .where(eq(messages.id, seeded.messageId))
248
+ .get();
249
+
250
+ expect(row!.content).toBe("Should remain untouched");
251
+ const parsed = JSON.parse(row!.metadata!) as Record<string, unknown>;
252
+ const slackMeta = readSlackMetadata(parsed.slackMeta as string);
253
+ expect(slackMeta!.deletedAt).toBeUndefined();
254
+ });
255
+
256
+ test("delete for row without slackMeta is a no-op (legacy row)", async () => {
257
+ const seeded = seedSlackMessage({
258
+ externalChatId: "C0123CHANNEL",
259
+ originalTs: "2222.2222",
260
+ content: "Legacy pre-upgrade text",
261
+ withSlackMeta: false,
262
+ });
263
+
264
+ const req = buildSlackDeleteRequest({
265
+ externalChatId: seeded.externalChatId,
266
+ deletedTs: seeded.originalTs,
267
+ });
268
+ const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
269
+ const json = (await resp.json()) as Record<string, unknown>;
270
+
271
+ expect(json.accepted).toBe(true);
272
+ expect(json.deleted).toBe(false);
273
+
274
+ const db = getDb();
275
+ const row = db
276
+ .select()
277
+ .from(messages)
278
+ .where(eq(messages.id, seeded.messageId))
279
+ .get();
280
+
281
+ expect(row!.content).toBe("Legacy pre-upgrade text");
282
+ const parsed = JSON.parse(row!.metadata!) as Record<string, unknown>;
283
+ expect(parsed.slackMeta).toBeUndefined();
284
+ });
285
+
286
+ test("delete missing sourceMetadata.messageId is a no-op", async () => {
287
+ const seeded = seedSlackMessage({
288
+ externalChatId: "C0123CHANNEL",
289
+ originalTs: "3333.3333",
290
+ content: "Untouched",
291
+ withSlackMeta: true,
292
+ });
293
+
294
+ const req = new Request("http://localhost:8080/channels/inbound", {
295
+ method: "POST",
296
+ headers: {
297
+ "Content-Type": "application/json",
298
+ "X-Gateway-Origin": TEST_BEARER_TOKEN,
299
+ },
300
+ body: JSON.stringify({
301
+ sourceChannel: "slack",
302
+ interface: "slack",
303
+ conversationExternalId: seeded.externalChatId,
304
+ externalMessageId: "evt-del-no-source",
305
+ content: "",
306
+ callbackData: "message_deleted",
307
+ actorExternalId: SLACK_DELETE_ACTOR_ID,
308
+ // sourceMetadata intentionally omitted
309
+ }),
310
+ });
311
+ const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
312
+ const json = (await resp.json()) as Record<string, unknown>;
313
+
314
+ expect(json.accepted).toBe(true);
315
+ expect(json.deleted).toBe(false);
316
+
317
+ const db = getDb();
318
+ const row = db
319
+ .select()
320
+ .from(messages)
321
+ .where(eq(messages.id, seeded.messageId))
322
+ .get();
323
+ const parsed = JSON.parse(row!.metadata!) as Record<string, unknown>;
324
+ const slackMeta = readSlackMetadata(parsed.slackMeta as string);
325
+ expect(slackMeta!.deletedAt).toBeUndefined();
326
+ });
327
+
328
+ test("delete that races ahead of linkMessage is retried until the link lands", async () => {
329
+ // Simulates the race: a delete webhook arrives after `recordInbound`
330
+ // has inserted the original event row but before the agent-loop path
331
+ // has called `linkMessage` to bind it to a stored message. Without
332
+ // the retry loop the delete would silently no-op and the deletion
333
+ // signal would be lost.
334
+ const db = getDb();
335
+ const externalChatId = "C0123CHANNEL";
336
+ const originalTs = "5555.5555";
337
+ const inbound = recordInbound("slack", externalChatId, originalTs, {
338
+ sourceMessageId: originalTs,
339
+ });
340
+
341
+ const messageId = `msg-${originalTs}`;
342
+ const slackMeta = writeSlackMetadata({
343
+ source: "slack",
344
+ channelId: externalChatId,
345
+ channelTs: originalTs,
346
+ eventKind: "message",
347
+ displayName: "Test User",
348
+ });
349
+ db.insert(messages)
350
+ .values({
351
+ id: messageId,
352
+ conversationId: inbound.conversationId,
353
+ role: "user",
354
+ content: "Original text",
355
+ createdAt: Date.now(),
356
+ metadata: JSON.stringify({
357
+ userMessageChannel: "slack",
358
+ userMessageInterface: "slack",
359
+ slackMeta,
360
+ }),
361
+ })
362
+ .run();
363
+
364
+ // Shorten retries to a handful of small backoffs so the test is fast
365
+ // while still exercising the loop.
366
+ _setDeleteLookupConfigForTests(5, 50);
367
+
368
+ // Link the message after a short delay — this lands during one of the
369
+ // retry backoffs. Intentionally not awaited.
370
+ const LINK_DELAY_MS = 120;
371
+ setTimeout(() => {
372
+ linkMessage(inbound.eventId, messageId);
373
+ }, LINK_DELAY_MS);
374
+
375
+ const req = buildSlackDeleteRequest({
376
+ externalChatId,
377
+ deletedTs: originalTs,
378
+ });
379
+ const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
380
+ const json = (await resp.json()) as Record<string, unknown>;
381
+
382
+ expect(resp.status).toBe(200);
383
+ expect(json.accepted).toBe(true);
384
+ expect(json.deleted).toBe(true);
385
+ expect(json.messageId).toBe(messageId);
386
+
387
+ const row = db
388
+ .select()
389
+ .from(messages)
390
+ .where(eq(messages.id, messageId))
391
+ .get();
392
+ const parsed = JSON.parse(row!.metadata!) as Record<string, unknown>;
393
+ const parsedSlackMeta = readSlackMetadata(parsed.slackMeta as string);
394
+ expect(parsedSlackMeta!.deletedAt).toBeDefined();
395
+ });
396
+
397
+ test("delete from non-member actor is rejected by ACL and does not apply", async () => {
398
+ // Use a channel where NO active member is seeded so the actor cannot
399
+ // resolve via the channel's externalChatId either. Verifies that ACL
400
+ // enforcement rejects delete events from non-members before the delete
401
+ // handler processes them — the delete must not apply and no row should
402
+ // be mutated when the actor is not an active member of the target
403
+ // channel. Also clear the C0123CHANNEL seed for the alt channel below
404
+ // since beforeEach wires the seed on C0123CHANNEL only.
405
+ const altChannel = "C0_NON_MEMBER_CHAN";
406
+ const seeded = seedSlackMessage({
407
+ externalChatId: altChannel,
408
+ originalTs: "7777.7777",
409
+ content: "Original audited text",
410
+ withSlackMeta: true,
411
+ });
412
+
413
+ const req = buildSlackDeleteRequest({
414
+ externalChatId: seeded.externalChatId,
415
+ deletedTs: seeded.originalTs,
416
+ actorExternalId: "U_NON_MEMBER",
417
+ });
418
+ const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
419
+ const json = (await resp.json()) as Record<string, unknown>;
420
+
421
+ // ACL denies the inbound — the response must not carry `deleted: true`.
422
+ expect(json.deleted).not.toBe(true);
423
+
424
+ // The original row remains unmodified — content untouched and no
425
+ // deletedAt marker stamped on slackMeta.
426
+ const db = getDb();
427
+ const row = db
428
+ .select()
429
+ .from(messages)
430
+ .where(eq(messages.id, seeded.messageId))
431
+ .get();
432
+ expect(row!.content).toBe("Original audited text");
433
+ const parsed = JSON.parse(row!.metadata!) as Record<string, unknown>;
434
+ const slackMeta = readSlackMetadata(parsed.slackMeta as string);
435
+ expect(slackMeta!.deletedAt).toBeUndefined();
436
+ });
437
+ });