@vellumai/assistant 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +68 -15
  3. package/Dockerfile +2 -2
  4. package/bun.lock +6 -2
  5. package/docker-entrypoint.sh +32 -1
  6. package/docs/architecture/integrations.md +1 -1
  7. package/docs/architecture/memory.md +21 -24
  8. package/openapi.yaml +538 -3
  9. package/package.json +5 -1
  10. package/src/__tests__/anthropic-provider.test.ts +160 -95
  11. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  12. package/src/__tests__/app-executors.test.ts +47 -1
  13. package/src/__tests__/app-source-watcher.test.ts +159 -0
  14. package/src/__tests__/checker.test.ts +38 -6
  15. package/src/__tests__/config-schema.test.ts +5 -0
  16. package/src/__tests__/conversation-agent-loop-overflow.test.ts +4 -6
  17. package/src/__tests__/conversation-agent-loop.test.ts +4 -51
  18. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  19. package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
  20. package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
  21. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
  22. package/src/__tests__/conversation-wipe.test.ts +2 -6
  23. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
  24. package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
  25. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  26. package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
  27. package/src/__tests__/date-context.test.ts +76 -210
  28. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
  29. package/src/__tests__/file-list-tool.test.ts +219 -0
  30. package/src/__tests__/first-greeting.test.ts +1 -1
  31. package/src/__tests__/heartbeat-service.test.ts +180 -3
  32. package/src/__tests__/identity-routes.test.ts +328 -0
  33. package/src/__tests__/injection-block.test.ts +24 -0
  34. package/src/__tests__/install-skill-routing.test.ts +7 -6
  35. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +15 -14
  36. package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
  37. package/src/__tests__/llm-context-normalization.test.ts +18 -18
  38. package/src/__tests__/llm-context-route-provider.test.ts +101 -0
  39. package/src/__tests__/llm-request-log-turn-query.test.ts +162 -0
  40. package/src/__tests__/log-export-workspace.test.ts +72 -105
  41. package/src/__tests__/mcp-abort-signal.test.ts +5 -0
  42. package/src/__tests__/mcp-client-auth.test.ts +5 -0
  43. package/src/__tests__/memory-recall-log-store.test.ts +132 -0
  44. package/src/__tests__/migration-export-streaming.test.ts +304 -0
  45. package/src/__tests__/migration-import-commit-http.test.ts +11 -10
  46. package/src/__tests__/mock-fetch.ts +87 -0
  47. package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
  48. package/src/__tests__/onboarding-template-contract.test.ts +62 -14
  49. package/src/__tests__/parser.test.ts +32 -0
  50. package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
  51. package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
  52. package/src/__tests__/permission-mode-sse.test.ts +418 -0
  53. package/src/__tests__/permission-mode-store.test.ts +277 -0
  54. package/src/__tests__/permission-mode.test.ts +101 -0
  55. package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
  56. package/src/__tests__/profiler-routes.test.ts +502 -0
  57. package/src/__tests__/profiler-run-store.test.ts +441 -0
  58. package/src/__tests__/proxy-approval-callback.test.ts +4 -75
  59. package/src/__tests__/registry.test.ts +1 -1
  60. package/src/__tests__/sandbox-host-parity.test.ts +5 -4
  61. package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
  62. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
  63. package/src/__tests__/search-skills-unified.test.ts +4 -3
  64. package/src/__tests__/send-endpoint-busy.test.ts +42 -3
  65. package/src/__tests__/set-permission-mode.test.ts +274 -0
  66. package/src/__tests__/skill-load-feature-flag.test.ts +12 -0
  67. package/src/__tests__/skill-memory.test.ts +2 -783
  68. package/src/__tests__/strip-memory-injections.test.ts +187 -0
  69. package/src/__tests__/subagent-detail.test.ts +84 -0
  70. package/src/__tests__/subagent-disposal.test.ts +308 -0
  71. package/src/__tests__/subagent-manager-notify.test.ts +19 -10
  72. package/src/__tests__/subagent-notify-parent.test.ts +390 -0
  73. package/src/__tests__/subagent-role-registry.test.ts +108 -0
  74. package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
  75. package/src/__tests__/subagent-tools.test.ts +464 -4
  76. package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
  77. package/src/__tests__/task-memory-cleanup.test.ts +12 -12
  78. package/src/__tests__/terminal-tools.test.ts +17 -27
  79. package/src/__tests__/test-preload.ts +4 -0
  80. package/src/__tests__/tool-executor.test.ts +4 -26
  81. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  82. package/src/__tests__/top-level-renderer.test.ts +10 -13
  83. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +116 -2
  84. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
  85. package/src/agent/loop.ts +6 -0
  86. package/src/approvals/guardian-request-resolvers.ts +24 -0
  87. package/src/avatar/traits-png-sync.ts +3 -3
  88. package/src/cli/__tests__/run-assistant-command.ts +29 -0
  89. package/src/cli/commands/__tests__/email-download.test.ts +245 -0
  90. package/src/cli/commands/__tests__/email-list.test.ts +192 -0
  91. package/src/cli/commands/__tests__/email-register.test.ts +186 -0
  92. package/src/cli/commands/__tests__/email-send.test.ts +291 -0
  93. package/src/cli/commands/__tests__/email-status.test.ts +181 -0
  94. package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
  95. package/src/cli/commands/__tests__/routes.test.ts +562 -0
  96. package/src/cli/commands/conversations.ts +1 -8
  97. package/src/cli/commands/email.ts +584 -835
  98. package/src/cli/commands/memory.ts +1 -34
  99. package/src/cli/commands/notifications.ts +7 -2
  100. package/src/cli/commands/oauth/connect.ts +14 -5
  101. package/src/cli/commands/routes.ts +396 -0
  102. package/src/cli/commands/skills.ts +130 -20
  103. package/src/cli/program.ts +2 -0
  104. package/src/cli.ts +1 -120
  105. package/src/config/bundled-skills/app-builder/SKILL.md +4 -1
  106. package/src/config/bundled-skills/gmail/SKILL.md +2 -2
  107. package/src/config/bundled-skills/messaging/SKILL.md +7 -0
  108. package/src/config/bundled-skills/schedule/SKILL.md +22 -2
  109. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  110. package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
  111. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
  112. package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
  113. package/src/config/bundled-skills/slack/SKILL.md +2 -0
  114. package/src/config/bundled-skills/subagent/SKILL.md +43 -3
  115. package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
  116. package/src/config/env-registry.ts +63 -0
  117. package/src/config/feature-flag-registry.json +17 -1
  118. package/src/config/schema.ts +8 -0
  119. package/src/config/schemas/filing.ts +51 -0
  120. package/src/config/schemas/heartbeat.ts +15 -12
  121. package/src/config/schemas/memory-lifecycle.ts +12 -0
  122. package/src/config/schemas/security.ts +14 -0
  123. package/src/daemon/app-source-watcher.ts +93 -0
  124. package/src/daemon/config-watcher.ts +79 -1
  125. package/src/daemon/conversation-agent-loop-handlers.ts +20 -0
  126. package/src/daemon/conversation-agent-loop.ts +158 -65
  127. package/src/daemon/conversation-history.ts +4 -19
  128. package/src/daemon/conversation-lifecycle.ts +8 -14
  129. package/src/daemon/conversation-process.ts +13 -7
  130. package/src/daemon/conversation-runtime-assembly.ts +300 -306
  131. package/src/daemon/conversation-tool-setup.ts +44 -14
  132. package/src/daemon/conversation-workspace.ts +1 -2
  133. package/src/daemon/conversation.ts +18 -0
  134. package/src/daemon/date-context.ts +26 -53
  135. package/src/daemon/first-greeting.ts +1 -1
  136. package/src/daemon/handlers/conversations.ts +4 -7
  137. package/src/daemon/handlers/shared.test.ts +143 -0
  138. package/src/daemon/handlers/shared.ts +63 -5
  139. package/src/daemon/handlers/skills.ts +11 -18
  140. package/src/daemon/lifecycle.ts +199 -157
  141. package/src/daemon/message-types/conversations.ts +25 -6
  142. package/src/daemon/message-types/messages.ts +9 -1
  143. package/src/daemon/message-types/schedules.ts +1 -0
  144. package/src/daemon/message-types/settings.ts +6 -0
  145. package/src/daemon/profiler-run-store.ts +557 -0
  146. package/src/daemon/server.ts +89 -9
  147. package/src/daemon/shutdown-handlers.ts +5 -0
  148. package/src/daemon/tool-side-effects.ts +23 -3
  149. package/src/export/transcript-formatter.ts +148 -0
  150. package/src/filing/filing-service.ts +228 -0
  151. package/src/heartbeat/heartbeat-service.ts +96 -7
  152. package/src/mcp/client.ts +6 -0
  153. package/src/mcp/mcp-oauth-provider.ts +149 -27
  154. package/src/memory/admin.ts +33 -32
  155. package/src/memory/app-store.ts +69 -0
  156. package/src/memory/conversation-bootstrap.ts +1 -1
  157. package/src/memory/conversation-crud.ts +136 -107
  158. package/src/memory/conversation-group-migration.ts +1 -1
  159. package/src/memory/conversation-queries.ts +58 -12
  160. package/src/memory/conversation-title-service.ts +1 -0
  161. package/src/memory/db-init.ts +182 -376
  162. package/src/memory/graph/bootstrap.ts +75 -66
  163. package/src/memory/graph/capability-seed.ts +167 -15
  164. package/src/memory/graph/consolidation.ts +38 -4
  165. package/src/memory/graph/conversation-graph-memory.ts +133 -104
  166. package/src/memory/graph/extraction-job.ts +9 -4
  167. package/src/memory/graph/extraction.ts +66 -23
  168. package/src/memory/graph/graph-memory-state-store.ts +37 -0
  169. package/src/memory/graph/graph-search.ts +29 -15
  170. package/src/memory/graph/injection.ts +38 -8
  171. package/src/memory/graph/inspect.ts +12 -3
  172. package/src/memory/graph/retriever.ts +365 -262
  173. package/src/memory/graph/store.test.ts +48 -0
  174. package/src/memory/graph/store.ts +150 -11
  175. package/src/memory/graph/tool-handlers.ts +84 -209
  176. package/src/memory/graph/tools.ts +8 -52
  177. package/src/memory/graph/types.ts +24 -0
  178. package/src/memory/job-handlers/cleanup.ts +44 -1
  179. package/src/memory/jobs-store.ts +70 -60
  180. package/src/memory/jobs-worker.ts +44 -28
  181. package/src/memory/llm-request-log-store.ts +96 -12
  182. package/src/memory/memory-recall-log-store.ts +49 -5
  183. package/src/memory/migrations/203-drop-memory-items-tables.ts +33 -1
  184. package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
  185. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
  186. package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
  187. package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
  188. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
  189. package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
  190. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
  191. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
  192. package/src/memory/migrations/index.ts +8 -0
  193. package/src/memory/migrations/registry.ts +8 -0
  194. package/src/memory/schema/conversations.ts +14 -0
  195. package/src/memory/schema/infrastructure.ts +8 -1
  196. package/src/memory/schema/memory-core.ts +0 -51
  197. package/src/memory/schema/memory-graph.ts +15 -0
  198. package/src/memory/task-memory-cleanup.ts +30 -11
  199. package/src/notifications/copy-composer.ts +86 -0
  200. package/src/notifications/decision-engine.ts +35 -0
  201. package/src/permissions/checker.ts +12 -1
  202. package/src/permissions/permission-mode-store.ts +180 -0
  203. package/src/permissions/permission-mode.ts +31 -0
  204. package/src/permissions/workspace-policy.ts +9 -0
  205. package/src/prompts/system-prompt.ts +59 -7
  206. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
  207. package/src/prompts/templates/BOOTSTRAP.md +70 -165
  208. package/src/prompts/templates/HEARTBEAT.md +3 -1
  209. package/src/prompts/templates/SOUL.md +25 -4
  210. package/src/prompts/templates/UPDATES.md +8 -0
  211. package/src/providers/anthropic/client.ts +107 -219
  212. package/src/runtime/auth/route-policy.ts +23 -0
  213. package/src/runtime/http-server.ts +32 -2
  214. package/src/runtime/http-types.ts +12 -1
  215. package/src/runtime/migrations/vbundle-builder.ts +389 -3
  216. package/src/runtime/migrations/vbundle-importer.ts +8 -6
  217. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
  218. package/src/runtime/routes/app-management-routes.ts +1 -11
  219. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
  220. package/src/runtime/routes/archive-utils.ts +29 -0
  221. package/src/runtime/routes/avatar-routes.ts +2 -9
  222. package/src/runtime/routes/btw-routes.ts +14 -1
  223. package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
  224. package/src/runtime/routes/conversation-management-routes.ts +1 -14
  225. package/src/runtime/routes/conversation-query-routes.ts +49 -3
  226. package/src/runtime/routes/conversation-routes.ts +264 -44
  227. package/src/runtime/routes/heartbeat-routes.ts +4 -10
  228. package/src/runtime/routes/identity-routes.ts +53 -18
  229. package/src/runtime/routes/llm-context-normalization.ts +14 -10
  230. package/src/runtime/routes/log-export-routes.ts +23 -275
  231. package/src/runtime/routes/memory-item-routes.test.ts +168 -233
  232. package/src/runtime/routes/migration-routes.ts +18 -7
  233. package/src/runtime/routes/profiler-routes.ts +350 -0
  234. package/src/runtime/routes/schedule-routes.ts +27 -12
  235. package/src/runtime/routes/settings-routes.ts +95 -8
  236. package/src/runtime/routes/subagents-routes.ts +28 -7
  237. package/src/runtime/routes/user-route-dispatcher.ts +223 -0
  238. package/src/runtime/routes/user-routes.ts +41 -0
  239. package/src/runtime/routes/workspace-routes.ts +0 -1
  240. package/src/schedule/schedule-store.ts +30 -0
  241. package/src/schedule/scheduler.ts +45 -18
  242. package/src/skills/catalog-install.ts +10 -2
  243. package/src/skills/managed-store.ts +2 -2
  244. package/src/skills/skill-memory.ts +1 -293
  245. package/src/subagent/index.ts +13 -3
  246. package/src/subagent/manager.ts +308 -29
  247. package/src/subagent/types.ts +68 -0
  248. package/src/tasks/task-runner.ts +4 -4
  249. package/src/tools/apps/executors.ts +29 -4
  250. package/src/tools/filesystem/list.ts +93 -0
  251. package/src/tools/permission-checker.ts +78 -0
  252. package/src/tools/registry.ts +4 -0
  253. package/src/tools/schedule/create.ts +3 -0
  254. package/src/tools/schedule/list.ts +1 -0
  255. package/src/tools/schedule/update.ts +6 -0
  256. package/src/tools/shared/filesystem/errors.ts +5 -0
  257. package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
  258. package/src/tools/shared/filesystem/types.ts +17 -0
  259. package/src/tools/shared/shell-output.ts +31 -2
  260. package/src/tools/subagent/abort.ts +12 -2
  261. package/src/tools/subagent/message.ts +9 -2
  262. package/src/tools/subagent/notify-parent.ts +79 -0
  263. package/src/tools/subagent/read.ts +29 -8
  264. package/src/tools/subagent/resolve.ts +21 -0
  265. package/src/tools/subagent/spawn.ts +2 -0
  266. package/src/tools/subagent/status.ts +11 -1
  267. package/src/tools/system/avatar-generator.ts +3 -3
  268. package/src/tools/system/register.ts +23 -0
  269. package/src/tools/system/set-permission-mode.ts +103 -0
  270. package/src/tools/terminal/parser.ts +30 -5
  271. package/src/tools/terminal/safe-env.ts +16 -1
  272. package/src/tools/tool-manifest.ts +6 -0
  273. package/src/tools/types.ts +2 -0
  274. package/src/util/logger.ts +1 -1
  275. package/src/util/platform.ts +50 -17
  276. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
  277. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
  278. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
  279. package/src/workspace/migrations/029-seed-pkb.ts +84 -0
  280. package/src/workspace/migrations/registry.ts +4 -0
  281. package/src/workspace/top-level-renderer.ts +5 -9
  282. package/src/__tests__/cli-memory.test.ts +0 -377
  283. package/src/__tests__/clipboard.test.ts +0 -88
  284. package/src/cli/cli-memory.ts +0 -179
  285. package/src/util/clipboard.ts +0 -34
@@ -5,7 +5,6 @@ import { reconcileCallsOnStartup } from "../calls/call-recovery.js";
5
5
  import { setRelayBroadcast } from "../calls/relay-server.js";
6
6
  import { TwilioConversationRelayProvider } from "../calls/twilio-provider.js";
7
7
  import { setVoiceBridgeDeps } from "../calls/voice-session-bridge.js";
8
- import { seedCliCommandMemories } from "../cli/cli-memory.js";
9
8
  import {
10
9
  getPlatformAssistantId,
11
10
  getQdrantHttpPortEnv,
@@ -32,6 +31,7 @@ import {
32
31
  awaitCesClientWithTimeout,
33
32
  DEFAULT_CES_STARTUP_TIMEOUT_MS,
34
33
  } from "../credential-execution/startup-timeout.js";
34
+ import { FilingService } from "../filing/filing-service.js";
35
35
  import { HeartbeatService } from "../heartbeat/heartbeat-service.js";
36
36
  import { getHookManager } from "../hooks/manager.js";
37
37
  import { installTemplates } from "../hooks/templates.js";
@@ -82,10 +82,6 @@ import {
82
82
  setCesClient,
83
83
  setCesReconnect,
84
84
  } from "../security/secure-keys.js";
85
- import {
86
- seedCatalogSkillMemories,
87
- seedUninstalledCatalogSkillMemories,
88
- } from "../skills/skill-memory.js";
89
85
  import { UsageTelemetryReporter } from "../telemetry/usage-telemetry-reporter.js";
90
86
  import { getDeviceId } from "../util/device-id.js";
91
87
  import { getLogger, initLogger } from "../util/logger.js";
@@ -127,6 +123,7 @@ import {
127
123
  } from "./handlers/conversations.js";
128
124
  import { installAssistantSymlink } from "./install-symlink.js";
129
125
  import type { ServerMessage } from "./message-protocol.js";
126
+ import { runProfilerSweep } from "./profiler-run-store.js";
130
127
  import {
131
128
  initializeProvidersAndTools,
132
129
  registerMessagingProviders,
@@ -282,151 +279,191 @@ export async function runDaemon(): Promise<void> {
282
279
  // workspace migrations (e.g. 009-backfill-conversation-disk-view)
283
280
  // depend on DB migrations having run (e.g. the inline-attachment-to-disk
284
281
  // backfill that populates attachment filePaths).
285
- initializeDb();
286
- // Seed well-known OAuth provider configurations (insert-if-not-exists)
287
- seedOAuthProviders();
288
- log.info("Daemon startup: DB initialized");
289
-
290
- await runWorkspaceMigrations(getWorkspaceDir(), WORKSPACE_MIGRATIONS);
291
- log.info("Daemon startup: workspace migrations complete");
292
-
293
- // Backfill oauth_connection rows for manual-token providers (Telegram,
294
- // Slack channel) that already have stored credentials from before the
295
- // oauth_connection migration. Safe to call on every startup.
296
282
  //
297
- // Must run AFTER workspace migrations.
298
- // Otherwise syncManualTokenConnection sees no stored credentials and
299
- // incorrectly removes existing connection rows.
283
+ // If DB initialization fails (e.g. a migration error), the daemon
284
+ // continues in a degraded state DB-dependent features won't work but
285
+ // the HTTP server and config-based subsystems still start so the process
286
+ // remains reachable for health checks and diagnostics.
287
+ let dbReady = false;
300
288
  try {
301
- await backfillManualTokenConnections();
289
+ initializeDb();
290
+ dbReady = true;
291
+ log.info("Daemon startup: DB initialized");
302
292
  } catch (err) {
303
- log.warn(
293
+ log.error(
304
294
  { err },
305
- "Manual-token connection backfill failed — continuing startup",
295
+ "DB initialization failed — continuing startup in degraded mode",
306
296
  );
307
297
  }
308
298
 
309
- // Backfill injection templates on Slack bot token credentials so the
310
- // credential proxy can inject Authorization headers. Safe on every startup.
311
- try {
312
- backfillSlackInjectionTemplates();
313
- } catch (err) {
314
- log.warn(
315
- { err },
316
- "Slack injection template backfill failed — continuing startup",
317
- );
299
+ // Seed well-known OAuth provider configurations (insert-if-not-exists).
300
+ // Runs in its own try/catch so a seeding error doesn't force degraded mode
301
+ // when the DB itself initialized successfully.
302
+ if (dbReady) {
303
+ try {
304
+ seedOAuthProviders();
305
+ } catch (err) {
306
+ log.warn({ err }, "OAuth provider seeding failed — continuing startup");
307
+ }
318
308
  }
319
309
 
320
- // Now that workspace migrations have run (including 003-seed-device-id
321
- // which may copy the legacy installationId into device.json), it is safe
322
- // to read the device ID and set the Sentry tag.
323
- setSentryDeviceId(getDeviceId());
310
+ if (dbReady) {
311
+ await runWorkspaceMigrations(getWorkspaceDir(), WORKSPACE_MIGRATIONS);
312
+ log.info("Daemon startup: workspace migrations complete");
324
313
 
325
- // Purge private (temporary) conversations from the previous daemon run.
326
- // These are ephemeral by design and should not survive daemon restarts.
327
- const { count: purgedCount, deletedMemory } = purgePrivateConversations();
328
- if (purgedCount > 0) {
329
- log.info(
330
- { purgedCount },
331
- `Purged ${purgedCount} private conversation(s) from previous daemon run`,
332
- );
333
- // Qdrant may not be ready at startup, so enqueue vector cleanup jobs
334
- // rather than attempting direct deletion.
335
- for (const segId of deletedMemory.segmentIds) {
336
- enqueueMemoryJob("delete_qdrant_vectors", {
337
- targetType: "segment",
338
- targetId: segId,
339
- });
314
+ // Profiler retention sweep prune completed profiler runs to stay
315
+ // within configured byte-count, run-count, and free-space budgets.
316
+ // Runs on every startup and is safe to call from explicit cleanup routes.
317
+ try {
318
+ const sweepResult = runProfilerSweep();
319
+ if (sweepResult.prunedCount > 0 || sweepResult.activeRunOverBudget) {
320
+ log.info(
321
+ {
322
+ prunedCount: sweepResult.prunedCount,
323
+ freedBytes: sweepResult.freedBytes,
324
+ activeRunOverBudget: sweepResult.activeRunOverBudget,
325
+ remainingRuns: sweepResult.remainingRuns,
326
+ },
327
+ "Profiler retention sweep completed on startup",
328
+ );
329
+ }
330
+ } catch (err) {
331
+ log.warn(
332
+ { err },
333
+ "Profiler retention sweep failed — continuing startup",
334
+ );
340
335
  }
341
- for (const itemId of deletedMemory.orphanedItemIds) {
342
- enqueueMemoryJob("delete_qdrant_vectors", {
343
- targetType: "item",
344
- targetId: itemId,
345
- });
336
+
337
+ // Backfill oauth_connection rows for manual-token providers (Telegram,
338
+ // Slack channel) that already have stored credentials from before the
339
+ // oauth_connection migration. Safe to call on every startup.
340
+ //
341
+ // Must run AFTER workspace migrations.
342
+ // Otherwise syncManualTokenConnection sees no stored credentials and
343
+ // incorrectly removes existing connection rows.
344
+ try {
345
+ await backfillManualTokenConnections();
346
+ } catch (err) {
347
+ log.warn(
348
+ { err },
349
+ "Manual-token connection backfill failed — continuing startup",
350
+ );
346
351
  }
347
- for (const summaryId of deletedMemory.deletedSummaryIds) {
348
- enqueueMemoryJob("delete_qdrant_vectors", {
349
- targetType: "summary",
350
- targetId: summaryId,
351
- });
352
+
353
+ // Backfill injection templates on Slack bot token credentials so the
354
+ // credential proxy can inject Authorization headers. Safe on every startup.
355
+ try {
356
+ backfillSlackInjectionTemplates();
357
+ } catch (err) {
358
+ log.warn(
359
+ { err },
360
+ "Slack injection template backfill failed — continuing startup",
361
+ );
352
362
  }
353
- if (
354
- deletedMemory.segmentIds.length > 0 ||
355
- deletedMemory.orphanedItemIds.length > 0 ||
356
- deletedMemory.deletedSummaryIds.length > 0
357
- ) {
363
+
364
+ // Now that workspace migrations have run (including 003-seed-device-id
365
+ // which may copy the legacy installationId into device.json), it is safe
366
+ // to read the device ID and set the Sentry tag.
367
+ setSentryDeviceId(getDeviceId());
368
+
369
+ // Purge private (temporary) conversations from the previous daemon run.
370
+ // These are ephemeral by design and should not survive daemon restarts.
371
+ const { count: purgedCount, deletedMemory } = purgePrivateConversations();
372
+ if (purgedCount > 0) {
358
373
  log.info(
359
- {
360
- segments: deletedMemory.segmentIds.length,
361
- orphanedItems: deletedMemory.orphanedItemIds.length,
362
- deletedSummaries: deletedMemory.deletedSummaryIds.length,
363
- },
364
- "Enqueued Qdrant vector cleanup jobs for purged private conversations",
374
+ { purgedCount },
375
+ `Purged ${purgedCount} private conversation(s) from previous daemon run`,
365
376
  );
377
+ // Qdrant may not be ready at startup, so enqueue vector cleanup jobs
378
+ // rather than attempting direct deletion.
379
+ for (const segId of deletedMemory.segmentIds) {
380
+ enqueueMemoryJob("delete_qdrant_vectors", {
381
+ targetType: "segment",
382
+ targetId: segId,
383
+ });
384
+ }
385
+ for (const summaryId of deletedMemory.deletedSummaryIds) {
386
+ enqueueMemoryJob("delete_qdrant_vectors", {
387
+ targetType: "summary",
388
+ targetId: summaryId,
389
+ });
390
+ }
391
+ if (
392
+ deletedMemory.segmentIds.length > 0 ||
393
+ deletedMemory.deletedSummaryIds.length > 0
394
+ ) {
395
+ log.info(
396
+ {
397
+ segments: deletedMemory.segmentIds.length,
398
+ deletedSummaries: deletedMemory.deletedSummaryIds.length,
399
+ },
400
+ "Enqueued Qdrant vector cleanup jobs for purged private conversations",
401
+ );
402
+ }
366
403
  }
367
- }
368
404
 
369
- // Expire stale pending canonical guardian requests left over from before
370
- // this process started. Two categories are cleaned up:
371
- //
372
- // 1. Interaction-bound kinds (tool_approval, pending_question) — their
373
- // in-memory pending-interaction session references are gone, so they
374
- // can never be completed.
375
- // 2. Any pending request whose expiresAt has already passed — persistent
376
- // kinds (access_request, tool_grant_request) that expired while the
377
- // daemon was stopped are transitioned so dedup logic doesn't return
378
- // stale rows.
379
- const expiredCount = expireAllPendingCanonicalRequests();
380
- if (expiredCount > 0) {
381
- log.info(
382
- { event: "startup_expired_stale_requests", expiredCount },
383
- `Expired ${expiredCount} stale canonical request(s) from previous process`,
384
- );
385
- }
405
+ // Expire stale pending canonical guardian requests left over from before
406
+ // this process started. Two categories are cleaned up:
407
+ //
408
+ // 1. Interaction-bound kinds (tool_approval, pending_question) — their
409
+ // in-memory pending-interaction session references are gone, so they
410
+ // can never be completed.
411
+ // 2. Any pending request whose expiresAt has already passed — persistent
412
+ // kinds (access_request, tool_grant_request) that expired while the
413
+ // daemon was stopped are transitioned so dedup logic doesn't return
414
+ // stale rows.
415
+ const expiredCount = expireAllPendingCanonicalRequests();
416
+ if (expiredCount > 0) {
417
+ log.info(
418
+ { event: "startup_expired_stale_requests", expiredCount },
419
+ `Expired ${expiredCount} stale canonical request(s) from previous process`,
420
+ );
421
+ }
386
422
 
387
- // Ensure a vellum guardian binding exists so the identity system works
388
- // without requiring a manual bootstrap step.
389
- try {
390
- ensureVellumGuardianBinding(DAEMON_INTERNAL_ASSISTANT_ID);
391
- } catch (err) {
392
- log.warn(
393
- { err },
394
- "Vellum guardian binding backfill failed — continuing startup",
395
- );
396
- }
423
+ // Ensure a vellum guardian binding exists so the identity system works
424
+ // without requiring a manual bootstrap step.
425
+ try {
426
+ ensureVellumGuardianBinding(DAEMON_INTERNAL_ASSISTANT_ID);
427
+ } catch (err) {
428
+ log.warn(
429
+ { err },
430
+ "Vellum guardian binding backfill failed — continuing startup",
431
+ );
432
+ }
397
433
 
398
- try {
399
- syncUpdateBulletinOnStartup();
400
- } catch (err) {
401
- log.warn({ err }, "Bulletin sync failed — continuing startup");
402
- }
434
+ try {
435
+ syncUpdateBulletinOnStartup();
436
+ } catch (err) {
437
+ log.warn({ err }, "Bulletin sync failed — continuing startup");
438
+ }
403
439
 
404
- // Recover orphaned work items that were left in 'running' state when the
405
- // daemon previously crashed or was killed mid-task.
406
- const orphanedRunning = listWorkItems({ status: "running" });
407
- if (orphanedRunning.length > 0) {
408
- for (const item of orphanedRunning) {
409
- updateWorkItem(item.id, {
410
- status: "failed",
411
- lastRunStatus: "interrupted",
412
- });
440
+ // Recover orphaned work items that were left in 'running' state when the
441
+ // daemon previously crashed or was killed mid-task.
442
+ const orphanedRunning = listWorkItems({ status: "running" });
443
+ if (orphanedRunning.length > 0) {
444
+ for (const item of orphanedRunning) {
445
+ updateWorkItem(item.id, {
446
+ status: "failed",
447
+ lastRunStatus: "interrupted",
448
+ });
449
+ log.info(
450
+ { workItemId: item.id, title: item.title },
451
+ "Recovered orphaned running work item → failed (interrupted)",
452
+ );
453
+ }
413
454
  log.info(
414
- { workItemId: item.id, title: item.title },
415
- "Recovered orphaned running work item → failed (interrupted)",
455
+ { count: orphanedRunning.length },
456
+ "Recovered orphaned running work items",
416
457
  );
417
458
  }
418
- log.info(
419
- { count: orphanedRunning.length },
420
- "Recovered orphaned running work items",
421
- );
422
- }
423
459
 
424
- try {
425
- const twilioProvider = new TwilioConversationRelayProvider();
426
- await reconcileCallsOnStartup(twilioProvider, log);
427
- } catch (err) {
428
- log.warn({ err }, "Call recovery failed — continuing startup");
429
- }
460
+ try {
461
+ const twilioProvider = new TwilioConversationRelayProvider();
462
+ await reconcileCallsOnStartup(twilioProvider, log);
463
+ } catch (err) {
464
+ log.warn({ err }, "Call recovery failed — continuing startup");
465
+ }
466
+ } // end if (dbReady)
430
467
 
431
468
  // Merge CLI-provided default config (from VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH)
432
469
  // into the workspace config file before the first loadConfig() call so
@@ -645,35 +682,21 @@ export async function runDaemon(): Promise<void> {
645
682
  log.info("Daemon startup: starting memory worker");
646
683
  bgRefs.memoryWorker = startMemoryJobsWorker();
647
684
 
648
- // Seed capability memories for all enabled skills so the memory
649
- // pipeline can surface relevant skills via semantic search.
650
- try {
651
- seedCatalogSkillMemories();
652
- } catch (err) {
653
- log.warn({ err }, "Catalog skill memory seeding failed — continuing");
654
- }
655
-
656
- // Seed memories for catalog skills not yet installed so they're
657
- // discoverable via memory injection and can be auto-installed.
658
- void seedUninstalledCatalogSkillMemories().catch((err) =>
659
- log.warn(
660
- { err },
661
- "Uninstalled catalog skill memory seeding failed — continuing",
662
- ),
663
- );
664
-
665
- try {
666
- seedCliCommandMemories();
667
- } catch (err) {
668
- log.warn({ err }, "CLI command memory seeding failed — continuing");
669
- }
670
-
671
685
  // Seed capability graph nodes (new memory graph system)
672
686
  try {
673
- const { seedSkillGraphNodes, seedCliGraphNodes } =
674
- await import("../memory/graph/capability-seed.js");
687
+ const {
688
+ seedSkillGraphNodes,
689
+ seedCliGraphNodes,
690
+ seedUninstalledCatalogSkillMemories,
691
+ } = await import("../memory/graph/capability-seed.js");
675
692
  seedSkillGraphNodes();
676
693
  seedCliGraphNodes();
694
+ void seedUninstalledCatalogSkillMemories().catch((err) =>
695
+ log.warn(
696
+ { err },
697
+ "Uninstalled catalog skill memory seeding failed — continuing",
698
+ ),
699
+ );
677
700
  } catch (err) {
678
701
  log.warn({ err }, "Graph capability seeding failed — continuing");
679
702
  }
@@ -682,10 +705,8 @@ export async function runDaemon(): Promise<void> {
682
705
  // segments exist, enqueue a one-time graph_bootstrap job to populate the
683
706
  // graph from conversation history and journal files.
684
707
  try {
685
- const {
686
- maybeEnqueueGraphBootstrap,
687
- cleanupStaleItemVectors,
688
- } = await import("../memory/graph/bootstrap.js");
708
+ const { maybeEnqueueGraphBootstrap, cleanupStaleItemVectors } =
709
+ await import("../memory/graph/bootstrap.js");
689
710
  maybeEnqueueGraphBootstrap();
690
711
  // Fire-and-forget: clean up orphaned Qdrant vectors from dropped memory_items table
691
712
  void cleanupStaleItemVectors().catch((err) =>
@@ -849,8 +870,8 @@ export async function runDaemon(): Promise<void> {
849
870
  guardianFollowUpConversationGenerator:
850
871
  createGuardianFollowUpConversationGenerator(),
851
872
  sendMessageDeps: {
852
- getOrCreateConversation: (conversationId) =>
853
- server.getConversationForMessages(conversationId),
873
+ getOrCreateConversation: (conversationId, options) =>
874
+ server.getConversationForMessages(conversationId, options),
854
875
  assistantEventHub,
855
876
  resolveAttachments: (attachmentIds) => {
856
877
  const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds, {
@@ -1226,6 +1247,26 @@ export async function runDaemon(): Promise<void> {
1226
1247
  "Heartbeat service configured",
1227
1248
  );
1228
1249
 
1250
+ const filingConfig = config.filing;
1251
+ const filing = new FilingService({
1252
+ processMessage: (conversationId, content, options) =>
1253
+ server.processMessage(conversationId, content, undefined, {
1254
+ trustContext: {
1255
+ sourceChannel: "vellum",
1256
+ trustClass: "guardian",
1257
+ },
1258
+ ...options,
1259
+ }),
1260
+ });
1261
+ filing.start();
1262
+ log.info(
1263
+ {
1264
+ enabled: filingConfig.enabled,
1265
+ intervalMs: filingConfig.intervalMs,
1266
+ },
1267
+ "Filing service configured",
1268
+ );
1269
+
1229
1270
  // Retrieve the MCP manager if MCP servers were configured.
1230
1271
  // The manager is a singleton created during initializeProvidersAndTools().
1231
1272
  const mcpManager =
@@ -1237,6 +1278,7 @@ export async function runDaemon(): Promise<void> {
1237
1278
  server,
1238
1279
  workspaceHeartbeat,
1239
1280
  heartbeat,
1281
+ filing,
1240
1282
  hookManager,
1241
1283
  runtimeHttp,
1242
1284
  scheduler,
@@ -14,12 +14,10 @@ export interface ConversationListRequest {
14
14
  limit?: number;
15
15
  }
16
16
 
17
- /** Lightweight conversation transport metadata for channel identity and natural-language guidance. */
18
- export interface ConversationTransportMetadata {
17
+ /** Shared fields for all transport metadata variants. */
18
+ interface BaseTransportMetadata {
19
19
  /** Logical channel identifier (e.g. "desktop", "telegram", "mobile"). */
20
20
  channelId: ChannelId;
21
- /** Interface identifier for this transport (e.g. "macos", "ios", "cli"). */
22
- interfaceId?: InterfaceId;
23
21
  /** Optional natural-language hints for channel-specific UX behavior. */
24
22
  hints?: string[];
25
23
  /** Optional concise UX brief for this channel. */
@@ -28,6 +26,27 @@ export interface ConversationTransportMetadata {
28
26
  chatType?: string;
29
27
  }
30
28
 
29
+ /** Transport metadata for macOS desktop clients, including host environment fields. */
30
+ export interface MacosTransportMetadata extends BaseTransportMetadata {
31
+ /** Interface identifier for macOS transport. */
32
+ interfaceId: "macos";
33
+ /** Home directory of the host macOS user. */
34
+ hostHomeDir?: string;
35
+ /** Username of the host macOS user. */
36
+ hostUsername?: string;
37
+ }
38
+
39
+ /** Transport metadata for non-macOS transports. */
40
+ export interface NonMacosTransportMetadata extends BaseTransportMetadata {
41
+ /** Interface identifier for this transport (e.g. "ios", "cli"). */
42
+ interfaceId?: Exclude<InterfaceId, "macos">;
43
+ }
44
+
45
+ /** Lightweight conversation transport metadata for channel identity and natural-language guidance. */
46
+ export type ConversationTransportMetadata =
47
+ | MacosTransportMetadata
48
+ | NonMacosTransportMetadata;
49
+
31
50
  export interface ConversationCreateRequest {
32
51
  type: "conversation_create";
33
52
  title?: string;
@@ -310,11 +329,11 @@ export interface HistoryResponse {
310
329
  contentOrder?: string[];
311
330
  /** UI surfaces (widgets) embedded in the message. */
312
331
  surfaces?: HistoryResponseSurface[];
313
- /** Present when this message is a subagent lifecycle notification (completed/failed/aborted). */
332
+ /** Present when this message is a subagent lifecycle notification (running/completed/failed/aborted). */
314
333
  subagentNotification?: {
315
334
  subagentId: string;
316
335
  label: string;
317
- status: "completed" | "failed" | "aborted";
336
+ status: "running" | "completed" | "failed" | "aborted";
318
337
  error?: string;
319
338
  conversationId?: string;
320
339
  };
@@ -308,6 +308,13 @@ export interface AssistantActivityState {
308
308
  statusText?: string;
309
309
  }
310
310
 
311
+ /** Broadcast to clients when the two-axis permission mode changes. */
312
+ export interface PermissionModeUpdate {
313
+ type: "permission_mode_update";
314
+ askBeforeActing: boolean;
315
+ hostAccess: boolean;
316
+ }
317
+
311
318
  export type TraceEventKind =
312
319
  | "request_received"
313
320
  | "request_queued"
@@ -369,4 +376,5 @@ export type _MessagesServerMessages =
369
376
  | SuggestionResponse
370
377
  | TraceEvent
371
378
  | ConfirmationStateChanged
372
- | AssistantActivityState;
379
+ | AssistantActivityState
380
+ | PermissionModeUpdate;
@@ -74,6 +74,7 @@ export interface SchedulesListResponse {
74
74
  mode: string;
75
75
  status: string;
76
76
  routingIntent: string;
77
+ reuseConversation: boolean;
77
78
  isOneShot: boolean;
78
79
  }>;
79
80
  }
@@ -34,6 +34,11 @@ export interface AvatarUpdated {
34
34
  avatarPath: string;
35
35
  }
36
36
 
37
+ /** Sent by the daemon when sounds config or sound files change on disk. */
38
+ export interface SoundsConfigUpdated {
39
+ type: "sounds_config_updated";
40
+ }
41
+
37
42
  /** Response to a generate_avatar request indicating success or failure. */
38
43
  export interface GenerateAvatarResponse {
39
44
  type: "generate_avatar_response";
@@ -51,4 +56,5 @@ export type _SettingsClientMessages =
51
56
  export type _SettingsServerMessages =
52
57
  | ClientSettingsUpdate
53
58
  | AvatarUpdated
59
+ | SoundsConfigUpdated
54
60
  | GenerateAvatarResponse;