@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
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Tests for the surface-content route handler.
3
+ *
4
+ * Focus is the rehydrate-on-miss path: after daemon restart or LRU
5
+ * eviction, the in-memory conversation map is empty even though the
6
+ * surface still persists as a `ui_surface` content block in the
7
+ * messages table. The handler must fall back to a DB scan via the
8
+ * shared `resolveSurfaceConversation` helper, which calls
9
+ * `getOrCreateConversation` to rehydrate the conversation. The
10
+ * rehydration runs `restoreSurfaceStateFromHistory()` in production,
11
+ * which is what repopulates the surfaceState the handler then reads
12
+ * from — in tests we simulate the rehydrated conversation by stubbing
13
+ * `getOrCreateConversation`'s return value with pre-populated
14
+ * `surfaceState`.
15
+ *
16
+ * Strategy mirrors `surface-action-routes.test.ts`: mock the
17
+ * `conversation-store` and `raw-query` modules at their boundary so
18
+ * the resolver code path executes against the test doubles, import
19
+ * ROUTES afterwards, and dispatch by operationId.
20
+ */
21
+
22
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Mock state
26
+ // ---------------------------------------------------------------------------
27
+
28
+ interface StoredSurface {
29
+ surfaceType: string;
30
+ title: string | null;
31
+ data: Record<string, unknown>;
32
+ }
33
+
34
+ interface StubConversation {
35
+ id: string;
36
+ surfaceState: Map<string, StoredSurface>;
37
+ currentTurnSurfaces?: Array<{
38
+ surfaceId: string;
39
+ surfaceType: string;
40
+ title?: string | null;
41
+ data: Record<string, unknown>;
42
+ }>;
43
+ }
44
+
45
+ let memoryById: StubConversation | null = null;
46
+ let rehydrated: StubConversation | null = null;
47
+ let rawGetReturn: { conversation_id: string } | null = null;
48
+
49
+ const findConvCalls: string[] = [];
50
+ const findBySurfaceCalls: string[] = [];
51
+ const getOrCreateCalls: string[] = [];
52
+ const rawGetCalls: Array<{ sql: string; params: unknown[] }> = [];
53
+
54
+ mock.module("../../../daemon/conversation-store.js", () => ({
55
+ findConversation: (id: string) => {
56
+ findConvCalls.push(id);
57
+ return memoryById ?? undefined;
58
+ },
59
+ findConversationBySurfaceId: (surfaceId: string) => {
60
+ findBySurfaceCalls.push(surfaceId);
61
+ return undefined;
62
+ },
63
+ getOrCreateConversation: async (id: string) => {
64
+ getOrCreateCalls.push(id);
65
+ if (!rehydrated) {
66
+ throw new Error(
67
+ `getOrCreateConversation(${id}) called but no rehydrated stub configured`,
68
+ );
69
+ }
70
+ return rehydrated;
71
+ },
72
+ }));
73
+
74
+ mock.module("../../../memory/raw-query.js", () => ({
75
+ rawGet: (sql: string, ...params: unknown[]) => {
76
+ rawGetCalls.push({ sql, params });
77
+ return rawGetReturn;
78
+ },
79
+ }));
80
+
81
+ // Defer route import until after mocks are installed.
82
+ const { ROUTES } = await import("../surface-content-routes.js");
83
+ const { BadRequestError, NotFoundError } = await import("../errors.js");
84
+ import type { RouteDefinition } from "../types.js";
85
+
86
+ function findHandler(operationId: string): RouteDefinition["handler"] {
87
+ const route = ROUTES.find((r) => r.operationId === operationId);
88
+ if (!route) throw new Error(`Route ${operationId} not found`);
89
+ return route.handler;
90
+ }
91
+
92
+ function makeStub(id: string): StubConversation {
93
+ return { id, surfaceState: new Map() };
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Setup
98
+ // ---------------------------------------------------------------------------
99
+
100
+ beforeEach(() => {
101
+ memoryById = null;
102
+ rehydrated = null;
103
+ rawGetReturn = null;
104
+ findConvCalls.length = 0;
105
+ findBySurfaceCalls.length = 0;
106
+ getOrCreateCalls.length = 0;
107
+ rawGetCalls.length = 0;
108
+ });
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // surfaces_get_content
112
+ // ---------------------------------------------------------------------------
113
+
114
+ describe("surfaces_get_content handler", () => {
115
+ test("serves surface from in-memory surfaceState", async () => {
116
+ const conv = makeStub("conv-active");
117
+ conv.surfaceState.set("surf-1", {
118
+ surfaceType: "card",
119
+ title: "T",
120
+ data: { foo: "bar" },
121
+ });
122
+ memoryById = conv;
123
+
124
+ const handler = findHandler("surfaces_get_content");
125
+ const result = await handler({
126
+ pathParams: { surfaceId: "surf-1" },
127
+ queryParams: { conversationId: "conv-active" },
128
+ });
129
+
130
+ expect(result).toEqual({
131
+ surfaceId: "surf-1",
132
+ surfaceType: "card",
133
+ title: "T",
134
+ data: { foo: "bar" },
135
+ });
136
+ expect(findConvCalls).toEqual(["conv-active"]);
137
+ // Fast path — never touched the DB or rehydration helpers.
138
+ expect(rawGetCalls).toEqual([]);
139
+ expect(getOrCreateCalls).toEqual([]);
140
+ });
141
+
142
+ test("falls back to currentTurnSurfaces when surfaceState misses", async () => {
143
+ const conv = makeStub("conv-mid-turn");
144
+ conv.currentTurnSurfaces = [
145
+ {
146
+ surfaceId: "surf-pending",
147
+ surfaceType: "list",
148
+ title: "Picks",
149
+ data: { items: [] },
150
+ },
151
+ ];
152
+ memoryById = conv;
153
+
154
+ const handler = findHandler("surfaces_get_content");
155
+ const result = await handler({
156
+ pathParams: { surfaceId: "surf-pending" },
157
+ queryParams: { conversationId: "conv-mid-turn" },
158
+ });
159
+
160
+ expect(result).toEqual({
161
+ surfaceId: "surf-pending",
162
+ surfaceType: "list",
163
+ title: "Picks",
164
+ data: { items: [] },
165
+ });
166
+ });
167
+
168
+ // -------------------------------------------------------------------------
169
+ // The bug fix: rehydration on in-memory miss.
170
+ // -------------------------------------------------------------------------
171
+ test("rehydrates from DB when the conversation is not in memory", async () => {
172
+ // Simulate post-restart or post-eviction: nothing in memory, but the
173
+ // surface exists in the messages table and rehydration restores the
174
+ // conversation with its surfaceState repopulated from history.
175
+ memoryById = null;
176
+ rawGetReturn = { conversation_id: "conv-evicted" };
177
+ const restored = makeStub("conv-evicted");
178
+ restored.surfaceState.set("surf-restored", {
179
+ surfaceType: "card",
180
+ title: "Restored",
181
+ data: { from: "history" },
182
+ });
183
+ rehydrated = restored;
184
+
185
+ const handler = findHandler("surfaces_get_content");
186
+ const result = await handler({
187
+ pathParams: { surfaceId: "surf-restored" },
188
+ queryParams: { conversationId: "conv-evicted" },
189
+ });
190
+
191
+ expect(result).toEqual({
192
+ surfaceId: "surf-restored",
193
+ surfaceType: "card",
194
+ title: "Restored",
195
+ data: { from: "history" },
196
+ });
197
+ // Hit the in-memory map first, missed, fell through to the DB scan,
198
+ // then rehydrated. The DB scan keyed on the surfaceId.
199
+ expect(findConvCalls).toEqual(["conv-evicted"]);
200
+ expect(rawGetCalls).toHaveLength(1);
201
+ expect(rawGetCalls[0]!.params[0]).toBe(`%"surfaceId":"surf-restored"%`);
202
+ expect(getOrCreateCalls).toEqual(["conv-evicted"]);
203
+ });
204
+
205
+ test("400s when conversationId is missing", async () => {
206
+ const handler = findHandler("surfaces_get_content");
207
+
208
+ let caught: unknown;
209
+ try {
210
+ await handler({
211
+ pathParams: { surfaceId: "surf-1" },
212
+ queryParams: {},
213
+ });
214
+ } catch (err) {
215
+ caught = err;
216
+ }
217
+
218
+ expect(caught).toBeInstanceOf(BadRequestError);
219
+ expect(findConvCalls).toEqual([]);
220
+ });
221
+
222
+ test("404s when no row in the DB matches the surfaceId (truly unknown surface)", async () => {
223
+ // Cold-cache miss with no DB row — the surfaceId is bogus or has
224
+ // never been persisted. We must 404, not rehydrate a phantom
225
+ // conversation for the caller-supplied conversationId.
226
+ memoryById = null;
227
+ rawGetReturn = null;
228
+
229
+ const handler = findHandler("surfaces_get_content");
230
+
231
+ let caught: unknown;
232
+ try {
233
+ await handler({
234
+ pathParams: { surfaceId: "surf-missing" },
235
+ queryParams: { conversationId: "conv-unknown" },
236
+ });
237
+ } catch (err) {
238
+ caught = err;
239
+ }
240
+
241
+ expect(caught).toBeInstanceOf(NotFoundError);
242
+ // Rehydration must NOT have been called — otherwise an arbitrary
243
+ // caller could materialize empty conversations for any UUID.
244
+ expect(getOrCreateCalls).toEqual([]);
245
+ });
246
+
247
+ test("404s when the DB row's conversation_id mismatches the caller's", async () => {
248
+ // The surface lives on a different conversation than the caller
249
+ // claims. Refusing to rehydrate prevents cross-conversation
250
+ // information leakage via guessable surfaceIds.
251
+ memoryById = null;
252
+ rawGetReturn = { conversation_id: "conv-actual-owner" };
253
+
254
+ const handler = findHandler("surfaces_get_content");
255
+
256
+ let caught: unknown;
257
+ try {
258
+ await handler({
259
+ pathParams: { surfaceId: "surf-leaked" },
260
+ queryParams: { conversationId: "conv-attacker" },
261
+ });
262
+ } catch (err) {
263
+ caught = err;
264
+ }
265
+
266
+ expect(caught).toBeInstanceOf(NotFoundError);
267
+ expect(getOrCreateCalls).toEqual([]);
268
+ });
269
+
270
+ test("404s when rehydration succeeds but the surface still isn't present", async () => {
271
+ // Adversarial sanity check: the DB scan found a row pointing at a
272
+ // conversation, but after rehydration the surface neither lives in
273
+ // surfaceState nor in currentTurnSurfaces. (Shouldn't really
274
+ // happen given the scan keyed on the surfaceId — defensive.)
275
+ memoryById = null;
276
+ rawGetReturn = { conversation_id: "conv-evicted" };
277
+ rehydrated = makeStub("conv-evicted"); // empty surfaceState
278
+
279
+ const handler = findHandler("surfaces_get_content");
280
+
281
+ let caught: unknown;
282
+ try {
283
+ await handler({
284
+ pathParams: { surfaceId: "surf-gone" },
285
+ queryParams: { conversationId: "conv-evicted" },
286
+ });
287
+ } catch (err) {
288
+ caught = err;
289
+ }
290
+
291
+ expect(caught).toBeInstanceOf(NotFoundError);
292
+ expect(getOrCreateCalls).toEqual(["conv-evicted"]);
293
+ });
294
+ });
@@ -195,9 +195,54 @@ mock.module("../../../tools/tasks/work-item-run.js", () => ({
195
195
  }));
196
196
 
197
197
  // Also mock getWorkspaceDir so handlers don't hit the real filesystem
198
- mock.module("../../../util/platform.js", () => ({
199
- getWorkspaceDir: () => "/mock/workspace",
200
- }));
198
+ mock.module("../../../util/platform.js", () => {
199
+ const stub = () => "/mock/workspace";
200
+ return {
201
+ getWorkspaceDir: () => "/mock/workspace",
202
+ vellumRoot: stub,
203
+ isMacOS: () => false,
204
+ isLinux: () => true,
205
+ isWindows: () => false,
206
+ getPlatformName: () => "linux",
207
+ normalizeAssistantId: (id: string) => id,
208
+ getDataDir: stub,
209
+ getEmbeddingModelsDir: stub,
210
+ getSandboxRootDir: stub,
211
+ getSandboxWorkingDir: stub,
212
+ getSoundsDir: stub,
213
+ getAvatarDir: stub,
214
+ AVATAR_IMAGE_FILENAME: "avatar-image.png",
215
+ getAvatarImagePath: stub,
216
+ getXdgVellumConfigDirName: () => ".vellum",
217
+ getPidPath: stub,
218
+ getDbPath: stub,
219
+ getLogsDir: stub,
220
+ getHistoryPath: stub,
221
+ getProtectedDir: stub,
222
+ getSignalsDir: stub,
223
+ getDaemonStderrLogPath: stub,
224
+ getDaemonStartupLockPath: stub,
225
+ getExternalDir: stub,
226
+ getBinDir: stub,
227
+ getDotEnvPath: stub,
228
+ getEmbedWorkerPidPath: stub,
229
+ getWorkspaceDirDisplay: stub,
230
+ getWorkspaceConfigPath: stub,
231
+ getWorkspaceSkillsDir: stub,
232
+ getWorkspaceHooksDir: stub,
233
+ getWorkspacePluginsDir: stub,
234
+ getWorkspaceRoutesDir: stub,
235
+ getDeprecatedDir: stub,
236
+ getConversationsDir: stub,
237
+ getWorkspacePromptPath: stub,
238
+ getProfilerRootDir: stub,
239
+ getProfilerRunsDir: stub,
240
+ getProfilerRunDir: stub,
241
+ getSkillRuntimePath: stub,
242
+ getBundledBunPath: () => undefined,
243
+ ensureDataDir: () => {},
244
+ };
245
+ });
201
246
 
202
247
  // ---------------------------------------------------------------------------
203
248
  // Import route definitions after mocking
@@ -44,6 +44,9 @@ mock.module("../../memory/db-connection.js", () => {
44
44
  builder.all = () => [];
45
45
  return {
46
46
  getDb: () => builder,
47
+ getSqlite: () => ({ __stub: true }),
48
+ getSqliteFrom: () => ({ __stub: true }),
49
+ resetDb: () => {},
47
50
  };
48
51
  });
49
52
 
@@ -786,7 +786,17 @@ export const ROUTES: RouteDefinition[] = [
786
786
  },
787
787
  ],
788
788
  responseBody: z.object({
789
- apps: z.array(z.unknown()).describe("Array of app summary objects"),
789
+ apps: z.array(
790
+ z.object({
791
+ id: z.string(),
792
+ name: z.string(),
793
+ description: z.string().optional(),
794
+ icon: z.string().optional(),
795
+ createdAt: z.number(),
796
+ version: z.string(),
797
+ contentId: z.string(),
798
+ }),
799
+ ),
790
800
  }),
791
801
  },
792
802
  {
@@ -802,6 +812,21 @@ export const ROUTES: RouteDefinition[] = [
802
812
  requestBody: z.object({
803
813
  filePath: z.string().describe("Absolute path to the .vbundle file"),
804
814
  }),
815
+ responseBody: z.object({
816
+ manifest: z.object({}).passthrough(),
817
+ scanResult: z.object({
818
+ passed: z.boolean(),
819
+ blocked: z.array(z.string()),
820
+ warnings: z.array(z.string()),
821
+ }),
822
+ signatureResult: z.object({
823
+ trustTier: z.string(),
824
+ signerKeyId: z.string().optional(),
825
+ signerDisplayName: z.string().optional(),
826
+ signerAccount: z.string().optional(),
827
+ }),
828
+ bundleSizeBytes: z.number(),
829
+ }),
805
830
  },
806
831
  {
807
832
  operationId: "apps_shared_list",
@@ -813,7 +838,23 @@ export const ROUTES: RouteDefinition[] = [
813
838
  description: "Return all apps available via cloud share links.",
814
839
  tags: ["apps"],
815
840
  responseBody: z.object({
816
- apps: z.array(z.unknown()).describe("Array of shared app objects"),
841
+ apps: z.array(
842
+ z.object({
843
+ uuid: z.string(),
844
+ name: z.string(),
845
+ description: z.string().optional(),
846
+ icon: z.string().optional(),
847
+ preview: z.string().optional(),
848
+ entry: z.string(),
849
+ trustTier: z.string(),
850
+ signerDisplayName: z.string().optional(),
851
+ bundleSizeBytes: z.number(),
852
+ installedAt: z.string(),
853
+ version: z.string().optional(),
854
+ contentId: z.string().optional(),
855
+ updateAvailable: z.boolean().optional(),
856
+ }),
857
+ ),
817
858
  }),
818
859
  },
819
860
  {
@@ -828,6 +869,11 @@ export const ROUTES: RouteDefinition[] = [
828
869
  requestBody: z.object({
829
870
  uuid: z.string().describe("UUID of the shared app to fork"),
830
871
  }),
872
+ responseBody: z.object({
873
+ success: z.literal(true),
874
+ appId: z.string(),
875
+ name: z.string(),
876
+ }),
831
877
  },
832
878
  {
833
879
  operationId: "apps_gallery_install",
@@ -839,6 +885,11 @@ export const ROUTES: RouteDefinition[] = [
839
885
  description: "Install an app from the built-in gallery by its ID.",
840
886
  tags: ["apps"],
841
887
  requestBody: z.object({ galleryAppId: z.string() }),
888
+ responseBody: z.object({
889
+ success: z.literal(true),
890
+ appId: z.string(),
891
+ name: z.string(),
892
+ }),
842
893
  },
843
894
  {
844
895
  operationId: "apps_gallery_list",
@@ -850,7 +901,28 @@ export const ROUTES: RouteDefinition[] = [
850
901
  description: "Return the built-in app gallery catalog.",
851
902
  tags: ["apps"],
852
903
  responseBody: z.object({
853
- gallery: z.array(z.unknown()).describe("Gallery app entries"),
904
+ gallery: z.object({
905
+ version: z.number(),
906
+ updatedAt: z.string(),
907
+ categories: z.array(
908
+ z.object({
909
+ id: z.string(),
910
+ name: z.string(),
911
+ icon: z.string(),
912
+ }),
913
+ ),
914
+ apps: z.array(
915
+ z.object({
916
+ id: z.string(),
917
+ name: z.string(),
918
+ description: z.string(),
919
+ icon: z.string(),
920
+ category: z.string(),
921
+ version: z.string(),
922
+ featured: z.boolean().optional(),
923
+ }),
924
+ ),
925
+ }),
854
926
  }),
855
927
  },
856
928
  {
@@ -897,6 +969,12 @@ export const ROUTES: RouteDefinition[] = [
897
969
  keyId: z.string().optional(),
898
970
  publicKey: z.string().optional(),
899
971
  }),
972
+ responseBody: z.object({
973
+ signed: z.boolean().optional(),
974
+ signatureJson: z.object({}).passthrough().optional(),
975
+ payload: z.string().optional(),
976
+ message: z.string().optional(),
977
+ }),
900
978
  },
901
979
  {
902
980
  operationId: "apps_signing_identity",
@@ -908,6 +986,7 @@ export const ROUTES: RouteDefinition[] = [
908
986
  description:
909
987
  "Return signing identity info. Signing is managed client-side over HTTP.",
910
988
  tags: ["apps"],
989
+ responseBody: z.object({ message: z.string() }),
911
990
  },
912
991
 
913
992
  // Parameterized `apps/:id/*` routes — must follow all literal routes.
@@ -927,6 +1006,10 @@ export const ROUTES: RouteDefinition[] = [
927
1006
  type: "string",
928
1007
  },
929
1008
  ],
1009
+ responseBody: z.object({
1010
+ success: z.boolean(),
1011
+ result: z.unknown(),
1012
+ }),
930
1013
  },
931
1014
  {
932
1015
  operationId: "apps_data_mutate",
@@ -943,6 +1026,10 @@ export const ROUTES: RouteDefinition[] = [
943
1026
  recordId: z.string(),
944
1027
  data: z.object({}).passthrough(),
945
1028
  }),
1029
+ responseBody: z.object({
1030
+ success: z.boolean(),
1031
+ result: z.unknown(),
1032
+ }),
946
1033
  },
947
1034
  {
948
1035
  operationId: "apps_open",
@@ -969,6 +1056,7 @@ export const ROUTES: RouteDefinition[] = [
969
1056
  summary: "Delete an app",
970
1057
  description: "Permanently remove an app and its data.",
971
1058
  tags: ["apps"],
1059
+ responseBody: z.object({ success: z.boolean() }),
972
1060
  },
973
1061
  {
974
1062
  operationId: "apps_preview_get",
@@ -979,6 +1067,10 @@ export const ROUTES: RouteDefinition[] = [
979
1067
  summary: "Get app preview",
980
1068
  description: "Return the preview image or HTML for an app.",
981
1069
  tags: ["apps"],
1070
+ responseBody: z.object({
1071
+ appId: z.string(),
1072
+ preview: z.string().nullable(),
1073
+ }),
982
1074
  },
983
1075
  {
984
1076
  operationId: "apps_preview_update",
@@ -992,6 +1084,10 @@ export const ROUTES: RouteDefinition[] = [
992
1084
  requestBody: z.object({
993
1085
  preview: z.string().describe("Base64-encoded image or HTML string"),
994
1086
  }),
1087
+ responseBody: z.object({
1088
+ success: z.boolean(),
1089
+ appId: z.string(),
1090
+ }),
995
1091
  },
996
1092
  {
997
1093
  operationId: "apps_history",
@@ -1005,7 +1101,13 @@ export const ROUTES: RouteDefinition[] = [
1005
1101
  queryParams: [{ name: "limit", type: "number" }],
1006
1102
  responseBody: z.object({
1007
1103
  appId: z.string(),
1008
- versions: z.array(z.unknown()),
1104
+ versions: z.array(
1105
+ z.object({
1106
+ commitHash: z.string(),
1107
+ message: z.string(),
1108
+ timestamp: z.number(),
1109
+ }),
1110
+ ),
1009
1111
  }),
1010
1112
  },
1011
1113
  {
@@ -1021,6 +1123,10 @@ export const ROUTES: RouteDefinition[] = [
1021
1123
  { name: "fromCommit", type: "string", required: true },
1022
1124
  { name: "toCommit", type: "string" },
1023
1125
  ],
1126
+ responseBody: z.object({
1127
+ appId: z.string(),
1128
+ diff: z.string(),
1129
+ }),
1024
1130
  },
1025
1131
  {
1026
1132
  operationId: "apps_restore",
@@ -1032,6 +1138,7 @@ export const ROUTES: RouteDefinition[] = [
1032
1138
  description: "Restore an app to a previous git commit.",
1033
1139
  tags: ["apps"],
1034
1140
  requestBody: z.object({ commitHash: z.string() }),
1141
+ responseBody: z.object({ success: z.boolean() }),
1035
1142
  },
1036
1143
  {
1037
1144
  operationId: "apps_bundle",