@vellumai/assistant 0.7.2 → 0.7.3

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 (347) hide show
  1. package/ARCHITECTURE.md +16 -1
  2. package/docs/architecture/memory.md +5 -2
  3. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
  4. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
  5. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  6. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  7. package/openapi.yaml +449 -22
  8. package/package.json +1 -1
  9. package/src/__tests__/app-control-flow.test.ts +21 -11
  10. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  11. package/src/__tests__/assistant-event.test.ts +0 -10
  12. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
  13. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
  14. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  15. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  16. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  17. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  18. package/src/__tests__/channel-readiness-service.test.ts +4 -2
  19. package/src/__tests__/config-loader-backfill.test.ts +379 -0
  20. package/src/__tests__/config-schema.test.ts +1 -0
  21. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
  22. package/src/__tests__/config-watcher.test.ts +140 -69
  23. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  24. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  25. package/src/__tests__/context-search-fanout.test.ts +0 -1
  26. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  27. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  28. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  29. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  30. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  31. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  32. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  33. package/src/__tests__/conversation-error.test.ts +150 -3
  34. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  35. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  36. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  37. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  38. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  39. package/src/__tests__/conversation-store.test.ts +0 -18
  40. package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
  41. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  42. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  43. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  44. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  45. package/src/__tests__/credentials-cli.test.ts +7 -0
  46. package/src/__tests__/cu-unified-flow.test.ts +176 -10
  47. package/src/__tests__/date-context.test.ts +164 -2
  48. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  49. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  50. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  51. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  52. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  53. package/src/__tests__/disk-usage.test.ts +150 -0
  54. package/src/__tests__/events-client-registration.test.ts +52 -0
  55. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  56. package/src/__tests__/file-write-tool.test.ts +4 -10
  57. package/src/__tests__/filing-service.test.ts +3 -4
  58. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  59. package/src/__tests__/heartbeat-service.test.ts +260 -11
  60. package/src/__tests__/host-app-control-proxy.test.ts +195 -25
  61. package/src/__tests__/host-bash-proxy.test.ts +227 -34
  62. package/src/__tests__/host-bash-routes.test.ts +178 -13
  63. package/src/__tests__/host-cu-proxy.test.ts +210 -3
  64. package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
  65. package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
  66. package/src/__tests__/host-file-proxy.test.ts +268 -6
  67. package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
  68. package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
  69. package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
  70. package/src/__tests__/http-user-message-parity.test.ts +107 -1
  71. package/src/__tests__/injector-chain.test.ts +18 -6
  72. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  73. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  74. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  75. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  77. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  78. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  79. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  80. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  81. package/src/__tests__/openai-provider.test.ts +45 -8
  82. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  83. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  84. package/src/__tests__/platform.test.ts +2 -1
  85. package/src/__tests__/playbook-execution.test.ts +0 -43
  86. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  87. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
  88. package/src/__tests__/provider-tool-name.test.ts +23 -0
  89. package/src/__tests__/relay-server.test.ts +15 -4
  90. package/src/__tests__/runtime-events-sse.test.ts +4 -8
  91. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  92. package/src/__tests__/secret-ingress-http.test.ts +0 -1
  93. package/src/__tests__/suggestion-routes.test.ts +46 -0
  94. package/src/__tests__/twilio-validation.test.ts +2 -2
  95. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  96. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  97. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  98. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  99. package/src/approvals/guardian-decision-primitive.ts +13 -0
  100. package/src/approvals/guardian-request-resolvers.ts +16 -17
  101. package/src/backup/snapshot-lock.ts +2 -27
  102. package/src/bundler/compiler-tools.ts +3 -2
  103. package/src/calls/call-conversation-messages.ts +46 -10
  104. package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
  105. package/src/cli/commands/bash.ts +35 -108
  106. package/src/cli/commands/contacts.ts +64 -25
  107. package/src/cli/commands/credentials.ts +56 -0
  108. package/src/cli/commands/memory-v2.ts +7 -6
  109. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  110. package/src/cli/commands/oauth/connect.ts +127 -1
  111. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
  112. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
  113. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  114. package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
  115. package/src/cli/commands/platform/index.ts +16 -7
  116. package/src/cli/commands/status.ts +57 -0
  117. package/src/cli/program.ts +4 -2
  118. package/src/config/assistant-feature-flags.ts +13 -3
  119. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  120. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
  121. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  122. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  123. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  124. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  125. package/src/config/env.ts +0 -8
  126. package/src/config/feature-flag-registry.json +27 -3
  127. package/src/config/loader.ts +127 -8
  128. package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
  129. package/src/config/schemas/call-site-catalog.ts +14 -0
  130. package/src/config/schemas/channels.ts +0 -5
  131. package/src/config/schemas/heartbeat.ts +1 -1
  132. package/src/config/schemas/llm.ts +2 -0
  133. package/src/config/schemas/memory-lifecycle.ts +13 -0
  134. package/src/config/schemas/memory-v2.ts +75 -11
  135. package/src/config/schemas/platform.ts +43 -3
  136. package/src/config/schemas/services.ts +28 -0
  137. package/src/config/seed-inference-profiles.ts +230 -33
  138. package/src/contacts/contact-store.ts +0 -25
  139. package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
  140. package/src/daemon/assistant-attachments.ts +4 -4
  141. package/src/daemon/config-watcher.ts +85 -57
  142. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  143. package/src/daemon/conversation-agent-loop.ts +170 -33
  144. package/src/daemon/conversation-error.ts +87 -15
  145. package/src/daemon/conversation-lifecycle.ts +1 -3
  146. package/src/daemon/conversation-process.ts +8 -0
  147. package/src/daemon/conversation-runtime-assembly.ts +26 -0
  148. package/src/daemon/conversation-store.ts +2 -2
  149. package/src/daemon/conversation-surfaces.ts +195 -15
  150. package/src/daemon/conversation-tool-setup.ts +57 -14
  151. package/src/daemon/conversation.ts +17 -22
  152. package/src/daemon/date-context.ts +71 -22
  153. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  154. package/src/daemon/disk-pressure-guard.ts +343 -0
  155. package/src/daemon/disk-pressure-policy.ts +163 -0
  156. package/src/daemon/handlers/shared.ts +0 -1
  157. package/src/daemon/handlers/skills.ts +3 -4
  158. package/src/daemon/host-app-control-proxy.ts +137 -41
  159. package/src/daemon/host-bash-proxy.ts +46 -21
  160. package/src/daemon/host-cu-proxy.ts +49 -3
  161. package/src/daemon/host-file-proxy.ts +43 -7
  162. package/src/daemon/host-transfer-proxy.ts +95 -4
  163. package/src/daemon/lifecycle.ts +79 -28
  164. package/src/daemon/meet-host-supervisor.ts +4 -4
  165. package/src/daemon/meet-manifest-loader.ts +0 -1
  166. package/src/daemon/memory-v2-startup.ts +14 -4
  167. package/src/daemon/message-protocol.ts +3 -0
  168. package/src/daemon/message-types/conversations.ts +4 -0
  169. package/src/daemon/message-types/disk-pressure.ts +9 -0
  170. package/src/daemon/message-types/messages.ts +3 -0
  171. package/src/daemon/profiler-run-store.ts +5 -5
  172. package/src/daemon/tool-setup-types.ts +2 -2
  173. package/src/documents/document-store.ts +85 -0
  174. package/src/filing/filing-service.ts +30 -5
  175. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
  176. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
  177. package/src/heartbeat/heartbeat-run-store.ts +13 -0
  178. package/src/heartbeat/heartbeat-service.ts +205 -31
  179. package/src/home/feed-scheduler.ts +18 -0
  180. package/src/inbound/platform-callback-registration.ts +8 -15
  181. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  182. package/src/ipc/assistant-server.ts +56 -2
  183. package/src/ipc/gateway-client.ts +37 -3
  184. package/src/live-voice/live-voice-archive.ts +4 -4
  185. package/src/live-voice/protocol.ts +5 -7
  186. package/src/media/image-service.ts +1 -7
  187. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  188. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  189. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  190. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  191. package/src/memory/admin.ts +5 -9
  192. package/src/memory/context-search/agent-runner.ts +19 -2
  193. package/src/memory/context-search/sources/conversations.ts +2 -11
  194. package/src/memory/context-search/sources/memory-v2.ts +5 -4
  195. package/src/memory/context-search/sources/memory.ts +0 -1
  196. package/src/memory/context-search/types.ts +0 -1
  197. package/src/memory/conversation-crud.ts +4 -12
  198. package/src/memory/db-init.ts +2 -0
  199. package/src/memory/embedding-runtime-manager.ts +119 -5
  200. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
  201. package/src/memory/graph/conversation-graph-memory.ts +42 -54
  202. package/src/memory/graph/extraction.ts +1 -3
  203. package/src/memory/graph/graph-search.test.ts +10 -67
  204. package/src/memory/graph/graph-search.ts +1 -20
  205. package/src/memory/graph/retriever.test.ts +6 -0
  206. package/src/memory/graph/retriever.ts +6 -10
  207. package/src/memory/indexer.ts +54 -45
  208. package/src/memory/job-handlers/backfill.ts +2 -11
  209. package/src/memory/job-handlers/cleanup.ts +43 -0
  210. package/src/memory/job-handlers/embedding.ts +6 -8
  211. package/src/memory/job-handlers/summarization.ts +2 -7
  212. package/src/memory/jobs-store.ts +48 -0
  213. package/src/memory/jobs-worker.ts +81 -43
  214. package/src/memory/memory-v2-activation-log-store.ts +32 -14
  215. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  216. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  217. package/src/memory/migrations/index.ts +1 -0
  218. package/src/memory/pkb/pkb-search.test.ts +6 -0
  219. package/src/memory/qdrant-client.ts +0 -13
  220. package/src/memory/rerank-local.ts +374 -0
  221. package/src/memory/search/semantic.ts +6 -67
  222. package/src/memory/trace-event-store.ts +1 -17
  223. package/src/memory/v2/__tests__/activation.test.ts +311 -250
  224. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  225. package/src/memory/v2/__tests__/injection.test.ts +157 -167
  226. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  227. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  228. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  229. package/src/memory/v2/__tests__/sim.test.ts +5 -199
  230. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  231. package/src/memory/v2/__tests__/static-context.test.ts +76 -1
  232. package/src/memory/v2/activation.ts +149 -156
  233. package/src/memory/v2/consolidation-job.ts +62 -12
  234. package/src/memory/v2/injection.ts +47 -60
  235. package/src/memory/v2/prompts/consolidation.ts +36 -1
  236. package/src/memory/v2/qdrant.ts +99 -0
  237. package/src/memory/v2/reranker.ts +177 -0
  238. package/src/memory/v2/sim.ts +10 -84
  239. package/src/memory/v2/skill-content.ts +4 -3
  240. package/src/memory/v2/skill-store.ts +82 -59
  241. package/src/memory/v2/static-context.ts +22 -0
  242. package/src/memory/v2/types.ts +10 -10
  243. package/src/notifications/copy-composer.ts +13 -0
  244. package/src/notifications/signal.ts +4 -0
  245. package/src/oauth/AGENTS.md +3 -1
  246. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  247. package/src/oauth/connect-orchestrator.ts +2 -0
  248. package/src/oauth/connection-resolver.test.ts +66 -1
  249. package/src/oauth/connection-resolver.ts +55 -1
  250. package/src/oauth/oauth-connect-state.ts +77 -0
  251. package/src/oauth/seed-providers.ts +58 -1
  252. package/src/plugins/defaults/injectors.ts +35 -2
  253. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  254. package/src/plugins/types.ts +7 -0
  255. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  256. package/src/proactive-artifact/decision.test.ts +226 -0
  257. package/src/proactive-artifact/decision.ts +165 -0
  258. package/src/proactive-artifact/index.ts +7 -0
  259. package/src/proactive-artifact/job.test.ts +867 -0
  260. package/src/proactive-artifact/job.ts +352 -0
  261. package/src/proactive-artifact/message-copy.ts +41 -0
  262. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  263. package/src/proactive-artifact/trigger-state.ts +119 -0
  264. package/src/prompts/normalize-onboarding.ts +80 -0
  265. package/src/prompts/persona-resolver.ts +101 -9
  266. package/src/prompts/system-prompt.ts +21 -7
  267. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  268. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  269. package/src/providers/model-intents.ts +7 -0
  270. package/src/providers/openrouter/client.ts +8 -0
  271. package/src/providers/retry.ts +50 -0
  272. package/src/providers/types.ts +1 -0
  273. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  274. package/src/runtime/agent-wake.ts +238 -100
  275. package/src/runtime/assistant-event-hub.ts +36 -6
  276. package/src/runtime/assistant-event.ts +0 -1
  277. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  278. package/src/runtime/auth/route-policy.ts +14 -1
  279. package/src/runtime/auth/same-actor.ts +216 -0
  280. package/src/runtime/channel-retry-sweep.ts +65 -1
  281. package/src/runtime/guardian-reply-router.ts +10 -0
  282. package/src/runtime/local-actor-identity.ts +52 -11
  283. package/src/runtime/pending-interactions.ts +8 -0
  284. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
  286. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  287. package/src/runtime/routes/client-routes.ts +20 -2
  288. package/src/runtime/routes/contact-routes.ts +0 -25
  289. package/src/runtime/routes/conversation-routes.ts +35 -26
  290. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  291. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  292. package/src/runtime/routes/document-pdf-renderer.ts +6 -2
  293. package/src/runtime/routes/documents-routes.ts +2 -75
  294. package/src/runtime/routes/events-routes.ts +41 -9
  295. package/src/runtime/routes/host-bash-routes.ts +23 -3
  296. package/src/runtime/routes/host-cu-routes.ts +33 -6
  297. package/src/runtime/routes/host-file-routes.ts +32 -6
  298. package/src/runtime/routes/host-transfer-routes.ts +79 -16
  299. package/src/runtime/routes/identity-routes.ts +7 -138
  300. package/src/runtime/routes/inbound-message-handler.ts +77 -12
  301. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  302. package/src/runtime/routes/index.ts +6 -0
  303. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  304. package/src/runtime/routes/memory-v2-routes.ts +33 -0
  305. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  306. package/src/runtime/verification-outbound-actions.ts +4 -4
  307. package/src/schedule/run-script.ts +37 -5
  308. package/src/schedule/scheduler.ts +20 -1
  309. package/src/security/encrypted-store.ts +2 -0
  310. package/src/security/secure-keys.ts +55 -0
  311. package/src/skills/remote-skill-policy.ts +4 -10
  312. package/src/subagent/index.ts +1 -7
  313. package/src/subagent/manager.ts +1 -15
  314. package/src/tasks/task-runner.ts +0 -1
  315. package/src/tasks/task-store.ts +0 -3
  316. package/src/tools/background-tool-registry.ts +17 -3
  317. package/src/tools/host-filesystem/edit.test.ts +151 -0
  318. package/src/tools/host-filesystem/edit.ts +43 -1
  319. package/src/tools/host-filesystem/read.test.ts +129 -0
  320. package/src/tools/host-filesystem/read.ts +43 -1
  321. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  322. package/src/tools/host-filesystem/transfer.ts +56 -11
  323. package/src/tools/host-filesystem/write.test.ts +134 -0
  324. package/src/tools/host-filesystem/write.ts +43 -1
  325. package/src/tools/host-terminal/host-shell.ts +13 -6
  326. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  327. package/src/tools/memory/register.test.ts +12 -9
  328. package/src/tools/memory/register.ts +1 -2
  329. package/src/tools/provider-tool-name.ts +28 -0
  330. package/src/tools/registry.ts +30 -9
  331. package/src/tools/terminal/shell.ts +9 -1
  332. package/src/tools/tool-approval-handler.ts +31 -6
  333. package/src/tools/types.ts +24 -2
  334. package/src/tts/provider-catalog.ts +3 -5
  335. package/src/util/disk-usage.ts +138 -0
  336. package/src/util/platform.ts +21 -11
  337. package/src/util/process-liveness.ts +26 -0
  338. package/src/workspace/heartbeat-service.ts +19 -0
  339. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  340. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  341. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  342. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  343. package/src/workspace/migrations/registry.ts +8 -0
  344. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  345. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  346. package/src/memory/v2/skill-qdrant.ts +0 -404
  347. package/src/signals/bash.ts +0 -198
@@ -9,6 +9,11 @@ import {
9
9
  assistantEventHub,
10
10
  broadcastMessage,
11
11
  } from "../runtime/assistant-event-hub.js";
12
+ import {
13
+ ambiguousSameUserError,
14
+ enforceSameActorOrErrorResult,
15
+ pickSameUserAutoResolve,
16
+ } from "../runtime/auth/same-actor.js";
12
17
  import * as pendingInteractions from "../runtime/pending-interactions.js";
13
18
  import type { ToolExecutionResult } from "../tools/types.js";
14
19
  import { AssistantError, ErrorCode } from "../util/errors.js";
@@ -31,6 +36,13 @@ interface TransferEntry {
31
36
  sha256?: string;
32
37
  fileBuffer?: Buffer;
33
38
  targetClientId?: string;
39
+ /**
40
+ * Snapshot of `targetClientId`'s `actorPrincipalId` taken at registration
41
+ * time. Persisted so the GET/PUT content routes compare against a stable
42
+ * value rather than the live hub — the target client's SSE subscription
43
+ * may briefly disconnect between dispatch and content fetch/upload.
44
+ */
45
+ targetActorPrincipalId?: string;
34
46
  }
35
47
 
36
48
  /**
@@ -124,6 +136,8 @@ export class HostTransferProxy {
124
136
  targetClientId?: string;
125
137
  },
126
138
  signal?: AbortSignal,
139
+ // Principal ID of the actor on whose behalf this request is initiated.
140
+ sourceActorPrincipalId?: string,
127
141
  ): Promise<ToolExecutionResult> {
128
142
  if (signal?.aborted) {
129
143
  return Promise.resolve({ content: "Aborted", isError: true });
@@ -145,8 +159,29 @@ export class HostTransferProxy {
145
159
  });
146
160
  }
147
161
  } else {
148
- const capable = assistantEventHub.listClientsByCapability("host_file");
149
- if (capable.length === 1) resolvedTargetClientId = capable[0].clientId;
162
+ // Auto-resolve to the unique same-user client; reject ambiguous
163
+ // (multi-machine) cases so a single targeted-style transfer cannot
164
+ // fan out across the user's machines.
165
+ const resolved = pickSameUserAutoResolve({
166
+ hub: assistantEventHub,
167
+ capability: "host_file",
168
+ sourceActorPrincipalId,
169
+ });
170
+ if (resolved.kind === "ambiguous") {
171
+ return Promise.resolve(ambiguousSameUserError("host_file"));
172
+ }
173
+ resolvedTargetClientId =
174
+ resolved.kind === "match" ? resolved.clientId : undefined;
175
+ }
176
+
177
+ if (resolvedTargetClientId != null) {
178
+ const rejection = enforceSameActorOrErrorResult({
179
+ hub: assistantEventHub,
180
+ sourceActorPrincipalId,
181
+ targetClientId: resolvedTargetClientId,
182
+ op: "host_transfer",
183
+ });
184
+ if (rejection != null) return Promise.resolve(rejection);
150
185
  }
151
186
 
152
187
  const requestId = uuid();
@@ -220,12 +255,24 @@ export class HostTransferProxy {
220
255
  sha256,
221
256
  fileBuffer,
222
257
  targetClientId: resolvedTargetClientId,
258
+ targetActorPrincipalId:
259
+ resolvedTargetClientId != null
260
+ ? assistantEventHub.getActorPrincipalIdForClient(
261
+ resolvedTargetClientId,
262
+ )
263
+ : undefined,
223
264
  });
224
265
 
225
266
  pendingInteractions.register(requestId, {
226
267
  conversationId: input.conversationId,
227
268
  kind: "host_transfer",
228
269
  targetClientId: resolvedTargetClientId,
270
+ targetActorPrincipalId:
271
+ resolvedTargetClientId != null
272
+ ? assistantEventHub.getActorPrincipalIdForClient(
273
+ resolvedTargetClientId,
274
+ )
275
+ : undefined,
229
276
  rpcResolve: resolve,
230
277
  rpcReject: reject,
231
278
  timer,
@@ -291,6 +338,8 @@ export class HostTransferProxy {
291
338
  targetClientId?: string;
292
339
  },
293
340
  signal?: AbortSignal,
341
+ // Principal ID of the actor on whose behalf this request is initiated.
342
+ sourceActorPrincipalId?: string,
294
343
  ): Promise<ToolExecutionResult> {
295
344
  if (signal?.aborted) {
296
345
  return Promise.resolve({ content: "Aborted", isError: true });
@@ -312,8 +361,29 @@ export class HostTransferProxy {
312
361
  });
313
362
  }
314
363
  } else {
315
- const capable = assistantEventHub.listClientsByCapability("host_file");
316
- if (capable.length === 1) resolvedTargetClientId = capable[0].clientId;
364
+ // Auto-resolve to the unique same-user client; reject ambiguous
365
+ // (multi-machine) cases so a single targeted-style transfer cannot
366
+ // fan out across the user's machines.
367
+ const resolved = pickSameUserAutoResolve({
368
+ hub: assistantEventHub,
369
+ capability: "host_file",
370
+ sourceActorPrincipalId,
371
+ });
372
+ if (resolved.kind === "ambiguous") {
373
+ return Promise.resolve(ambiguousSameUserError("host_file"));
374
+ }
375
+ resolvedTargetClientId =
376
+ resolved.kind === "match" ? resolved.clientId : undefined;
377
+ }
378
+
379
+ if (resolvedTargetClientId != null) {
380
+ const rejection = enforceSameActorOrErrorResult({
381
+ hub: assistantEventHub,
382
+ sourceActorPrincipalId,
383
+ targetClientId: resolvedTargetClientId,
384
+ op: "host_transfer",
385
+ });
386
+ if (rejection != null) return Promise.resolve(rejection);
317
387
  }
318
388
 
319
389
  const requestId = uuid();
@@ -374,12 +444,24 @@ export class HostTransferProxy {
374
444
  filePath: input.destPath,
375
445
  overwrite: input.overwrite,
376
446
  targetClientId: resolvedTargetClientId,
447
+ targetActorPrincipalId:
448
+ resolvedTargetClientId != null
449
+ ? assistantEventHub.getActorPrincipalIdForClient(
450
+ resolvedTargetClientId,
451
+ )
452
+ : undefined,
377
453
  });
378
454
 
379
455
  pendingInteractions.register(requestId, {
380
456
  conversationId: input.conversationId,
381
457
  kind: "host_transfer",
382
458
  targetClientId: resolvedTargetClientId,
459
+ targetActorPrincipalId:
460
+ resolvedTargetClientId != null
461
+ ? assistantEventHub.getActorPrincipalIdForClient(
462
+ resolvedTargetClientId,
463
+ )
464
+ : undefined,
383
465
  rpcResolve: resolve,
384
466
  rpcReject: reject,
385
467
  timer,
@@ -623,6 +705,15 @@ export class HostTransferProxy {
623
705
  return this.transfers.get(transferId)?.targetClientId ?? null;
624
706
  }
625
707
 
708
+ /**
709
+ * Look up the persisted `targetActorPrincipalId` for a given transferId
710
+ * without consuming the entry. Routes call this for the same-actor
711
+ * binding check so it's stable across brief SSE reconnects.
712
+ */
713
+ getTargetActorPrincipalIdForTransfer(transferId: string): string | undefined {
714
+ return this.transfers.get(transferId)?.targetActorPrincipalId;
715
+ }
716
+
626
717
  dispose(): void {
627
718
  for (const entry of pendingInteractions.getByKind("host_transfer")) {
628
719
  const transferId = entry.metadata?.transferId as string | undefined;
@@ -54,7 +54,6 @@ import { startMemoryJobsWorker } from "../memory/jobs-worker.js";
54
54
  import { initQdrantClient, resolveQdrantUrl } from "../memory/qdrant-client.js";
55
55
  import { QdrantManager } from "../memory/qdrant-manager.js";
56
56
  import { rotateToolInvocations } from "../memory/tool-usage-store.js";
57
- import { deleteOldTraceEvents } from "../memory/trace-event-store.js";
58
57
  import {
59
58
  emitNotificationSignal,
60
59
  registerBroadcastFn,
@@ -62,6 +61,7 @@ import {
62
61
  import { backfillManualTokenConnections } from "../oauth/manual-token-connection.js";
63
62
  import { seedOAuthProviders } from "../oauth/seed-providers.js";
64
63
  import { loadUserPlugins } from "../plugins/user-loader.js";
64
+ import { backfillGuardIfNeeded } from "../proactive-artifact/index.js";
65
65
  import { ensurePromptFiles } from "../prompts/system-prompt.js";
66
66
  import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js";
67
67
  import { broadcastMessage } from "../runtime/assistant-event-hub.js";
@@ -105,6 +105,11 @@ import {
105
105
  cleanupPidFileIfOwner,
106
106
  writePid,
107
107
  } from "./daemon-control.js";
108
+ import {
109
+ evaluateDiskPressureNow,
110
+ startDiskPressureGuard,
111
+ stopDiskPressureGuard,
112
+ } from "./disk-pressure-guard.js";
108
113
  import { bootstrapPlugins } from "./external-plugins-bootstrap.js";
109
114
  import {
110
115
  createGuardianActionCopyGenerator,
@@ -125,11 +130,57 @@ import { DaemonServer } from "./server.js";
125
130
  import { installShutdownHandlers } from "./shutdown-handlers.js";
126
131
 
127
132
  const log = getLogger("lifecycle");
133
+ let diskPressureStartupSampleTimer: ReturnType<typeof setTimeout> | null = null;
128
134
 
129
135
  function loadDotEnv(): void {
130
136
  dotenvConfig({ path: getDotEnvPath(), quiet: true });
131
137
  }
132
138
 
139
+ function runDeferredDiskPressureStartupSample(): void {
140
+ diskPressureStartupSampleTimer = null;
141
+ try {
142
+ const status = evaluateDiskPressureNow();
143
+ if (status.error) {
144
+ log.warn(
145
+ { error: status.error },
146
+ "Disk pressure guard sample failed during startup — continuing unlocked",
147
+ );
148
+ }
149
+ } catch (err) {
150
+ log.warn(
151
+ { err },
152
+ "Disk pressure guard failed during startup — continuing unlocked",
153
+ );
154
+ }
155
+ }
156
+
157
+ export function startDiskPressureGuardForLifecycle(): void {
158
+ try {
159
+ const startedStatus = startDiskPressureGuard();
160
+ if (!startedStatus.enabled) return;
161
+ if (!diskPressureStartupSampleTimer) {
162
+ diskPressureStartupSampleTimer = setTimeout(
163
+ runDeferredDiskPressureStartupSample,
164
+ 0,
165
+ );
166
+ (diskPressureStartupSampleTimer as { unref?: () => void }).unref?.();
167
+ }
168
+ } catch (err) {
169
+ log.warn(
170
+ { err },
171
+ "Disk pressure guard failed during startup — continuing unlocked",
172
+ );
173
+ }
174
+ }
175
+
176
+ export function stopDiskPressureGuardForLifecycle(): void {
177
+ if (diskPressureStartupSampleTimer) {
178
+ clearTimeout(diskPressureStartupSampleTimer);
179
+ diskPressureStartupSampleTimer = null;
180
+ }
181
+ stopDiskPressureGuard();
182
+ }
183
+
133
184
  export interface CesStartupResult {
134
185
  client: CesClient | undefined;
135
186
  processManager: CesProcessManager | undefined;
@@ -448,12 +499,22 @@ export async function runDaemon(): Promise<void> {
448
499
  }
449
500
  } // end if (dbReady)
450
501
 
451
- // Seed managed inference profiles into the workspace config. Runs
452
- // after workspace migrations (which may have created the initial
453
- // profile slots) and before mergeDefaultWorkspaceConfig / loadConfig
454
- // so the profiles are on disk for the first config load.
502
+ // Merge CLI-provided default config (from VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH)
503
+ // into the workspace config file before profile seeding and the first
504
+ // loadConfig() call so onboarding/platform preferences are visible to the
505
+ // seeder and persisted alongside schema defaults.
506
+ const defaultConfigMerge = mergeDefaultWorkspaceConfig();
507
+
508
+ // Seed managed inference profiles into the workspace config. Runs after
509
+ // workspace migrations and default-config merge, but before loadConfig() so
510
+ // fresh hatches have profiles on disk before the first config load. Any
511
+ // profile fields explicitly supplied by the default overlay stay
512
+ // authoritative for this startup.
455
513
  try {
456
- seedInferenceProfiles();
514
+ seedInferenceProfiles({
515
+ preserveProfileNames: defaultConfigMerge.providedLlmProfileNames,
516
+ preserveActiveProfile: defaultConfigMerge.providedLlmActiveProfile,
517
+ });
457
518
  log.info("Inference profile seeding complete");
458
519
  } catch (err) {
459
520
  log.warn(
@@ -462,11 +523,6 @@ export async function runDaemon(): Promise<void> {
462
523
  );
463
524
  }
464
525
 
465
- // Merge CLI-provided default config (from VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH)
466
- // into the workspace config file before the first loadConfig() call so
467
- // onboarding preferences are persisted alongside schema defaults.
468
- mergeDefaultWorkspaceConfig();
469
-
470
526
  log.info("Daemon startup: loading config");
471
527
  const config = loadConfig();
472
528
 
@@ -625,6 +681,7 @@ export async function runDaemon(): Promise<void> {
625
681
 
626
682
  await server.start();
627
683
  log.info("Daemon startup: DaemonServer started");
684
+ startDiskPressureGuardForLifecycle();
628
685
 
629
686
  // Kick off the update bulletin background job AFTER `server.start()`
630
687
  // resolves. The conversation store must be initialized before wake
@@ -1198,22 +1255,6 @@ export async function runDaemon(): Promise<void> {
1198
1255
  }
1199
1256
  }
1200
1257
 
1201
- // Prune trace events older than 7 days to keep the database lean.
1202
- // Deferred so synchronous cleanup doesn't block the startup path.
1203
- setTimeout(() => {
1204
- try {
1205
- const deletedTraceEvents = deleteOldTraceEvents(7);
1206
- if (deletedTraceEvents > 0) {
1207
- log.debug(
1208
- { deletedTraceEvents },
1209
- `Pruned ${deletedTraceEvents} trace event(s) older than 7 days`,
1210
- );
1211
- }
1212
- } catch (err) {
1213
- log.warn({ err }, "Trace event cleanup failed");
1214
- }
1215
- }, 0);
1216
-
1217
1258
  const workspaceHeartbeat = new WorkspaceHeartbeatService();
1218
1259
  workspaceHeartbeat.start();
1219
1260
 
@@ -1236,6 +1277,12 @@ export async function runDaemon(): Promise<void> {
1236
1277
  "Heartbeat service configured",
1237
1278
  );
1238
1279
 
1280
+ try {
1281
+ backfillGuardIfNeeded();
1282
+ } catch (err) {
1283
+ log.warn({ err }, "Proactive artifact backfill failed");
1284
+ }
1285
+
1239
1286
  // Filing yields to the memory v2 consolidation job when the flag is on —
1240
1287
  // both serve the same role (periodic background memory processing) and
1241
1288
  // running both is redundant. The consolidation job runs through the
@@ -1281,10 +1328,14 @@ export async function runDaemon(): Promise<void> {
1281
1328
  getQdrantManager: () => bgRefs.qdrantManager,
1282
1329
  mcpManager,
1283
1330
  telemetryReporter,
1284
- cleanupPidFile,
1331
+ cleanupPidFile: () => {
1332
+ stopDiskPressureGuardForLifecycle();
1333
+ cleanupPidFile();
1334
+ },
1285
1335
  });
1286
1336
  } catch (err) {
1287
1337
  log.error({ err }, "Daemon startup failed — cleaning up");
1338
+ stopDiskPressureGuardForLifecycle();
1288
1339
  cleanupPidFileIfOwner(process.pid);
1289
1340
  throw err;
1290
1341
  }
@@ -72,7 +72,7 @@ import { getLogger } from "../util/logger.js";
72
72
  * keeps the supervisor free of path assumptions and simplifies
73
73
  * tests.
74
74
  */
75
- export interface MeetHostManifest {
75
+ interface MeetHostManifest {
76
76
  /** SHA-256 of the shipped skill source tree. */
77
77
  sourceHash: string;
78
78
  }
@@ -84,7 +84,7 @@ export interface MeetHostManifest {
84
84
  * protocol version) can be threaded through later without a
85
85
  * signature break.
86
86
  */
87
- export interface MeetHostHandshakePayload {
87
+ interface MeetHostHandshakePayload {
88
88
  sourceHash: string;
89
89
  }
90
90
 
@@ -97,7 +97,7 @@ export interface MeetHostHandshakePayload {
97
97
  * supervisor unaware of the rest of the IPC server's surface and avoids a
98
98
  * circular import in tests that already stub `skill-server.js`.
99
99
  */
100
- export interface SkillRequestSender {
100
+ interface SkillRequestSender {
101
101
  sendRequest(
102
102
  connection: SkillIpcConnection,
103
103
  method: string,
@@ -111,7 +111,7 @@ export interface SkillRequestSender {
111
111
  * child. All are optional on construction — production callers
112
112
  * rely on the defaults and tests override one or two at a time.
113
113
  */
114
- export interface MeetHostSupervisorDeps {
114
+ interface MeetHostSupervisorDeps {
115
115
  /** Absolute path to the shipped `meet-join` skill dir, containing `register.ts`. */
116
116
  skillRuntimePath: string;
117
117
  /** Absolute path to a standalone bun binary, or `"bun"` for PATH lookup. */
@@ -109,7 +109,6 @@ const SERIALIZABLE_TOOL_CONTEXT_KEYS = [
109
109
  "callSessionId",
110
110
  "principal",
111
111
  "toolUseId",
112
- "memoryScopeId",
113
112
  "requesterExternalUserId",
114
113
  "requesterChatId",
115
114
  "requesterIdentifier",
@@ -13,10 +13,12 @@ import { getLogger } from "../util/logger.js";
13
13
  const log = getLogger("memory-v2-startup");
14
14
 
15
15
  /**
16
- * Fire-and-forget seed of the v2 parallel skill embedding collection. Gated
17
- * on both the `memory-v2-enabled` feature flag and the workspace-level
18
- * `config.memory.v2.enabled` switch so v2 modules stay out of the v1 startup
19
- * path when v2 is off.
16
+ * Fire-and-forget seed of the v2 skill entries (now indexed alongside concept
17
+ * pages in `memory_v2_concept_pages` under the `skills/<id>` slug prefix), and
18
+ * a one-shot best-effort cleanup of the legacy `memory_v2_skills` Qdrant
19
+ * collection. Gated on both the `memory-v2-enabled` feature flag and the
20
+ * workspace-level `config.memory.v2.enabled` switch so v2 modules stay out of
21
+ * the v1 startup path when v2 is off.
20
22
  *
21
23
  * Uses a dynamic import so v2 code does not load unless the gate passes.
22
24
  * Never awaits — startup must not block on this (see `assistant/CLAUDE.md`
@@ -32,4 +34,12 @@ export function maybeSeedMemoryV2Skills(config: AssistantConfig): void {
32
34
  void import("../memory/v2/skill-store.js")
33
35
  .then(({ seedV2SkillEntries }) => seedV2SkillEntries())
34
36
  .catch((err) => log.warn({ err }, "Failed to seed v2 skill entries"));
37
+ void import("../memory/v2/qdrant.js")
38
+ .then(({ dropLegacySkillsCollection }) => dropLegacySkillsCollection())
39
+ .catch((err) =>
40
+ log.warn(
41
+ { err },
42
+ "Failed to drop legacy memory_v2_skills collection — non-fatal",
43
+ ),
44
+ );
35
45
  }
@@ -20,6 +20,7 @@ export * from "./message-types/computer-use.js";
20
20
  export * from "./message-types/contacts.js";
21
21
  export * from "./message-types/conversations.js";
22
22
  export * from "./message-types/diagnostics.js";
23
+ export * from "./message-types/disk-pressure.js";
23
24
  export * from "./message-types/documents.js";
24
25
  export * from "./message-types/guardian-actions.js";
25
26
  export * from "./message-types/home.js";
@@ -71,6 +72,7 @@ import type {
71
72
  _DiagnosticsClientMessages,
72
73
  _DiagnosticsServerMessages,
73
74
  } from "./message-types/diagnostics.js";
75
+ import type { _DiskPressureServerMessages } from "./message-types/disk-pressure.js";
74
76
  import type {
75
77
  _DocumentsClientMessages,
76
78
  _DocumentsServerMessages,
@@ -203,6 +205,7 @@ export type ServerMessage =
203
205
  | _NotificationsServerMessages
204
206
  | _UpgradesServerMessages
205
207
  | _AcpServerMessages
208
+ | _DiskPressureServerMessages
206
209
  | SubagentEvent;
207
210
 
208
211
  // === Contract schema ===
@@ -29,6 +29,8 @@ interface BaseTransportMetadata {
29
29
  uxBrief?: string;
30
30
  /** Chat type from the gateway (e.g. "private", "group", "supergroup", "channel"). */
31
31
  chatType?: string;
32
+ /** IANA timezone reported by the active client for the current turn. */
33
+ clientTimezone?: string;
32
34
  }
33
35
 
34
36
  /**
@@ -522,6 +524,7 @@ export interface CompactionCircuitClosed {
522
524
  export type ConversationErrorCode =
523
525
  | "PROVIDER_NETWORK"
524
526
  | "PROVIDER_RATE_LIMIT"
527
+ | "MANAGED_USAGE_LIMIT"
525
528
  | "PROVIDER_OVERLOADED"
526
529
  | "PROVIDER_API"
527
530
  | "PROVIDER_BILLING"
@@ -532,6 +535,7 @@ export type ConversationErrorCode =
532
535
  | "CONTEXT_TOO_LARGE"
533
536
  | "CONVERSATION_ABORTED"
534
537
  | "CONVERSATION_PROCESSING_FAILED"
538
+ | "DISK_SPACE_CRITICAL"
535
539
  | "REGENERATE_FAILED"
536
540
  | "UNKNOWN";
537
541
 
@@ -0,0 +1,9 @@
1
+ import type { DiskPressureStatus } from "../disk-pressure-guard.js";
2
+
3
+ /** Server push when the disk pressure status snapshot changes. */
4
+ export interface DiskPressureStatusChanged {
5
+ type: "disk_pressure_status_changed";
6
+ status: DiskPressureStatus;
7
+ }
8
+
9
+ export type _DiskPressureServerMessages = DiskPressureStatusChanged;
@@ -236,10 +236,13 @@ export interface MessageComplete {
236
236
  export interface ErrorMessage {
237
237
  type: "error";
238
238
  conversationId?: string;
239
+ requestId?: string;
239
240
  code?: string;
240
241
  message: string;
241
242
  /** Categorizes the error so the client can offer contextual actions (e.g. "Send Anyway" for secret_blocked). */
242
243
  category?: string;
244
+ /** Machine-readable conversation error category for clients that need source-aware recovery UI. */
245
+ errorCategory?: string;
243
246
  }
244
247
 
245
248
  export interface MessageQueued {
@@ -73,7 +73,7 @@ const DEFAULT_MIN_FREE_MB = 200;
73
73
 
74
74
  // ── Result type ─────────────────────────────────────────────────────────
75
75
 
76
- export interface ProfilerSweepResult {
76
+ interface ProfilerSweepResult {
77
77
  /** Number of completed runs pruned during this sweep. */
78
78
  prunedCount: number;
79
79
  /** Total bytes freed by pruning. */
@@ -159,7 +159,7 @@ function getFreeDiskBytes(path: string): number {
159
159
  // ── Core operations ─────────────────────────────────────────────────────
160
160
 
161
161
  /** Options for {@link rescanRuns}. */
162
- export interface RescanRunsOptions {
162
+ interface RescanRunsOptions {
163
163
  /**
164
164
  * When true, skip all `writeManifest()` calls — just read existing
165
165
  * manifests and recompute sizes without mutating the filesystem.
@@ -384,7 +384,7 @@ export function runProfilerSweep(): ProfilerSweepResult {
384
384
  // health-endpoint reporting and control-plane polling.
385
385
 
386
386
  /** Budget state for the active profiler run. */
387
- export interface ProfilerBudgetStatus {
387
+ interface ProfilerBudgetStatus {
388
388
  /** Configured maximum bytes across all runs. */
389
389
  maxBytes: number;
390
390
  /** Bytes remaining before the byte-count budget is exceeded. */
@@ -398,7 +398,7 @@ export interface ProfilerBudgetStatus {
398
398
  }
399
399
 
400
400
  /** Summary of the most recently completed profiler run. */
401
- export interface ProfilerLastCompletedRun {
401
+ interface ProfilerLastCompletedRun {
402
402
  runId: string;
403
403
  totalBytes: number;
404
404
  artifactCount: number;
@@ -407,7 +407,7 @@ export interface ProfilerLastCompletedRun {
407
407
  }
408
408
 
409
409
  /** Full runtime status snapshot for health-endpoint embedding. */
410
- export interface ProfilerRuntimeStatus {
410
+ interface ProfilerRuntimeStatus {
411
411
  /** Whether profiling is enabled (env vars present). */
412
412
  enabled: boolean;
413
413
  /** The profiling mode ("cpu", "heap", "cpu+heap"), or null when disabled. */
@@ -21,8 +21,8 @@ export interface ToolSetupContext extends SurfaceConversationContext {
21
21
  abortController: AbortController | null;
22
22
  /** When set, only tools in this set may execute during the current turn. */
23
23
  allowedToolNames?: Set<string>;
24
- /** Conversation memory policy used to propagate scopeId into ToolContext. */
25
- memoryPolicy: { scopeId: string };
24
+ /** Turn-scoped disk-pressure cleanup mode flag. */
25
+ diskPressureCleanupModeActive?: boolean;
26
26
  /** True when the conversation has no connected client (HTTP-only path). */
27
27
  hasNoClient?: boolean;
28
28
  /** When true, the conversation is executing a task run and must not become interactive. */
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Shared document persistence service.
3
+ *
4
+ * Extracted from documents-routes.ts so that both HTTP route handlers and
5
+ * background jobs (e.g. proactive artifact generation) can persist documents
6
+ * without going through the HTTP layer.
7
+ */
8
+ import { rawRun } from "../memory/raw-query.js";
9
+ import { getLogger } from "../util/logger.js";
10
+
11
+ const log = getLogger("document-store");
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Junction table helper
15
+ // ---------------------------------------------------------------------------
16
+
17
+ /** Insert a document–conversation association (idempotent via INSERT OR IGNORE). */
18
+ export function addDocumentConversation(
19
+ surfaceId: string,
20
+ conversationId: string,
21
+ ): void {
22
+ rawRun(
23
+ /*sql*/ `INSERT OR IGNORE INTO document_conversations (surface_id, conversation_id, created_at) VALUES (?, ?, ?)`,
24
+ surfaceId,
25
+ conversationId,
26
+ Date.now(),
27
+ );
28
+ }
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Document persistence
32
+ // ---------------------------------------------------------------------------
33
+
34
+ export function saveDocument(params: {
35
+ surfaceId: string;
36
+ conversationId: string;
37
+ title: string;
38
+ content: string;
39
+ wordCount: number;
40
+ }): { success: true; surfaceId: string } | { success: false; error: string } {
41
+ try {
42
+ const now = Date.now();
43
+ rawRun(
44
+ `INSERT INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at)
45
+ VALUES (?, ?, ?, ?, ?, ?, ?)
46
+ ON CONFLICT(surface_id) DO UPDATE SET
47
+ title = excluded.title,
48
+ content = excluded.content,
49
+ word_count = excluded.word_count,
50
+ updated_at = excluded.updated_at`,
51
+ params.surfaceId,
52
+ params.conversationId,
53
+ params.title,
54
+ params.content,
55
+ params.wordCount,
56
+ now,
57
+ now,
58
+ );
59
+ log.info(
60
+ { surfaceId: params.surfaceId, title: params.title },
61
+ "Saved document",
62
+ );
63
+
64
+ // Best-effort: associate the document with the conversation.
65
+ // Failures (e.g. migration not yet applied, table missing) must not
66
+ // cause the save response to report failure — the document itself is
67
+ // already persisted at this point.
68
+ try {
69
+ addDocumentConversation(params.surfaceId, params.conversationId);
70
+ } catch (err) {
71
+ log.warn(
72
+ { err, surfaceId: params.surfaceId },
73
+ "Failed to record document–conversation association",
74
+ );
75
+ }
76
+
77
+ return { success: true, surfaceId: params.surfaceId };
78
+ } catch (error) {
79
+ log.error({ err: error, surfaceId: params.surfaceId }, "Save error");
80
+ return {
81
+ success: false,
82
+ error: error instanceof Error ? error.message : "Unknown error",
83
+ };
84
+ }
85
+ }