@vellumai/assistant 0.8.5 → 0.8.6

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 (544) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +1 -1
  3. package/bunfig.toml +6 -1
  4. package/docs/credential-execution-service.md +6 -6
  5. package/docs/plugins.md +4 -3
  6. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
  7. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
  8. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  9. package/openapi.yaml +1900 -166
  10. package/package.json +1 -1
  11. package/src/__tests__/actor-token-service.test.ts +3 -2
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
  13. package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
  14. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  15. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  16. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  17. package/src/__tests__/annotate-risk-options.test.ts +1 -0
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/approval-routes-http.test.ts +9 -13
  20. package/src/__tests__/assert-not-live-db.ts +79 -0
  21. package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
  22. package/src/__tests__/audit-log-rotation.test.ts +2 -2
  23. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  24. package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
  25. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  26. package/src/__tests__/btw-routes.test.ts +3 -2
  27. package/src/__tests__/call-controller.test.ts +3 -2
  28. package/src/__tests__/channel-approval-routes.test.ts +3 -2
  29. package/src/__tests__/channel-guardian.test.ts +3 -2
  30. package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
  31. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  32. package/src/__tests__/channel-retry-sweep.test.ts +320 -3
  33. package/src/__tests__/checker.test.ts +12 -12
  34. package/src/__tests__/compaction-events.test.ts +1 -0
  35. package/src/__tests__/compaction-trail-store.test.ts +264 -0
  36. package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
  37. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  38. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
  39. package/src/__tests__/computer-use-tools.test.ts +12 -14
  40. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  41. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  42. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  43. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  44. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  45. package/src/__tests__/config-schema.test.ts +10 -10
  46. package/src/__tests__/connection-model-compat.test.ts +83 -0
  47. package/src/__tests__/contacts-tools.test.ts +3 -2
  48. package/src/__tests__/context-token-estimator.test.ts +22 -0
  49. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
  50. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  52. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  53. package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
  54. package/src/__tests__/conversation-agent-loop.test.ts +488 -2
  55. package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
  56. package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
  57. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
  58. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  61. package/src/__tests__/conversation-error.test.ts +30 -0
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -8
  63. package/src/__tests__/conversation-fork-route.test.ts +3 -2
  64. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  65. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  66. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  67. package/src/__tests__/conversation-lifecycle.test.ts +1 -0
  68. package/src/__tests__/conversation-list-source.test.ts +3 -2
  69. package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
  70. package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
  71. package/src/__tests__/conversation-pairing.test.ts +53 -0
  72. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
  73. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  74. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
  75. package/src/__tests__/conversation-queue.test.ts +333 -291
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
  80. package/src/__tests__/conversation-skill-tools.test.ts +38 -142
  81. package/src/__tests__/conversation-slash-queue.test.ts +84 -32
  82. package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
  83. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
  85. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
  90. package/src/__tests__/conversation-sync-tags.test.ts +128 -12
  91. package/src/__tests__/conversation-title-service.test.ts +1 -0
  92. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
  93. package/src/__tests__/conversation-usage.test.ts +1 -0
  94. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  95. package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
  96. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
  97. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  98. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  99. package/src/__tests__/credential-execution-client.test.ts +72 -1
  100. package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
  101. package/src/__tests__/credential-health-service.test.ts +252 -3
  102. package/src/__tests__/credential-security-invariants.test.ts +5 -5
  103. package/src/__tests__/credential-vault-unit.test.ts +19 -19
  104. package/src/__tests__/credential-vault.test.ts +5 -5
  105. package/src/__tests__/cross-provider-web-search.test.ts +56 -2
  106. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  107. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  108. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  109. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  110. package/src/__tests__/db-test-helpers.ts +58 -0
  111. package/src/__tests__/disk-pressure-guard.test.ts +58 -41
  112. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  113. package/src/__tests__/disk-pressure-routes.test.ts +0 -33
  114. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  115. package/src/__tests__/dm-persistence.test.ts +26 -40
  116. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  117. package/src/__tests__/document-find-replace.test.ts +3 -2
  118. package/src/__tests__/document-tool-security.test.ts +81 -2
  119. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  120. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  121. package/src/__tests__/encrypted-store.test.ts +11 -9
  122. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  123. package/src/__tests__/filing-service.test.ts +1 -0
  124. package/src/__tests__/first-greeting.test.ts +62 -12
  125. package/src/__tests__/gateway-flag-listener.test.ts +0 -1
  126. package/src/__tests__/gemini-provider.test.ts +26 -0
  127. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  128. package/src/__tests__/guardian-outbound-http.test.ts +3 -2
  129. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  130. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
  131. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  132. package/src/__tests__/heartbeat-service.test.ts +1 -0
  133. package/src/__tests__/helpers/mock-logger.ts +26 -0
  134. package/src/__tests__/host-bash-routes.test.ts +1 -0
  135. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
  136. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  137. package/src/__tests__/host-shell-tool.test.ts +5 -4
  138. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  139. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  140. package/src/__tests__/http-user-message-parity.test.ts +29 -7
  141. package/src/__tests__/identity-intro-cache.test.ts +133 -22
  142. package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
  143. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  144. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  145. package/src/__tests__/injector-disk-pressure.test.ts +3 -17
  146. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  147. package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
  148. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  149. package/src/__tests__/llm-resolver.test.ts +331 -0
  150. package/src/__tests__/llm-schema.test.ts +1 -1
  151. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  152. package/src/__tests__/mcp-abort-signal.test.ts +14 -0
  153. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  154. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  155. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  156. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  157. package/src/__tests__/model-intents.test.ts +3 -3
  158. package/src/__tests__/native-web-search.test.ts +30 -2
  159. package/src/__tests__/notification-deep-link.test.ts +62 -0
  160. package/src/__tests__/oauth-commands-routes.test.ts +37 -0
  161. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  162. package/src/__tests__/oauth-store.test.ts +3 -2
  163. package/src/__tests__/onboarding-template-contract.test.ts +3 -2
  164. package/src/__tests__/openai-provider.test.ts +8 -9
  165. package/src/__tests__/openai-responses-provider.test.ts +70 -10
  166. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  167. package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
  168. package/src/__tests__/persistence-pipeline.test.ts +139 -1
  169. package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
  170. package/src/__tests__/plugin-bootstrap.test.ts +9 -11
  171. package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
  172. package/src/__tests__/process-message-background-slack.test.ts +21 -16
  173. package/src/__tests__/process-message-display-content.test.ts +19 -22
  174. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  175. package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
  176. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  177. package/src/__tests__/recording-handler.test.ts +1 -0
  178. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  179. package/src/__tests__/registry.test.ts +82 -76
  180. package/src/__tests__/relay-server.test.ts +10 -10
  181. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  182. package/src/__tests__/schedule-store.test.ts +16 -1
  183. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  184. package/src/__tests__/secret-ingress-http.test.ts +5 -1
  185. package/src/__tests__/secure-keys.test.ts +3 -3
  186. package/src/__tests__/send-endpoint-busy.test.ts +81 -42
  187. package/src/__tests__/server-history-render.test.ts +4 -1
  188. package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
  189. package/src/__tests__/skill-feature-flags.test.ts +14 -16
  190. package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
  191. package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
  192. package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
  193. package/src/__tests__/skill-tool-factory.test.ts +96 -95
  194. package/src/__tests__/slack-channel-config.test.ts +3 -3
  195. package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
  196. package/src/__tests__/subagent-disposal.test.ts +27 -8
  197. package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
  198. package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
  199. package/src/__tests__/subagent-manager-notify.test.ts +20 -8
  200. package/src/__tests__/subagent-notify-parent.test.ts +5 -4
  201. package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
  202. package/src/__tests__/subagent-tools.test.ts +2 -1
  203. package/src/__tests__/suggestion-routes.test.ts +1 -0
  204. package/src/__tests__/system-prompt.test.ts +38 -0
  205. package/src/__tests__/test-preload-verifier.ts +68 -0
  206. package/src/__tests__/test-preload.ts +32 -39
  207. package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
  208. package/src/__tests__/tool-executor.test.ts +55 -10
  209. package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
  210. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  211. package/src/__tests__/twilio-routes.test.ts +3 -2
  212. package/src/__tests__/validate-input.test.ts +381 -0
  213. package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
  214. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
  215. package/src/__tests__/voice-session-bridge.test.ts +37 -28
  216. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  217. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  218. package/src/acp/session-manager.ts +5 -6
  219. package/src/agent/loop.ts +80 -0
  220. package/src/api/README.md +124 -2
  221. package/src/api/constants/call-sites.ts +27 -0
  222. package/src/api/events/assistant-outbound-attachment.ts +51 -0
  223. package/src/api/events/assistant-text-delta.ts +32 -0
  224. package/src/api/events/assistant-turn-start.ts +33 -0
  225. package/src/api/events/document-comment-created.ts +48 -0
  226. package/src/api/events/document-comment-deleted.ts +24 -0
  227. package/src/api/events/document-comment-reopened.ts +25 -0
  228. package/src/api/events/document-comment-resolved.ts +27 -0
  229. package/src/api/events/generation-cancelled.ts +24 -0
  230. package/src/api/events/generation-handoff.ts +41 -0
  231. package/src/api/events/message-complete.ts +42 -0
  232. package/src/api/events/open-url.ts +30 -0
  233. package/src/{events → api/events}/relationship-state-updated.ts +3 -3
  234. package/src/api/events/tool-use-start.ts +32 -0
  235. package/src/api/index.ts +128 -3
  236. package/src/api/responses/llm-context-response.ts +39 -0
  237. package/src/api/responses/llm-request-log-entry.ts +93 -0
  238. package/src/api/responses/memory-recall-log.ts +65 -0
  239. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  240. package/src/background-wake/background-wake-routes.test.ts +687 -52
  241. package/src/background-wake/platform-client.test.ts +308 -0
  242. package/src/background-wake/platform-client.ts +167 -0
  243. package/src/background-wake/publisher.ts +91 -0
  244. package/src/background-wake/runtime-registry.ts +2 -2
  245. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  246. package/src/calls/guardian-dispatch.ts +1 -0
  247. package/src/calls/voice-session-bridge.ts +4 -4
  248. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  249. package/src/cli/commands/__tests__/notifications.test.ts +184 -40
  250. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  251. package/src/cli/commands/channels/index.ts +229 -0
  252. package/src/cli/commands/memory-v3-render.ts +147 -0
  253. package/src/cli/commands/memory-v3.ts +255 -4
  254. package/src/cli/commands/notifications.ts +365 -55
  255. package/src/cli/lib/open-browser.ts +7 -2
  256. package/src/cli/program.ts +2 -0
  257. package/src/config/assistant-feature-flags.ts +23 -42
  258. package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
  259. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  260. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  261. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  262. package/src/config/call-site-defaults.ts +1 -1
  263. package/src/config/feature-flag-cache.ts +86 -0
  264. package/src/config/feature-flag-registry.json +17 -17
  265. package/src/config/llm-context-resolution.ts +10 -1
  266. package/src/config/llm-resolver.ts +121 -15
  267. package/src/config/loader.ts +4 -5
  268. package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
  269. package/src/config/schemas/heartbeat.ts +1 -1
  270. package/src/config/schemas/llm.ts +90 -1
  271. package/src/config/schemas/memory-v2.ts +26 -0
  272. package/src/config/schemas/services.ts +6 -2
  273. package/src/config/seed-inference-profiles.ts +36 -16
  274. package/src/context/token-estimator.ts +10 -5
  275. package/src/credential-execution/executable-discovery.ts +40 -0
  276. package/src/credential-execution/process-manager.ts +6 -2
  277. package/src/credential-health/credential-health-service.ts +125 -40
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
  279. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
  280. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
  281. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  282. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  283. package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
  284. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  285. package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
  286. package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
  287. package/src/daemon/conversation-agent-loop.ts +132 -28
  288. package/src/daemon/conversation-error.ts +33 -5
  289. package/src/daemon/conversation-messaging.ts +84 -43
  290. package/src/daemon/conversation-process.ts +74 -37
  291. package/src/daemon/conversation-runtime-assembly.ts +29 -9
  292. package/src/daemon/conversation-skill-tools.ts +14 -30
  293. package/src/daemon/conversation-surfaces.ts +69 -34
  294. package/src/daemon/conversation-tool-setup.ts +33 -48
  295. package/src/daemon/conversation.ts +26 -46
  296. package/src/daemon/daemon-control.ts +1 -1
  297. package/src/daemon/daemon-skill-host.ts +9 -2
  298. package/src/daemon/disk-pressure-guard.ts +27 -29
  299. package/src/daemon/first-greeting.ts +31 -13
  300. package/src/daemon/handlers/shared.ts +6 -1
  301. package/src/daemon/lifecycle.ts +12 -12
  302. package/src/daemon/mcp-reload-service.ts +1 -1
  303. package/src/daemon/meet-manifest-loader.ts +10 -17
  304. package/src/daemon/message-types/conversations.ts +20 -22
  305. package/src/daemon/message-types/document-comments.ts +8 -44
  306. package/src/daemon/message-types/home.ts +2 -2
  307. package/src/daemon/message-types/integrations.ts +2 -7
  308. package/src/daemon/message-types/messages.ts +23 -38
  309. package/src/daemon/message-types/subagents.ts +6 -0
  310. package/src/daemon/process-message.ts +9 -9
  311. package/src/daemon/providers-setup.ts +1 -1
  312. package/src/daemon/server.ts +16 -0
  313. package/src/daemon/switch-inference-profile-tool.ts +13 -3
  314. package/src/daemon/tool-setup-types.ts +0 -6
  315. package/src/daemon/wake-target-adapter.ts +10 -0
  316. package/src/documents/document-store.ts +38 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  318. package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
  319. package/src/heartbeat/heartbeat-service.ts +63 -0
  320. package/src/home/__tests__/feed-writer.test.ts +161 -0
  321. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  322. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  323. package/src/home/feed-writer.ts +146 -7
  324. package/src/home/suggested-prompts.ts +27 -145
  325. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  326. package/src/ipc/gateway-client.test.ts +4 -1
  327. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
  328. package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
  329. package/src/ipc/skill-routes/memory.ts +4 -3
  330. package/src/ipc/skill-routes/registries.ts +28 -29
  331. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
  332. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
  333. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  334. package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
  335. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  336. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  337. package/src/memory/conversation-attention-store.ts +17 -3
  338. package/src/memory/conversation-crud.ts +352 -112
  339. package/src/memory/db-connection.ts +29 -19
  340. package/src/memory/db-init.ts +4 -0
  341. package/src/memory/db-singleton.ts +77 -0
  342. package/src/memory/delivery-channels.ts +82 -0
  343. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  344. package/src/memory/graph/retriever.test.ts +3 -3
  345. package/src/memory/job-handlers/embedding.test.ts +3 -2
  346. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  347. package/src/memory/jobs-worker.ts +12 -1
  348. package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
  349. package/src/memory/llm-request-log-source-local.ts +24 -0
  350. package/src/memory/llm-request-log-source.ts +31 -0
  351. package/src/memory/llm-request-log-store.ts +188 -3
  352. package/src/memory/memory-v2-activation-log-store.ts +95 -1
  353. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  354. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  355. package/src/memory/migrations/index.ts +2 -0
  356. package/src/memory/schema/conversations.ts +9 -1
  357. package/src/memory/schema/inference.ts +0 -1
  358. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  359. package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
  362. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
  363. package/src/memory/v2/harness/metrics.ts +5 -1
  364. package/src/memory/v2/harness/replay-input.ts +19 -3
  365. package/src/memory/v2/harness/runner.ts +6 -0
  366. package/src/memory/v2/harness/trace.ts +6 -0
  367. package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
  368. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
  369. package/src/memory/v3/__tests__/edges.test.ts +144 -1
  370. package/src/memory/v3/__tests__/filter.test.ts +48 -0
  371. package/src/memory/v3/__tests__/gate.test.ts +96 -33
  372. package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
  373. package/src/memory/v3/__tests__/loop.test.ts +250 -5
  374. package/src/memory/v3/__tests__/scouts.test.ts +49 -0
  375. package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
  376. package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
  377. package/src/memory/v3/__tests__/traversal.test.ts +39 -0
  378. package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
  379. package/src/memory/v3/__tests__/validate.test.ts +32 -0
  380. package/src/memory/v3/coretrieval-seed.ts +240 -0
  381. package/src/memory/v3/edges.ts +58 -21
  382. package/src/memory/v3/filter.ts +27 -22
  383. package/src/memory/v3/gate.ts +51 -36
  384. package/src/memory/v3/index-composition.ts +18 -5
  385. package/src/memory/v3/loop.ts +65 -17
  386. package/src/memory/v3/scouts.ts +15 -4
  387. package/src/memory/v3/shadow-diff.ts +287 -0
  388. package/src/memory/v3/shadow-middleware.ts +44 -2
  389. package/src/memory/v3/traversal.ts +6 -1
  390. package/src/memory/v3/tree-walk.ts +6 -1
  391. package/src/memory/v3/validate.ts +56 -33
  392. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  393. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  394. package/src/notifications/adapters/slack.ts +45 -11
  395. package/src/notifications/broadcaster.ts +114 -63
  396. package/src/notifications/conversation-pairing.ts +23 -3
  397. package/src/notifications/decisions-store.ts +32 -1
  398. package/src/notifications/deliveries-store.ts +45 -0
  399. package/src/notifications/edit-notification.ts +201 -0
  400. package/src/notifications/emit-signal.ts +11 -1
  401. package/src/notifications/signal.ts +10 -0
  402. package/src/notifications/types.ts +37 -0
  403. package/src/oauth/byo-connection.test.ts +67 -3
  404. package/src/oauth/byo-connection.ts +32 -5
  405. package/src/oauth/connect-orchestrator.ts +9 -0
  406. package/src/oauth/connection-resolver.test.ts +76 -0
  407. package/src/oauth/connection-resolver.ts +49 -10
  408. package/src/oauth/manual-token-connection.ts +51 -3
  409. package/src/oauth/seed-providers.ts +3 -0
  410. package/src/permissions/approval-policy.test.ts +19 -5
  411. package/src/permissions/approval-policy.ts +14 -3
  412. package/src/permissions/checker.ts +21 -8
  413. package/src/platform/client.test.ts +24 -1
  414. package/src/platform/client.ts +8 -0
  415. package/src/platform/feature-gate.ts +15 -0
  416. package/src/plugins/defaults/injectors.ts +2 -8
  417. package/src/plugins/defaults/persistence.ts +25 -6
  418. package/src/plugins/types.ts +57 -13
  419. package/src/proactive-artifact/job.test.ts +1 -0
  420. package/src/prompts/__tests__/system-prompt.test.ts +4 -4
  421. package/src/prompts/system-prompt.ts +38 -40
  422. package/src/prompts/template-detection.ts +10 -4
  423. package/src/prompts/templates/BOOTSTRAP.md +7 -11
  424. package/src/prompts/templates/IDENTITY.md +0 -2
  425. package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
  426. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  427. package/src/providers/call-site-routing.ts +33 -9
  428. package/src/providers/connection-model-compat.ts +23 -0
  429. package/src/providers/connection-resolution.ts +39 -20
  430. package/src/providers/fireworks/client.ts +1 -0
  431. package/src/providers/gemini/client.ts +24 -3
  432. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  433. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  434. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  435. package/src/providers/inference/auth.ts +0 -8
  436. package/src/providers/inference/connections.ts +3 -66
  437. package/src/providers/inference/resolve-auth.ts +2 -3
  438. package/src/providers/model-catalog.ts +35 -1
  439. package/src/providers/model-intents.ts +3 -3
  440. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  441. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
  442. package/src/providers/openai/chat-completions-provider.ts +110 -12
  443. package/src/providers/openai/codex-models.ts +2 -0
  444. package/src/providers/openai/responses-provider.ts +53 -53
  445. package/src/providers/openrouter/client.ts +13 -8
  446. package/src/providers/provider-send-message.ts +18 -9
  447. package/src/providers/registry.ts +48 -8
  448. package/src/providers/retry.ts +16 -4
  449. package/src/providers/search-provider-catalog.ts +17 -9
  450. package/src/providers/types.ts +9 -0
  451. package/src/runtime/__tests__/agent-wake.test.ts +1 -0
  452. package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
  453. package/src/runtime/access-request-helper.ts +1 -0
  454. package/src/runtime/auth/route-policy.ts +10 -0
  455. package/src/runtime/channel-readiness-service.ts +68 -0
  456. package/src/runtime/channel-reply-delivery.ts +23 -0
  457. package/src/runtime/channel-retry-sweep.ts +47 -14
  458. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  459. package/src/runtime/migrations/vbundle-builder.ts +3 -2
  460. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  461. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
  462. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  463. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  464. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  465. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
  466. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
  467. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
  468. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  469. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
  470. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  471. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  472. package/src/runtime/routes/app-management-routes.ts +111 -4
  473. package/src/runtime/routes/background-wake-routes.ts +188 -20
  474. package/src/runtime/routes/btw-routes.ts +4 -4
  475. package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
  476. package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
  477. package/src/runtime/routes/conversation-list-routes.ts +147 -0
  478. package/src/runtime/routes/conversation-management-routes.ts +39 -14
  479. package/src/runtime/routes/conversation-query-routes.ts +60 -10
  480. package/src/runtime/routes/conversation-routes.ts +186 -140
  481. package/src/runtime/routes/conversations-import-routes.ts +19 -6
  482. package/src/runtime/routes/documents-routes.ts +10 -1
  483. package/src/runtime/routes/group-routes.ts +11 -0
  484. package/src/runtime/routes/home-feed-routes.ts +129 -0
  485. package/src/runtime/routes/identity-intro-cache.ts +61 -16
  486. package/src/runtime/routes/identity-routes.ts +30 -9
  487. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
  488. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
  489. package/src/runtime/routes/index.ts +2 -0
  490. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
  491. package/src/runtime/routes/integrations/vercel.ts +15 -0
  492. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  493. package/src/runtime/routes/memory-v3-routes.ts +160 -2
  494. package/src/runtime/routes/migration-routes.ts +20 -13
  495. package/src/runtime/routes/notification-routes.ts +63 -1
  496. package/src/runtime/routes/oauth-commands-routes.ts +6 -1
  497. package/src/runtime/routes/surface-action-routes.ts +1 -38
  498. package/src/runtime/routes/surface-content-routes.ts +12 -5
  499. package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
  500. package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
  501. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
  502. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  503. package/src/runtime/sync/resource-sync-events.ts +1 -1
  504. package/src/runtime/tool-grant-request-helper.ts +1 -0
  505. package/src/schedule/schedule-store.ts +8 -1
  506. package/src/schedule/scheduler.ts +111 -15
  507. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  508. package/src/security/encrypted-store.ts +7 -16
  509. package/src/security/store-path-override.ts +61 -0
  510. package/src/signals/user-message.ts +5 -8
  511. package/src/skills/validate-input.ts +177 -0
  512. package/src/subagent/manager.ts +13 -13
  513. package/src/subagent/types.ts +6 -0
  514. package/src/tasks/tool-sanitizer.ts +2 -2
  515. package/src/tools/apps/definitions.ts +35 -21
  516. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  517. package/src/tools/computer-use/definitions.ts +268 -266
  518. package/src/tools/document/document-tool.ts +131 -8
  519. package/src/tools/execution-target.ts +2 -5
  520. package/src/tools/executor.ts +18 -55
  521. package/src/tools/host-filesystem/edit.test.ts +1 -0
  522. package/src/tools/host-filesystem/read.test.ts +1 -0
  523. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  524. package/src/tools/host-filesystem/write.test.ts +1 -0
  525. package/src/tools/mcp/mcp-tool-factory.ts +0 -2
  526. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  527. package/src/tools/network/__tests__/web-search.test.ts +211 -3
  528. package/src/tools/network/managed-search-proxy.ts +183 -0
  529. package/src/tools/network/web-search.ts +199 -44
  530. package/src/tools/policy-context.ts +3 -1
  531. package/src/tools/registry.ts +146 -103
  532. package/src/tools/schedule/create.ts +1 -1
  533. package/src/tools/skills/skill-tool-factory.ts +17 -36
  534. package/src/tools/subagent/spawn.ts +3 -0
  535. package/src/tools/tool-approval-handler.ts +10 -4
  536. package/src/tools/tool-name-aliases.ts +72 -14
  537. package/src/tools/types.ts +17 -15
  538. package/src/tools/ui-surface/definitions.ts +98 -86
  539. package/src/types/onboarding-context.ts +6 -0
  540. package/src/usage/attribution.ts +32 -1
  541. package/src/util/browser.ts +7 -2
  542. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  543. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  544. package/src/workspace/migrations/registry.ts +4 -0
@@ -5,7 +5,6 @@ import type { DiskUsageInfo } from "../util/disk-usage.js";
5
5
 
6
6
  let diskSample: DiskUsageInfo | null = null;
7
7
  let diskSampleError: unknown = null;
8
- let diskSampleCalls = 0;
9
8
 
10
9
  mock.module("../config/loader.js", () => ({
11
10
  getConfig: () => ({}),
@@ -13,7 +12,6 @@ mock.module("../config/loader.js", () => ({
13
12
 
14
13
  mock.module("../util/disk-usage.js", () => ({
15
14
  getDiskUsageInfo: () => {
16
- diskSampleCalls += 1;
17
15
  if (diskSampleError) throw diskSampleError;
18
16
  return diskSample;
19
17
  },
@@ -38,9 +36,8 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
38
36
  },
39
37
  }));
40
38
 
41
- const { _setOverridesForTesting } =
42
- await import("../config/assistant-feature-flags.js");
43
39
  const {
40
+ DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT,
44
41
  DISK_PRESSURE_OVERRIDE_CONFIRMATION,
45
42
  DISK_PRESSURE_THRESHOLD_PERCENT,
46
43
  __getDiskPressureGuardTimerForTests,
@@ -53,10 +50,6 @@ const {
53
50
  stopDiskPressureGuard,
54
51
  } = await import("../daemon/disk-pressure-guard.js");
55
52
 
56
- function setFeatureFlag(enabled: boolean): void {
57
- _setOverridesForTesting({ "safe-storage-limits": enabled });
58
- }
59
-
60
53
  function setDiskUsage(usedMb: number, totalMb = 100): void {
61
54
  diskSample = {
62
55
  path: "/workspace",
@@ -80,35 +73,16 @@ function expectRejected(
80
73
 
81
74
  beforeEach(() => {
82
75
  __resetDiskPressureGuardForTests();
83
- setFeatureFlag(true);
84
76
  setDiskUsage(10);
85
- diskSampleCalls = 0;
86
77
  });
87
78
 
88
79
  afterEach(() => {
89
80
  __resetDiskPressureGuardForTests();
90
- _setOverridesForTesting({});
91
81
  diskSample = null;
92
82
  diskSampleError = null;
93
- diskSampleCalls = 0;
94
83
  });
95
84
 
96
85
  describe("disk pressure guard", () => {
97
- test("returns a stable disabled status without sampling when the flag is disabled", () => {
98
- setDiskUsage(99);
99
- setFeatureFlag(false);
100
-
101
- const status = evaluateDiskPressureNow();
102
-
103
- expect(status.enabled).toBe(false);
104
- expect(status.state).toBe("disabled");
105
- expect(status.locked).toBe(false);
106
- expect(status.effectivelyLocked).toBe(false);
107
- expect(status.usagePercent).toBeNull();
108
- expect(diskSampleCalls).toBe(0);
109
- expect(getDiskPressureStatus()).toEqual(status);
110
- });
111
-
112
86
  test("locks when sampled usage reaches the threshold", () => {
113
87
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT);
114
88
 
@@ -158,6 +132,63 @@ describe("disk pressure guard", () => {
158
132
  expect(status.blockedCapabilities).toEqual([]);
159
133
  });
160
134
 
135
+ test("does not lock within the deadband until usage reaches the critical threshold", () => {
136
+ setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
137
+
138
+ const status = evaluateDiskPressureNow();
139
+
140
+ expect(status.state).toBe("warning");
141
+ expect(status.locked).toBe(false);
142
+ expect(status.effectivelyLocked).toBe(false);
143
+ });
144
+
145
+ test("stays locked while usage stays within the hysteresis deadband", () => {
146
+ setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
147
+ const locked = evaluateDiskPressureNow();
148
+ expect(locked.locked).toBe(true);
149
+ const { lockId } = locked;
150
+
151
+ // Below critical (95) but above clear (90): must hold, not flap.
152
+ setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
153
+ const status = evaluateDiskPressureNow();
154
+
155
+ expect(status.state).toBe("critical");
156
+ expect(status.locked).toBe(true);
157
+ expect(status.effectivelyLocked).toBe(true);
158
+ // Same lock id — the dip did not mint a fresh lock.
159
+ expect(status.lockId).toBe(lockId);
160
+ });
161
+
162
+ test("preserves acknowledgement across a dip within the deadband", () => {
163
+ setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
164
+ evaluateDiskPressureNow();
165
+ acknowledgeDiskPressureLock();
166
+
167
+ setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
168
+ const status = evaluateDiskPressureNow();
169
+
170
+ expect(status.locked).toBe(true);
171
+ expect(status.acknowledged).toBe(true);
172
+ });
173
+
174
+ test("clears the lock only once usage falls below the clear threshold", () => {
175
+ setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
176
+ evaluateDiskPressureNow();
177
+
178
+ // Still within the deadband: locked.
179
+ setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
180
+ expect(evaluateDiskPressureNow().locked).toBe(true);
181
+
182
+ // Below the clear threshold: released.
183
+ setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT - 2);
184
+ const status = evaluateDiskPressureNow();
185
+
186
+ expect(status.locked).toBe(false);
187
+ expect(status.effectivelyLocked).toBe(false);
188
+ expect(status.lockId).toBeNull();
189
+ expect(status.blockedCapabilities).toEqual([]);
190
+ });
191
+
161
192
  test("overrides an active lock only with the exact confirmation after trimming whitespace", () => {
162
193
  setDiskUsage(99);
163
194
  evaluateDiskPressureNow();
@@ -245,18 +276,4 @@ describe("disk pressure guard", () => {
245
276
  stopDiskPressureGuard();
246
277
  expect(__getDiskPressureGuardTimerForTests()).toBeNull();
247
278
  });
248
-
249
- test("disabling the flag clears an active timer and lock", () => {
250
- setDiskUsage(99);
251
- evaluateDiskPressureNow();
252
- startDiskPressureGuard();
253
- expect(__getDiskPressureGuardTimerForTests()).toBeTruthy();
254
-
255
- setFeatureFlag(false);
256
- const status = evaluateDiskPressureNow();
257
-
258
- expect(status.enabled).toBe(false);
259
- expect(status.locked).toBe(false);
260
- expect(__getDiskPressureGuardTimerForTests()).toBeNull();
261
- });
262
279
  });
@@ -1,5 +1,7 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
+ import { createMockLoggerModule } from "./helpers/mock-logger.js";
4
+
3
5
  const warnCalls: unknown[] = [];
4
6
  let guardEnabled = true;
5
7
  let startCalls = 0;
@@ -81,17 +83,18 @@ mock.module("../daemon/disk-pressure-guard.js", () => ({
81
83
  DISK_PRESSURE_OVERRIDE_CONFIRMATION: "I understand the risks",
82
84
  }));
83
85
 
84
- mock.module("../util/logger.js", () => ({
85
- getLogger: () => ({
86
- debug: () => {},
87
- error: () => {},
88
- info: () => {},
89
- warn: (...args: unknown[]) => {
90
- warnCalls.push(args);
91
- },
86
+ mock.module("../util/logger.js", () =>
87
+ createMockLoggerModule({
88
+ getLogger: () => ({
89
+ debug: () => {},
90
+ error: () => {},
91
+ info: () => {},
92
+ warn: (...args: unknown[]) => {
93
+ warnCalls.push(args);
94
+ },
95
+ }),
92
96
  }),
93
- initLogger: () => {},
94
- }));
97
+ );
95
98
 
96
99
  const {
97
100
  startDiskPressureGuardForLifecycle,
@@ -42,8 +42,6 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
42
42
  },
43
43
  }));
44
44
 
45
- const { _setOverridesForTesting } =
46
- await import("../config/assistant-feature-flags.js");
47
45
  const {
48
46
  DISK_PRESSURE_OVERRIDE_CONFIRMATION,
49
47
  DISK_PRESSURE_THRESHOLD_PERCENT,
@@ -73,10 +71,6 @@ type DiskPressureRouteResult = {
73
71
  };
74
72
  };
75
73
 
76
- function setFeatureFlag(enabled: boolean): void {
77
- _setOverridesForTesting({ "safe-storage-limits": enabled });
78
- }
79
-
80
74
  function setDiskUsage(usedMb: number, totalMb = 100): void {
81
75
  diskSample = {
82
76
  path: "/workspace",
@@ -137,13 +131,11 @@ async function flushPublishedEvents(): Promise<void> {
137
131
 
138
132
  beforeEach(() => {
139
133
  __resetDiskPressureGuardForTests();
140
- setFeatureFlag(true);
141
134
  setDiskUsage(10);
142
135
  });
143
136
 
144
137
  afterEach(() => {
145
138
  __resetDiskPressureGuardForTests();
146
- _setOverridesForTesting({});
147
139
  diskSample = null;
148
140
  eventSubscribers.clear();
149
141
  });
@@ -164,31 +156,6 @@ describe("disk pressure routes", () => {
164
156
  }
165
157
  });
166
158
 
167
- test("returns disabled status without error when the feature flag is off", async () => {
168
- setFeatureFlag(false);
169
- setDiskUsage(99);
170
-
171
- const result = await callRoute("disk-pressure/status", "GET");
172
-
173
- expect(result.status).toMatchObject({
174
- enabled: false,
175
- state: "disabled",
176
- locked: false,
177
- acknowledged: false,
178
- overrideActive: false,
179
- effectivelyLocked: false,
180
- lockId: null,
181
- usagePercent: null,
182
- path: null,
183
- lastCheckedAt: null,
184
- blockedCapabilities: [],
185
- error: null,
186
- });
187
- expect(result.status.thresholdPercent).toBe(
188
- DISK_PRESSURE_THRESHOLD_PERCENT,
189
- );
190
- });
191
-
192
159
  test("returns the full status shape for an active lock", async () => {
193
160
  setDiskUsage(99);
194
161
  evaluateDiskPressureNow();
@@ -80,8 +80,6 @@ mock.module("../util/disk-usage.js", () => ({
80
80
  getDiskUsageInfo: () => diskSample,
81
81
  }));
82
82
 
83
- const { _setOverridesForTesting } =
84
- await import("../config/assistant-feature-flags.js");
85
83
  const {
86
84
  DISK_PRESSURE_THRESHOLD_PERCENT,
87
85
  __resetDiskPressureGuardForTests,
@@ -127,14 +125,12 @@ function setDiskUsage(usedMb: number, totalMb = 100): void {
127
125
  beforeEach(() => {
128
126
  _clearRegistryForTesting();
129
127
  __resetDiskPressureGuardForTests();
130
- _setOverridesForTesting({ "safe-storage-limits": true });
131
128
  setDiskUsage(10);
132
129
  });
133
130
 
134
131
  afterEach(() => {
135
132
  _clearRegistryForTesting();
136
133
  __resetDiskPressureGuardForTests();
137
- _setOverridesForTesting({});
138
134
  diskSample = null;
139
135
  });
140
136
 
@@ -43,6 +43,7 @@ mock.module("../memory/conversation-crud.js", () => ({
43
43
  provenanceFromTrustContext: () => ({}),
44
44
  setConversationOriginChannelIfUnset: () => {},
45
45
  setConversationOriginInterfaceIfUnset: () => {},
46
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
46
47
  }));
47
48
 
48
49
  mock.module("../memory/conversation-disk-view.js", () => ({
@@ -120,20 +121,17 @@ describe("PR 16 — Slack DM persistence parity", () => {
120
121
  // ingress handler builds a `slackInbound` with no `threadTs` and threads
121
122
  // it through to persistence.
122
123
  const ctx = createSlackTurnContext();
123
- await persistQueuedMessageBody(
124
- ctx,
125
- "hello from DM",
126
- [],
127
- "req-dm",
128
- {
124
+ await persistQueuedMessageBody(ctx, {
125
+ content: "hello from DM",
126
+ requestId: "req-dm",
127
+ metadata: {
129
128
  slackInbound: {
130
129
  channelId: "D0123DM",
131
130
  channelTs: "1700000000.123456",
132
131
  displayName: "Alice",
133
132
  },
134
133
  },
135
- undefined,
136
- );
134
+ });
137
135
 
138
136
  const slackMeta = lastPersistedSlackMeta();
139
137
  expect(slackMeta).not.toBeNull();
@@ -157,19 +155,16 @@ describe("PR 16 — Slack DM persistence parity", () => {
157
155
  // gateway can't resolve the user). The envelope should still be written;
158
156
  // only the optional displayName field is omitted.
159
157
  const ctx = createSlackTurnContext();
160
- await persistQueuedMessageBody(
161
- ctx,
162
- "anonymous DM",
163
- [],
164
- "req-dm-anon",
165
- {
158
+ await persistQueuedMessageBody(ctx, {
159
+ content: "anonymous DM",
160
+ requestId: "req-dm-anon",
161
+ metadata: {
166
162
  slackInbound: {
167
163
  channelId: "D9999DM",
168
164
  channelTs: "1700000000.555555",
169
165
  },
170
166
  },
171
- undefined,
172
- );
167
+ });
173
168
 
174
169
  const slackMeta = lastPersistedSlackMeta();
175
170
  expect(slackMeta).not.toBeNull();
@@ -181,12 +176,10 @@ describe("PR 16 — Slack DM persistence parity", () => {
181
176
 
182
177
  test("DM inbound persists Slack actor timezone metadata", async () => {
183
178
  const ctx = createSlackTurnContext();
184
- await persistQueuedMessageBody(
185
- ctx,
186
- "hello across timezones",
187
- [],
188
- "req-dm-timezone",
189
- {
179
+ await persistQueuedMessageBody(ctx, {
180
+ content: "hello across timezones",
181
+ requestId: "req-dm-timezone",
182
+ metadata: {
190
183
  slackInbound: {
191
184
  channelId: "D0123DM",
192
185
  channelTs: "1700000000.777777",
@@ -199,8 +192,7 @@ describe("PR 16 — Slack DM persistence parity", () => {
199
192
  speakerTimezoneLabel: "ET",
200
193
  },
201
194
  },
202
- undefined,
203
- );
195
+ });
204
196
 
205
197
  const slackMeta = lastPersistedSlackMeta();
206
198
  expect(slackMeta).not.toBeNull();
@@ -215,12 +207,10 @@ describe("PR 16 — Slack DM persistence parity", () => {
215
207
  test("DM and channel-message envelopes differ only by threadTs", async () => {
216
208
  // Capture the channel-thread case first.
217
209
  const ctx = createSlackTurnContext();
218
- await persistQueuedMessageBody(
219
- ctx,
220
- "channel thread reply",
221
- [],
222
- "req-channel",
223
- {
210
+ await persistQueuedMessageBody(ctx, {
211
+ content: "channel thread reply",
212
+ requestId: "req-channel",
213
+ metadata: {
224
214
  slackInbound: {
225
215
  channelId: "C0123CHAN",
226
216
  channelTs: "1700000000.999999",
@@ -228,8 +218,7 @@ describe("PR 16 — Slack DM persistence parity", () => {
228
218
  displayName: "Bob",
229
219
  },
230
220
  },
231
- undefined,
232
- );
221
+ });
233
222
  const channelMeta = lastPersistedSlackMeta();
234
223
  expect(channelMeta).not.toBeNull();
235
224
  expect(channelMeta!.threadTs).toBe("1700000000.111111");
@@ -237,20 +226,17 @@ describe("PR 16 — Slack DM persistence parity", () => {
237
226
  // Now dispatch a DM and assert that every shared field has the same
238
227
  // shape — only `threadTs` (and the inputs themselves) differ.
239
228
  addMessageCalls.length = 0;
240
- await persistQueuedMessageBody(
241
- ctx,
242
- "DM reply",
243
- [],
244
- "req-dm-2",
245
- {
229
+ await persistQueuedMessageBody(ctx, {
230
+ content: "DM reply",
231
+ requestId: "req-dm-2",
232
+ metadata: {
246
233
  slackInbound: {
247
234
  channelId: "D9999DM",
248
235
  channelTs: "1700000000.222222",
249
236
  displayName: "Carol",
250
237
  },
251
238
  },
252
- undefined,
253
- );
239
+ });
254
240
  const dmMeta = lastPersistedSlackMeta();
255
241
  expect(dmMeta).not.toBeNull();
256
242
  expect(dmMeta!.source).toBe(channelMeta!.source);
@@ -0,0 +1,189 @@
1
+ import { beforeEach, describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ getDocumentById,
5
+ getDocumentsForConversation,
6
+ } from "../documents/document-store.js";
7
+ import { getSqlite } from "../memory/db-connection.js";
8
+ import { executeDocumentCreate } from "../tools/document/document-tool.js";
9
+ import type { ToolContext, ToolExecutionResult } from "../tools/types.js";
10
+ import { resetDbForTesting } from "./db-test-helpers.js";
11
+
12
+ function makeContext(overrides: Partial<ToolContext> = {}): ToolContext {
13
+ return {
14
+ workingDir: "/tmp/project",
15
+ conversationId: "conv-current",
16
+ trustClass: "trusted_contact",
17
+ executionChannel: "slack",
18
+ sendToClient: () => {},
19
+ ...overrides,
20
+ };
21
+ }
22
+
23
+ function parseResult<T>(result: ToolExecutionResult): T {
24
+ return JSON.parse(result.content) as T;
25
+ }
26
+
27
+ function bootstrapDocumentTables(): void {
28
+ resetDbForTesting();
29
+ const raw = getSqlite();
30
+ raw.exec(/*sql*/ `
31
+ DROP TABLE IF EXISTS document_conversations;
32
+ DROP TABLE IF EXISTS documents;
33
+ DROP TABLE IF EXISTS conversations;
34
+
35
+ CREATE TABLE conversations (
36
+ id TEXT PRIMARY KEY,
37
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)
38
+ );
39
+
40
+ CREATE TABLE documents (
41
+ surface_id TEXT PRIMARY KEY,
42
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
43
+ title TEXT NOT NULL,
44
+ content TEXT NOT NULL,
45
+ word_count INTEGER NOT NULL DEFAULT 0,
46
+ created_at INTEGER NOT NULL,
47
+ updated_at INTEGER NOT NULL
48
+ );
49
+
50
+ CREATE TABLE document_conversations (
51
+ surface_id TEXT NOT NULL,
52
+ conversation_id TEXT NOT NULL,
53
+ created_at INTEGER NOT NULL,
54
+ PRIMARY KEY (surface_id, conversation_id),
55
+ FOREIGN KEY (surface_id) REFERENCES documents(surface_id) ON DELETE CASCADE
56
+ );
57
+ `);
58
+ }
59
+
60
+ function seedDocument(params: {
61
+ surfaceId: string;
62
+ conversationId: string;
63
+ title: string;
64
+ content: string;
65
+ createdAt: number;
66
+ }): void {
67
+ const raw = getSqlite();
68
+ raw
69
+ .query(`INSERT OR IGNORE INTO conversations (id, created_at) VALUES (?, ?)`)
70
+ .run(params.conversationId, params.createdAt);
71
+ raw
72
+ .query(
73
+ `INSERT INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)`,
74
+ )
75
+ .run(
76
+ params.surfaceId,
77
+ params.conversationId,
78
+ params.title,
79
+ params.content,
80
+ params.content.split(/\s+/).filter(Boolean).length,
81
+ params.createdAt,
82
+ params.createdAt,
83
+ );
84
+ raw
85
+ .query(
86
+ `INSERT OR IGNORE INTO document_conversations (surface_id, conversation_id, created_at) VALUES (?, ?, ?)`,
87
+ )
88
+ .run(params.surfaceId, params.conversationId, params.createdAt);
89
+ }
90
+
91
+ describe("executeDocumentCreate — dedupe empty same-title document", () => {
92
+ beforeEach(() => {
93
+ bootstrapDocumentTables();
94
+ });
95
+
96
+ test("reuses an empty same-title doc when incoming content is non-empty", () => {
97
+ const seededId = "doc-empty-seeded";
98
+ seedDocument({
99
+ surfaceId: seededId,
100
+ conversationId: "conv-current",
101
+ title: "My Post",
102
+ content: "",
103
+ createdAt: Date.now(),
104
+ });
105
+
106
+ const result = executeDocumentCreate(
107
+ { title: "My Post", initial_content: "Hello" },
108
+ makeContext(),
109
+ );
110
+ expect(result.isError).toBe(false);
111
+ const body = parseResult<{
112
+ surface_id: string;
113
+ reused?: boolean;
114
+ message?: string;
115
+ }>(result);
116
+ expect(body.surface_id).toBe(seededId);
117
+ expect(body.reused).toBe(true);
118
+ expect(body.message).toBe("Document editor reopened (deduped empty draft)");
119
+
120
+ expect(getDocumentById(seededId)?.content).toBe("Hello");
121
+ expect(getDocumentsForConversation("conv-current").length).toBe(1);
122
+ });
123
+
124
+ test("creates a new doc when incoming initial_content is empty (no dedupe)", () => {
125
+ const seededId = "doc-empty-seeded";
126
+ seedDocument({
127
+ surfaceId: seededId,
128
+ conversationId: "conv-current",
129
+ title: "My Post",
130
+ content: "",
131
+ createdAt: Date.now(),
132
+ });
133
+
134
+ const result = executeDocumentCreate(
135
+ { title: "My Post", initial_content: "" },
136
+ makeContext(),
137
+ );
138
+ expect(result.isError).toBe(false);
139
+ const body = parseResult<{ surface_id: string; reused?: boolean }>(result);
140
+ expect(body.reused).toBeUndefined();
141
+ expect(body.surface_id).not.toBe(seededId);
142
+ expect(getDocumentsForConversation("conv-current").length).toBe(2);
143
+ });
144
+
145
+ test("does not dedupe when the seeded doc already has content", () => {
146
+ const seededId = "doc-has-content";
147
+ seedDocument({
148
+ surfaceId: seededId,
149
+ conversationId: "conv-current",
150
+ title: "My Post",
151
+ content: "already drafted",
152
+ createdAt: Date.now(),
153
+ });
154
+
155
+ const result = executeDocumentCreate(
156
+ { title: "My Post", initial_content: "Hello" },
157
+ makeContext(),
158
+ );
159
+ expect(result.isError).toBe(false);
160
+ const body = parseResult<{ surface_id: string; reused?: boolean }>(result);
161
+ expect(body.reused).toBeUndefined();
162
+ expect(body.surface_id).not.toBe(seededId);
163
+ expect(getDocumentById(seededId)?.content).toBe("already drafted");
164
+ expect(getDocumentsForConversation("conv-current").length).toBe(2);
165
+ });
166
+
167
+ test("does not dedupe when the seeded empty doc is outside the 5-minute window", () => {
168
+ const seededId = "doc-stale-empty";
169
+ seedDocument({
170
+ surfaceId: seededId,
171
+ conversationId: "conv-current",
172
+ title: "My Post",
173
+ content: "",
174
+ // 10 minutes ago — outside the 5-minute dedupe window.
175
+ createdAt: Date.now() - 10 * 60 * 1000,
176
+ });
177
+
178
+ const result = executeDocumentCreate(
179
+ { title: "My Post", initial_content: "Hello" },
180
+ makeContext(),
181
+ );
182
+ expect(result.isError).toBe(false);
183
+ const body = parseResult<{ surface_id: string; reused?: boolean }>(result);
184
+ expect(body.reused).toBeUndefined();
185
+ expect(body.surface_id).not.toBe(seededId);
186
+ expect(getDocumentById(seededId)?.content).toBe("");
187
+ expect(getDocumentsForConversation("conv-current").length).toBe(2);
188
+ });
189
+ });
@@ -1,12 +1,13 @@
1
1
  import { beforeEach, describe, expect, test } from "bun:test";
2
2
 
3
3
  import { getDocumentById } from "../documents/document-store.js";
4
- import { getSqlite, resetDb } from "../memory/db-connection.js";
4
+ import { getSqlite } from "../memory/db-connection.js";
5
5
  import {
6
6
  executeDocumentFind,
7
7
  executeDocumentReplaceText,
8
8
  } from "../tools/document/document-tool.js";
9
9
  import type { ToolContext, ToolExecutionResult } from "../tools/types.js";
10
+ import { resetDbForTesting } from "./db-test-helpers.js";
10
11
 
11
12
  function makeContext(overrides: Partial<ToolContext> = {}): ToolContext {
12
13
  return {
@@ -23,7 +24,7 @@ function parseResult<T>(result: ToolExecutionResult): T {
23
24
  }
24
25
 
25
26
  function bootstrapDocumentTables(): void {
26
- resetDb();
27
+ resetDbForTesting();
27
28
  const raw = getSqlite();
28
29
  raw.exec(/*sql*/ `
29
30
  DROP TABLE IF EXISTS document_conversations;