@vellumai/assistant 0.8.4 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docs/browser-use-architecture-phase2.md +1 -1
  3. package/knip.json +2 -1
  4. package/openapi.yaml +809 -11
  5. package/package.json +1 -1
  6. package/src/__tests__/anthropic-provider.test.ts +34 -37
  7. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  8. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  9. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
  11. package/src/__tests__/btw-routes.test.ts +2 -3
  12. package/src/__tests__/call-controller.test.ts +0 -1
  13. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  14. package/src/__tests__/channel-guardian.test.ts +3 -3
  15. package/src/__tests__/checker.test.ts +6 -15
  16. package/src/__tests__/compaction-events.test.ts +1 -0
  17. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  18. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  19. package/src/__tests__/computer-use-tools.test.ts +2 -4
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  21. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  22. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
  24. package/src/__tests__/conversation-agent-loop.test.ts +163 -122
  25. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  26. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  27. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  29. package/src/__tests__/conversation-error.test.ts +31 -0
  30. package/src/__tests__/conversation-fork-crud.test.ts +178 -15
  31. package/src/__tests__/conversation-lifecycle.test.ts +52 -11
  32. package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
  33. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
  34. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  36. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  37. package/src/__tests__/conversation-store.test.ts +1 -1
  38. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  40. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  42. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  43. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  44. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  45. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  46. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  47. package/src/__tests__/email-html-renderer.test.ts +12 -0
  48. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  49. package/src/__tests__/gemini-provider.test.ts +78 -0
  50. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  51. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  52. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  53. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  54. package/src/__tests__/heartbeat-service.test.ts +4 -0
  55. package/src/__tests__/host-shell-tool.test.ts +1 -1
  56. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  57. package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
  58. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  59. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  60. package/src/__tests__/llm-resolver.test.ts +77 -9
  61. package/src/__tests__/llm-usage-store.test.ts +66 -0
  62. package/src/__tests__/logger.test.ts +89 -0
  63. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  64. package/src/__tests__/media-generate-image.test.ts +31 -0
  65. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  66. package/src/__tests__/model-intents.test.ts +2 -4
  67. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  68. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  69. package/src/__tests__/openai-provider.test.ts +46 -0
  70. package/src/__tests__/openai-responses-provider.test.ts +114 -12
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
  72. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  73. package/src/__tests__/platform.test.ts +2 -2
  74. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  75. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  76. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  77. package/src/__tests__/plugin-types.test.ts +3 -2
  78. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  79. package/src/__tests__/pricing.test.ts +12 -0
  80. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  81. package/src/__tests__/registry.test.ts +2 -8
  82. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  83. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  84. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  85. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  86. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  87. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  88. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  89. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  90. package/src/__tests__/suggestion-routes.test.ts +1 -0
  91. package/src/__tests__/sync-message-contract.test.ts +59 -0
  92. package/src/__tests__/system-prompt.test.ts +145 -131
  93. package/src/__tests__/terminal-tools.test.ts +1 -1
  94. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  95. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  96. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  97. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  98. package/src/__tests__/tool-executor.test.ts +9 -62
  99. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  100. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  101. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  102. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  103. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  104. package/src/__tests__/usage-routes.test.ts +3 -0
  105. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  106. package/src/__tests__/workspace-git-service.test.ts +6 -5
  107. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  108. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  109. package/src/acp/prepare-agent-env.ts +78 -0
  110. package/src/acp/session-manager.ts +1 -1
  111. package/src/agent/loop.ts +8 -0
  112. package/src/api/README.md +5 -0
  113. package/src/api/index.ts +4 -0
  114. package/src/api/package.json +10 -0
  115. package/src/background-wake/background-wake-routes.test.ts +233 -0
  116. package/src/background-wake/runtime-registry.ts +24 -0
  117. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  118. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  119. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  120. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  121. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  122. package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
  123. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  124. package/src/cli/commands/browser.ts +247 -0
  125. package/src/cli/commands/domain.ts +91 -41
  126. package/src/cli/commands/inference.ts +93 -40
  127. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  128. package/src/cli/commands/memory-v2.ts +176 -1
  129. package/src/cli/commands/memory-v3-render.ts +344 -0
  130. package/src/cli/commands/memory-v3.ts +316 -0
  131. package/src/cli/program.ts +2 -0
  132. package/src/config/assistant-feature-flags.ts +21 -9
  133. package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
  134. package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
  135. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  136. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  137. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  138. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  139. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  140. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  141. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  142. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  143. package/src/config/bundled-tool-registry.ts +2 -0
  144. package/src/config/call-site-defaults.ts +7 -6
  145. package/src/config/feature-flag-registry.json +16 -0
  146. package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
  147. package/src/config/schemas/call-site-catalog.ts +21 -7
  148. package/src/config/schemas/llm.ts +12 -1
  149. package/src/config/schemas/memory-v2.ts +246 -0
  150. package/src/config/schemas/memory.ts +2 -1
  151. package/src/context/compactor.ts +52 -0
  152. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  153. package/src/conversations/message-consolidation.ts +404 -0
  154. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  155. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  156. package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
  157. package/src/daemon/conversation-agent-loop.ts +126 -76
  158. package/src/daemon/conversation-error.ts +31 -1
  159. package/src/daemon/conversation-lifecycle.ts +27 -22
  160. package/src/daemon/conversation-runtime-assembly.ts +10 -9
  161. package/src/daemon/conversation-tool-setup.ts +63 -3
  162. package/src/daemon/conversation-usage.ts +2 -0
  163. package/src/daemon/conversation.ts +14 -29
  164. package/src/daemon/disk-pressure-guard.ts +14 -2
  165. package/src/daemon/handlers/config-model.test.ts +1 -0
  166. package/src/daemon/handlers/conversations.ts +11 -3
  167. package/src/daemon/host-browser-proxy.ts +5 -5
  168. package/src/daemon/host-cu-proxy.ts +4 -4
  169. package/src/daemon/host-file-proxy.ts +4 -4
  170. package/src/daemon/host-proxy-base.ts +4 -4
  171. package/src/daemon/host-transfer-proxy.ts +10 -10
  172. package/src/daemon/lifecycle.ts +23 -20
  173. package/src/daemon/meet-manifest-loader.ts +1 -7
  174. package/src/daemon/message-types/conversations.ts +6 -9
  175. package/src/daemon/message-types/home.ts +1 -13
  176. package/src/daemon/message-types/messages.ts +6 -14
  177. package/src/daemon/message-types/sync.ts +14 -0
  178. package/src/daemon/shutdown-handlers.ts +24 -5
  179. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  180. package/src/daemon/tool-setup-types.ts +13 -0
  181. package/src/events/relationship-state-updated.ts +25 -0
  182. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
  183. package/src/home/home-greeting.ts +0 -9
  184. package/src/home/suggested-prompts.ts +0 -9
  185. package/src/ipc/gateway-flag-listener.ts +123 -0
  186. package/src/ipc/skill-routes/registries.ts +8 -12
  187. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  188. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  189. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  190. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  191. package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
  192. package/src/memory/auto-analysis-enqueue.ts +5 -1
  193. package/src/memory/conversation-crud.ts +71 -70
  194. package/src/memory/conversation-starters-cadence.ts +3 -1
  195. package/src/memory/conversation-title-service.ts +19 -3
  196. package/src/memory/db-async-query.ts +214 -0
  197. package/src/memory/db-init.ts +10 -0
  198. package/src/memory/db-maintenance.ts +30 -21
  199. package/src/memory/graph/bootstrap.ts +8 -1
  200. package/src/memory/graph/capability-seed.ts +7 -3
  201. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  202. package/src/memory/graph/extraction.ts +1 -5
  203. package/src/memory/graph/graph-search.ts +7 -1
  204. package/src/memory/indexer.ts +28 -18
  205. package/src/memory/job-handlers/cleanup.ts +76 -18
  206. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  207. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  208. package/src/memory/jobs-store.ts +14 -0
  209. package/src/memory/jobs-worker.ts +55 -22
  210. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  211. package/src/memory/llm-request-log-source-local.ts +7 -0
  212. package/src/memory/llm-request-log-source.ts +9 -2
  213. package/src/memory/llm-request-log-store.ts +43 -1
  214. package/src/memory/llm-usage-store.ts +24 -0
  215. package/src/memory/memory-retrospective-enqueue.ts +8 -1
  216. package/src/memory/memory-retrospective-job.ts +5 -0
  217. package/src/memory/memory-v2-activation-log-store.ts +15 -6
  218. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  219. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  220. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  221. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  222. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  223. package/src/memory/migrations/index.ts +17 -0
  224. package/src/memory/migrations/registry.ts +33 -0
  225. package/src/memory/schema/conversations.ts +1 -1
  226. package/src/memory/schema/infrastructure.ts +21 -0
  227. package/src/memory/tool-usage-store.ts +36 -8
  228. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  229. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  230. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  231. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  232. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  233. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  234. package/src/memory/v2/__tests__/injection.test.ts +127 -98
  235. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  236. package/src/memory/v2/__tests__/router.test.ts +171 -3
  237. package/src/memory/v2/harness/compare.ts +57 -0
  238. package/src/memory/v2/harness/metrics.ts +124 -0
  239. package/src/memory/v2/harness/oracle.ts +145 -0
  240. package/src/memory/v2/harness/replay-input.ts +224 -0
  241. package/src/memory/v2/harness/retriever.ts +74 -0
  242. package/src/memory/v2/harness/router-retriever.ts +43 -0
  243. package/src/memory/v2/harness/runner.ts +106 -0
  244. package/src/memory/v2/harness/trace.ts +58 -0
  245. package/src/memory/v2/injection.ts +21 -15
  246. package/src/memory/v2/prompts/router.ts +26 -1
  247. package/src/memory/v2/qdrant.ts +14 -2
  248. package/src/memory/v2/router.ts +171 -18
  249. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  250. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  251. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  252. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  253. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  254. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  255. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  256. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  257. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  258. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  259. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  260. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  261. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  262. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  263. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  264. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  265. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  266. package/src/memory/v3/auto-edges.ts +223 -0
  267. package/src/memory/v3/coactivation-store.ts +124 -0
  268. package/src/memory/v3/consolidation-job.ts +323 -0
  269. package/src/memory/v3/edge-learning-job.ts +160 -0
  270. package/src/memory/v3/edges.ts +249 -0
  271. package/src/memory/v3/filter.ts +281 -0
  272. package/src/memory/v3/gate.ts +334 -0
  273. package/src/memory/v3/index-composition.ts +113 -0
  274. package/src/memory/v3/llm-capture.ts +46 -0
  275. package/src/memory/v3/loop.ts +382 -0
  276. package/src/memory/v3/maintenance.ts +144 -0
  277. package/src/memory/v3/prompt-context.ts +33 -0
  278. package/src/memory/v3/prompts/consolidation.ts +458 -0
  279. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  280. package/src/memory/v3/retriever.ts +33 -0
  281. package/src/memory/v3/scouts.ts +420 -0
  282. package/src/memory/v3/shadow-middleware.ts +305 -0
  283. package/src/memory/v3/traversal.ts +206 -0
  284. package/src/memory/v3/tree-index.ts +237 -0
  285. package/src/memory/v3/tree-store.ts +394 -0
  286. package/src/memory/v3/tree-walk.ts +351 -0
  287. package/src/memory/v3/types.ts +65 -0
  288. package/src/memory/v3/validate.ts +300 -0
  289. package/src/notifications/adapters/macos.ts +18 -1
  290. package/src/notifications/adapters/platform.ts +1 -1
  291. package/src/notifications/decision-engine.ts +1 -4
  292. package/src/notifications/emit-signal.ts +29 -49
  293. package/src/permissions/prompter.ts +3 -3
  294. package/src/permissions/question-prompter.ts +5 -2
  295. package/src/permissions/secret-prompter.ts +2 -2
  296. package/src/plugin-api/index.ts +4 -0
  297. package/src/plugin-api/types.ts +7 -33
  298. package/src/plugins/defaults/index.ts +6 -0
  299. package/src/plugins/defaults/injectors.ts +18 -11
  300. package/src/plugins/external-plugin-loader.ts +5 -68
  301. package/src/plugins/types.ts +11 -16
  302. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  303. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  304. package/src/prompts/persona-resolver.ts +36 -21
  305. package/src/prompts/sections.ts +39 -7
  306. package/src/prompts/system-prompt.ts +50 -185
  307. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  308. package/src/prompts/templates/system-sections.ts +230 -8
  309. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  310. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  311. package/src/providers/anthropic/client.ts +32 -66
  312. package/src/providers/call-site-routing.ts +14 -2
  313. package/src/providers/connection-model-compat.ts +38 -0
  314. package/src/providers/connection-resolution.ts +16 -2
  315. package/src/providers/gemini/client.ts +49 -6
  316. package/src/providers/inference/adapter-factory.ts +3 -0
  317. package/src/providers/minimax/client.ts +106 -0
  318. package/src/providers/model-catalog.ts +43 -0
  319. package/src/providers/model-intents.ts +1 -1
  320. package/src/providers/openai/chat-completions-provider.ts +6 -3
  321. package/src/providers/openai/codex-models.ts +18 -0
  322. package/src/providers/openai/responses-provider.ts +78 -21
  323. package/src/providers/provider-send-message.ts +7 -1
  324. package/src/providers/retry.ts +34 -3
  325. package/src/providers/thinking-config.ts +26 -1
  326. package/src/providers/usage-tracking.ts +2 -0
  327. package/src/runtime/AGENTS.md +2 -2
  328. package/src/runtime/agent-wake.ts +1 -0
  329. package/src/runtime/assistant-event-hub.ts +76 -6
  330. package/src/runtime/auth/route-policy.ts +36 -0
  331. package/src/runtime/btw-sidechain.ts +0 -6
  332. package/src/runtime/http-types.ts +0 -2
  333. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  334. package/src/runtime/pending-interactions.ts +0 -1
  335. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
  336. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
  337. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  338. package/src/runtime/routes/acp-routes.test.ts +255 -6
  339. package/src/runtime/routes/acp-routes.ts +8 -1
  340. package/src/runtime/routes/avatar-routes.ts +10 -10
  341. package/src/runtime/routes/background-wake-routes.ts +188 -0
  342. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  343. package/src/runtime/routes/btw-routes.ts +0 -6
  344. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  345. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  346. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  347. package/src/runtime/routes/conversation-query-routes.ts +142 -36
  348. package/src/runtime/routes/conversation-routes.ts +252 -410
  349. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  350. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  351. package/src/runtime/routes/domain-routes.ts +60 -10
  352. package/src/runtime/routes/email-routes.ts +5 -2
  353. package/src/runtime/routes/events-routes.ts +54 -10
  354. package/src/runtime/routes/group-routes.ts +24 -8
  355. package/src/runtime/routes/host-browser-routes.ts +10 -2
  356. package/src/runtime/routes/host-cu-routes.ts +2 -2
  357. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  358. package/src/runtime/routes/index.ts +8 -0
  359. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  360. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  361. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  362. package/src/runtime/routes/memory-item-routes.ts +8 -3
  363. package/src/runtime/routes/memory-v2-routes.ts +215 -5
  364. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  365. package/src/runtime/routes/migration-routes.ts +21 -24
  366. package/src/runtime/routes/plugins-routes.ts +337 -0
  367. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  368. package/src/runtime/routes/secret-routes.ts +25 -5
  369. package/src/runtime/routes/settings-routes.ts +12 -11
  370. package/src/runtime/routes/slack-channel-routes.ts +5 -4
  371. package/src/runtime/routes/workspace-routes.ts +25 -10
  372. package/src/runtime/sync/resource-sync-events.ts +106 -38
  373. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  374. package/src/runtime/sync/sync-publisher.ts +2 -1
  375. package/src/runtime/verification-outbound-actions.ts +73 -1
  376. package/src/telemetry/types.ts +12 -0
  377. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  378. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  379. package/src/tools/acp/spawn.test.ts +119 -0
  380. package/src/tools/acp/spawn.ts +15 -2
  381. package/src/tools/apps/definitions.ts +2 -8
  382. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  383. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  384. package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
  385. package/src/tools/browser/browser-execution.ts +16 -3
  386. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  387. package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
  388. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
  389. package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
  390. package/src/tools/browser/cdp-client/factory.ts +100 -17
  391. package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
  392. package/src/tools/browser/cdp-client/types.ts +65 -0
  393. package/src/tools/browser/pinned-tabs.ts +96 -40
  394. package/src/tools/computer-use/definitions.ts +22 -78
  395. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  396. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  397. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  398. package/src/tools/credentials/vault.ts +3 -9
  399. package/src/tools/document/document-tool.ts +59 -0
  400. package/src/tools/execution-target.ts +21 -23
  401. package/src/tools/executor.ts +6 -1
  402. package/src/tools/filesystem/edit.ts +3 -9
  403. package/src/tools/filesystem/list.ts +3 -9
  404. package/src/tools/filesystem/read.ts +3 -9
  405. package/src/tools/filesystem/write.ts +3 -9
  406. package/src/tools/host-filesystem/edit.ts +3 -9
  407. package/src/tools/host-filesystem/read.ts +3 -9
  408. package/src/tools/host-filesystem/transfer.ts +3 -9
  409. package/src/tools/host-filesystem/write.ts +3 -9
  410. package/src/tools/host-terminal/host-shell.ts +3 -9
  411. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  412. package/src/tools/memory/register.test.ts +1 -1
  413. package/src/tools/memory/register.ts +4 -9
  414. package/src/tools/network/web-fetch.ts +3 -9
  415. package/src/tools/network/web-search.ts +25 -32
  416. package/src/tools/registry.ts +7 -23
  417. package/src/tools/schema-transforms.ts +1 -1
  418. package/src/tools/skills/execute.ts +3 -9
  419. package/src/tools/skills/load.ts +3 -9
  420. package/src/tools/skills/skill-tool-factory.ts +1 -8
  421. package/src/tools/subagent/notify-parent.ts +3 -9
  422. package/src/tools/system/request-permission.ts +3 -9
  423. package/src/tools/terminal/shell.ts +3 -9
  424. package/src/tools/tool-defaults.ts +94 -0
  425. package/src/tools/types.ts +27 -98
  426. package/src/tools/ui-surface/definitions.ts +6 -22
  427. package/src/usage/pricing.ts +23 -0
  428. package/src/usage/types.ts +12 -0
  429. package/src/util/logger.ts +16 -7
  430. package/src/util/platform.ts +7 -2
  431. package/src/util/sqlite3-runtime.ts +65 -0
  432. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  433. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  434. package/src/workspace/migrations/registry.ts +2 -0
  435. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  436. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  437. package/src/daemon/query-complexity-router.ts +0 -75
  438. package/src/prompts/cache-boundary.ts +0 -8
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Single source of truth for the defaults applied when a `ToolDefinition`
3
+ * omits one of the normally-required fields, plus the `finalizeTool`
4
+ * helper that lifts a `ToolDefinition` into a `LoadedTool`.
5
+ *
6
+ * Plugins, external loaders, and any other registration boundary that
7
+ * accepts loose `ToolDefinition` objects from authors must run them
8
+ * through `finalizeTool` before handing the result to a `registerXxxTools`
9
+ * call. The registry types make this a hard rule: every registered tool
10
+ * is a `LoadedTool` (`Required<ToolDefinition> & { name }`).
11
+ */
12
+
13
+ import type {
14
+ LoadedTool,
15
+ RiskLevel,
16
+ ToolDefinition,
17
+ ToolExecutionResult,
18
+ } from "./types.js";
19
+
20
+ /**
21
+ * Default values applied by `finalizeTool` when the author omits a field.
22
+ *
23
+ * - `description` defaults to empty — the model sees the tool name only
24
+ * for un-documented tools, which is the correct minimal-info signal.
25
+ * - `defaultRiskLevel` defaults to `medium` — the safe middle band that
26
+ * forces explicit approval for risky calls without spamming approval
27
+ * prompts on no-op tools.
28
+ * - `input_schema` defaults to an empty closed object — the model is
29
+ * allowed to call the tool with no arguments, and unknown arguments
30
+ * are rejected at the JSON-schema layer.
31
+ * - `executionTarget` defaults to `sandbox` — author-supplied tool code
32
+ * runs in the assistant container by default; opt in to `host` when
33
+ * the tool proxies work to the connected client.
34
+ *
35
+ * `execute` has no constant default because the default closure needs to
36
+ * close over the tool's name to produce a useful error message; see
37
+ * `finalizeTool` below.
38
+ */
39
+ export const TOOL_DEFAULTS = Object.freeze({
40
+ description: "",
41
+ defaultRiskLevel: "medium" as RiskLevel,
42
+ input_schema: Object.freeze({
43
+ type: "object",
44
+ properties: {},
45
+ additionalProperties: false,
46
+ }) as object,
47
+ executionTarget: "sandbox" as const,
48
+ });
49
+
50
+ /**
51
+ * Fill the four normally-required `ToolDefinition` fields with documented
52
+ * defaults when the author omitted them, attach the registration-time
53
+ * `name`, and return a `LoadedTool` that is safe to hand to a
54
+ * `registerXxxTools` call.
55
+ *
56
+ * The default `execute` returns an error result so the model sees a clear
57
+ * "this tool isn't wired up" signal at call time. The owning loader still
58
+ * registers the tool cleanly — a broken individual tool must never block
59
+ * the registration batch.
60
+ */
61
+ export function finalizeTool(
62
+ tool: ToolDefinition,
63
+ name: string,
64
+ ): LoadedTool {
65
+ const description =
66
+ typeof tool.description === "string"
67
+ ? tool.description
68
+ : TOOL_DEFAULTS.description;
69
+ const defaultRiskLevel =
70
+ typeof tool.defaultRiskLevel === "string"
71
+ ? tool.defaultRiskLevel
72
+ : TOOL_DEFAULTS.defaultRiskLevel;
73
+ const input_schema =
74
+ tool.input_schema !== null && typeof tool.input_schema === "object"
75
+ ? tool.input_schema
76
+ : TOOL_DEFAULTS.input_schema;
77
+ const execute =
78
+ typeof tool.execute === "function"
79
+ ? tool.execute
80
+ : async (): Promise<ToolExecutionResult> => ({
81
+ content: `tool ${name} has no execute implementation`,
82
+ isError: true,
83
+ });
84
+ const executionTarget = tool.executionTarget ?? TOOL_DEFAULTS.executionTarget;
85
+ return {
86
+ ...tool,
87
+ name,
88
+ description,
89
+ defaultRiskLevel,
90
+ input_schema,
91
+ executionTarget,
92
+ execute,
93
+ };
94
+ }
@@ -5,7 +5,6 @@ import type {
5
5
  ProxyApprovalCallback,
6
6
  RiskLevel,
7
7
  SensitiveOutputBinding,
8
- ToolDefinition,
9
8
  ToolExecutionErrorEvent,
10
9
  ToolExecutionStartEvent,
11
10
  ToolPermissionDeniedEvent,
@@ -64,7 +63,6 @@ export type {
64
63
  ProxyEnvVars,
65
64
  SensitiveOutputBinding,
66
65
  SensitiveOutputKind,
67
- ToolDefinition,
68
66
  ToolExecutionErrorEvent,
69
67
  ToolExecutionStartEvent,
70
68
  ToolPermissionDeniedEvent,
@@ -76,19 +74,7 @@ export { RiskLevel } from "@vellumai/skill-host-contracts";
76
74
  // Assistant-side concrete overlays
77
75
  // ---------------------------------------------------------------------------
78
76
 
79
- /**
80
- * Public, narrow subset of {@link ToolExecutionResult} that plugin-authored
81
- * tools are responsible for producing. Re-exported from
82
- * `@vellumai/plugin-api` as `ToolExecutionResult` — the type name plugin
83
- * authors actually import. The daemon-internal version below extends
84
- * this and adds runtime-only fields (risk metadata, approval
85
- * bookkeeping, sensitive-output bindings, etc.) that the executor
86
- * populates around the call — plugins MUST NOT set those.
87
- *
88
- * Adding fields here is a non-breaking change; renaming or removing
89
- * fields is breaking and gated on a major bump of `@vellumai/plugin-api`.
90
- */
91
- export interface PluginToolExecutionResult {
77
+ export interface ToolExecutionResult {
92
78
  /** Textual result shown to the model in the tool-result block. Empty string is valid. */
93
79
  content: string;
94
80
  /** When true, the agent loop treats `content` as an error and may surface it / retry. */
@@ -105,9 +91,6 @@ export interface PluginToolExecutionResult {
105
91
  * the LLM voluntarily end its turn.
106
92
  */
107
93
  yieldToUser?: boolean;
108
- }
109
-
110
- export interface ToolExecutionResult extends PluginToolExecutionResult {
111
94
  diff?: DiffInfo;
112
95
  /** Optional rich content blocks (e.g. images) to include alongside text in the tool result. */
113
96
  contentBlocks?: ContentBlock[];
@@ -211,20 +194,7 @@ export type ToolLifecycleEventHandler = (
211
194
  event: ToolLifecycleEvent,
212
195
  ) => void | Promise<void>;
213
196
 
214
- /**
215
- * Public, narrow subset of {@link ToolContext} handed to plugin-authored
216
- * tools. Re-exported from `@vellumai/plugin-api` as `ToolContext` — the
217
- * type name plugin authors actually import. The daemon-internal version
218
- * below extends this and adds host-only fields (CES client, trust class,
219
- * lifecycle handlers, requester metadata, host-bash proxy, etc.). Plugin
220
- * tools see this shape only — the runtime still hands them the full
221
- * {@link ToolContext} value, but the structural extension here guarantees
222
- * the assignment without a manual cast.
223
- *
224
- * Adding fields here is a non-breaking change; renaming or removing
225
- * fields is breaking and gated on a major bump of `@vellumai/plugin-api`.
226
- */
227
- export interface PluginToolContext {
197
+ export interface ToolContext {
228
198
  /** Identifier of the conversation this tool invocation belongs to. */
229
199
  conversationId: string;
230
200
  /** Working directory the daemon was launched from. */
@@ -235,9 +205,6 @@ export interface PluginToolContext {
235
205
  signal?: AbortSignal;
236
206
  /** Optional incremental-output callback for streaming tools. Streaming tools should fall back to returning the full result in `content` when this is absent. */
237
207
  onOutput?: (chunk: string) => void;
238
- }
239
-
240
- export interface ToolContext extends PluginToolContext {
241
208
  /** Logical assistant scope for multi-assistant routing. */
242
209
  assistantId?: string;
243
210
  /** When set, the tool execution is part of a task run. Used to retrieve ephemeral permission rules. */
@@ -349,11 +316,32 @@ export interface ToolContext extends PluginToolContext {
349
316
  sourceActorPrincipalId?: string;
350
317
  }
351
318
 
352
- export interface Tool {
353
- name: string;
354
- description: string;
319
+ /**
320
+ * Author-facing tool spec — re-exported from `@vellumai/plugin-api`.
321
+ * Loaders fill documented defaults for omitted fields via `finalizeTool`
322
+ * in `tool-defaults.ts`.
323
+ */
324
+ export interface ToolDefinition {
325
+ /** Human-readable description shown to the model in the tool catalog. */
326
+ description?: string;
327
+ /** Author-asserted risk band — low / medium / high. Drives default permission gating. */
328
+ defaultRiskLevel?: RiskLevel;
329
+ /** JSON schema describing the tool's input arguments. */
330
+ input_schema?: object;
331
+ /** Where the tool runs — sandbox (assistant container) or host (guardian device via proxy). Resolved by `resolveExecutionTarget` if omitted. */
332
+ executionTarget?: ExecutionTarget;
333
+ /** Implementation invoked when the model calls the tool. */
334
+ execute?: (
335
+ input: Record<string, unknown>,
336
+ context: ToolContext,
337
+ ) => Promise<ToolExecutionResult>;
338
+ }
339
+
340
+ /** Tool after the loader has derived its name and filled defaults. */
341
+ export type LoadedTool = Required<ToolDefinition> & { name: string };
342
+
343
+ export interface Tool extends LoadedTool {
355
344
  category: string;
356
- defaultRiskLevel: RiskLevel;
357
345
  /** When set to 'proxy', the tool is forwarded to a connected client rather than executed locally. */
358
346
  executionMode?: "local" | "proxy";
359
347
  /** Whether this tool is a core built-in, provided by a skill, contributed by a plugin, or from an MCP server. */
@@ -368,63 +356,4 @@ export interface Tool {
368
356
  ownerSkillVersionHash?: string;
369
357
  /** Whether the owning skill is bundled with the daemon (trusted first-party). */
370
358
  ownerSkillBundled?: boolean;
371
- /** Declared execution target from the skill manifest. Used by resolveExecutionTarget
372
- * to accurately label lifecycle events for skill-provided tools. */
373
- executionTarget?: ExecutionTarget;
374
- getDefinition(): ToolDefinition;
375
- execute(
376
- input: Record<string, unknown>,
377
- context: ToolContext,
378
- ): Promise<ToolExecutionResult>;
379
359
  }
380
-
381
- /**
382
- * Plugin-facing tool shape. The narrow surface plugin authors implement;
383
- * differs from {@link Tool} in four ways:
384
- * - Plugins declare `input_schema` as a top-level field instead of
385
- * implementing `getDefinition()`. The registration boundary synthesizes
386
- * `getDefinition()` from `{name, description, input_schema}` before the
387
- * tool enters the internal registry.
388
- * - `name` is derived from the tool file's basename by the external plugin
389
- * loader.
390
- * - `category` is registry-owned and stamped to `"plugin"` when the tool is
391
- * registered.
392
- * - All ownership stamps (`origin`, `ownerPluginId`, etc.) are set
393
- * authoritatively by the bootstrap; plugin authors leave them blank.
394
- *
395
- * Every author-visible field is optional. The loader fills the four
396
- * normally-required slots (`description`, `defaultRiskLevel`,
397
- * `input_schema`, `execute`) with documented defaults when a plugin omits
398
- * them — see `applyPluginToolDefaults` in `external-plugin-loader.ts`.
399
- * A nameless, body-less `export default {}` is a valid (if useless) tool;
400
- * misconfigured tools surface at call time rather than blocking plugin
401
- * load.
402
- */
403
- export type PluginTool = Omit<
404
- Tool,
405
- "category" | "getDefinition" | "name" | "description" | "defaultRiskLevel"
406
- > & {
407
- description?: string;
408
- defaultRiskLevel?: RiskLevel;
409
- input_schema?: object;
410
- execute?: (
411
- input: Record<string, unknown>,
412
- context: ToolContext,
413
- ) => Promise<ToolExecutionResult>;
414
- };
415
-
416
- /**
417
- * Plugin tool after the external loader has derived its registry name and
418
- * filled defaults for any author-omitted fields. All four normally-required
419
- * slots are guaranteed present.
420
- */
421
- export type LoadedPluginTool = PluginTool & {
422
- name: string;
423
- description: string;
424
- defaultRiskLevel: RiskLevel;
425
- input_schema: object;
426
- execute: (
427
- input: Record<string, unknown>,
428
- context: ToolContext,
429
- ) => Promise<ToolExecutionResult>;
430
- };
@@ -8,7 +8,6 @@
8
8
  */
9
9
 
10
10
  import { RiskLevel } from "../../permissions/types.js";
11
- import type { ToolDefinition } from "../../providers/types.js";
12
11
  import type { Tool, ToolExecutionResult } from "../types.js";
13
12
 
14
13
  // ---------------------------------------------------------------------------
@@ -42,12 +41,9 @@ export const uiShowTool: Tool = {
42
41
  category: "ui-surface",
43
42
  defaultRiskLevel: RiskLevel.Low,
44
43
  executionMode: "proxy",
44
+ executionTarget: "host",
45
45
 
46
- getDefinition(): ToolDefinition {
47
- return {
48
- name: this.name,
49
- description: this.description,
50
- input_schema: {
46
+ input_schema: {
51
47
  type: "object",
52
48
  properties: {
53
49
  surface_type: {
@@ -109,8 +105,6 @@ export const uiShowTool: Tool = {
109
105
  },
110
106
  required: ["surface_type", "data"],
111
107
  },
112
- };
113
- },
114
108
 
115
109
  execute: proxyExecute,
116
110
  };
@@ -127,12 +121,9 @@ const uiUpdateTool: Tool = {
127
121
  category: "ui-surface",
128
122
  defaultRiskLevel: RiskLevel.Low,
129
123
  executionMode: "proxy",
124
+ executionTarget: "host",
130
125
 
131
- getDefinition(): ToolDefinition {
132
- return {
133
- name: this.name,
134
- description: this.description,
135
- input_schema: {
126
+ input_schema: {
136
127
  type: "object",
137
128
  properties: {
138
129
  surface_id: {
@@ -146,8 +137,6 @@ const uiUpdateTool: Tool = {
146
137
  },
147
138
  required: ["surface_id", "data"],
148
139
  },
149
- };
150
- },
151
140
 
152
141
  execute: proxyExecute,
153
142
  };
@@ -162,12 +151,9 @@ const uiDismissTool: Tool = {
162
151
  category: "ui-surface",
163
152
  defaultRiskLevel: RiskLevel.Low,
164
153
  executionMode: "proxy",
154
+ executionTarget: "host",
165
155
 
166
- getDefinition(): ToolDefinition {
167
- return {
168
- name: this.name,
169
- description: this.description,
170
- input_schema: {
156
+ input_schema: {
171
157
  type: "object",
172
158
  properties: {
173
159
  surface_id: {
@@ -177,8 +163,6 @@ const uiDismissTool: Tool = {
177
163
  },
178
164
  required: ["surface_id"],
179
165
  },
180
- };
181
- },
182
166
 
183
167
  execute: proxyExecute,
184
168
  };
@@ -20,9 +20,32 @@ function normalizeTokenCount(value: number | null | undefined): number {
20
20
 
21
21
  function asRecord(value: unknown): Record<string, unknown> | null {
22
22
  if (typeof value !== "object" || value == null) return null;
23
+ if (Array.isArray(value)) return null;
23
24
  return value as Record<string, unknown>;
24
25
  }
25
26
 
27
+ /**
28
+ * Extract the provider's untouched `usage` block from a `rawResponse`
29
+ * payload for opaque end-to-end forwarding (the `raw_usage` column /
30
+ * telemetry field).
31
+ *
32
+ * Returns `null` when there is no usage object to surface. For streaming
33
+ * providers that pass `rawResponse` as an accumulated array of chunks,
34
+ * the final element's `usage` is preferred — Anthropic and OpenAI both
35
+ * stamp the complete tally on the terminal chunk, so taking the last
36
+ * element captures the post-completion state without re-aggregating.
37
+ */
38
+ export function extractRawUsage(
39
+ rawResponse: unknown,
40
+ ): Record<string, unknown> | null {
41
+ if (rawResponse == null) return null;
42
+ const candidate = Array.isArray(rawResponse)
43
+ ? rawResponse[rawResponse.length - 1]
44
+ : rawResponse;
45
+ const record = asRecord(candidate);
46
+ return asRecord(record?.usage);
47
+ }
48
+
26
49
  function extractAnthropicCacheCreationFromResponse(
27
50
  response: unknown,
28
51
  ): AnthropicCacheCreationTokenDetails | null {
@@ -42,6 +42,18 @@ export interface UsageEventInput {
42
42
  outputTokens: number;
43
43
  cacheCreationInputTokens: number | null;
44
44
  cacheReadInputTokens: number | null;
45
+ /**
46
+ * The provider's untouched `usage` block (the literal object returned in
47
+ * the API response), preserved as JSON so downstream consumers can
48
+ * extract any provider-specific detail without requiring a schema
49
+ * change. Anthropic nests its TTL breakdown under
50
+ * `cache_creation.ephemeral_{5m,1h}_input_tokens`; OpenAI nests cached
51
+ * read counts under `prompt_tokens_details.cached_tokens`; both shapes
52
+ * are stored as-is. `null` when the provider did not return a usage
53
+ * block and for rows persisted before the
54
+ * `260-llm-usage-add-raw-usage` migration.
55
+ */
56
+ rawUsage: Record<string, unknown> | null;
45
57
  actor: UsageActor;
46
58
  conversationId: string | null;
47
59
  runId: string | null;
@@ -17,7 +17,7 @@ import {
17
17
  getIsContainerized,
18
18
  } from "../config/env-registry.js";
19
19
  import { logSerializers } from "./log-redact.js";
20
- import { getLogPath } from "./platform.js";
20
+ import { getLogsDir } from "./platform.js";
21
21
  import { createSentryLogStream } from "./sentry-log-stream.js";
22
22
 
23
23
  /** Common pino-pretty options that inline [module] into the message prefix. */
@@ -87,7 +87,7 @@ function resolveLogDir(config: LogFileConfig): string | undefined {
87
87
  if (getIsContainerized()) {
88
88
  // Config has a host-specific path that can't be created inside the
89
89
  // container (e.g. /Users/…). Fall back to the default log directory.
90
- const fallback = join(getLogPath(), "..");
90
+ const fallback = getLogsDir();
91
91
  console.warn(
92
92
  `[logger] Configured logFile.dir "${config.dir}" cannot be created ` +
93
93
  `in container (${(err as Error).message}). Falling back to "${fallback}".`,
@@ -210,7 +210,8 @@ function getRootLogger(): pino.Logger {
210
210
  }
211
211
 
212
212
  try {
213
- const logPath = getLogPath();
213
+ const logDir = getLogsDir();
214
+ const logPath = logFilePathForDate(logDir, new Date());
214
215
  // Use sync: true so the fd is opened immediately. This prevents
215
216
  // "sonic boom is not ready yet" errors when commander calls
216
217
  // process.exit(0) for --help/--version before the async fd is ready.
@@ -247,6 +248,10 @@ function getRootLogger(): pino.Logger {
247
248
  fileStream,
248
249
  );
249
250
  }
251
+
252
+ // Register state so ensureCurrentDate() rebuilds across UTC midnight.
253
+ activeLogFileConfig = { dir: logDir, retentionDays: 0 };
254
+ activeLogDate = formatDate(new Date());
250
255
  } catch {
251
256
  rootLogger = pino(
252
257
  {
@@ -274,16 +279,20 @@ export function truncateForLog(value: string, maxLen = 500): string {
274
279
  /**
275
280
  * Returns a lazy logger that only initializes pino when a log method is called.
276
281
  * This avoids "sonic boom is not ready yet" errors when the process exits
277
- * quickly (e.g. `assistant --help`).
282
+ * quickly (e.g. `assistant --help`). The child is rebuilt whenever the
283
+ * underlying root logger changes (e.g. day rollover, late initLogger()).
278
284
  */
279
285
  export function getLogger(name: string): pino.Logger {
286
+ let cachedRoot: pino.Logger | null = null;
280
287
  let child: pino.Logger | null = null;
281
288
  const handler: ProxyHandler<pino.Logger> = {
282
289
  get(_target, prop, receiver) {
283
- if (!child) {
284
- child = getRootLogger().child({ module: name });
290
+ const root = getRootLogger();
291
+ if (root !== cachedRoot) {
292
+ cachedRoot = root;
293
+ child = root.child({ module: name });
285
294
  }
286
- const val = Reflect.get(child, prop, receiver);
295
+ const val = Reflect.get(child!, prop, receiver);
287
296
  if (typeof val === "function") {
288
297
  return val.bind(child);
289
298
  }
@@ -158,8 +158,13 @@ export function getDbPath(): string {
158
158
  return join(getDataDir(), "db", "assistant.db");
159
159
  }
160
160
 
161
- export function getLogPath(): string {
162
- return join(getDataDir(), "logs", "vellum.log");
161
+ /**
162
+ * Returns the directory where logs live: `<dataDir>/logs/`. Files rotate
163
+ * daily (`assistant-YYYY-MM-DD.log`), so callers ask for the directory and
164
+ * let the logger own the filename.
165
+ */
166
+ export function getLogsDir(): string {
167
+ return join(getDataDir(), "logs");
163
168
  }
164
169
 
165
170
  export function getHistoryPath(): string {
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Shared helper for locating a `sqlite3` CLI binary on the host.
3
+ *
4
+ * Used by `memory/db-async-query.ts` so slow statements (`VACUUM`,
5
+ * `PRAGMA optimize`, large bulk deletes) can be shelled out to a
6
+ * subprocess and run without blocking the daemon's main event loop.
7
+ *
8
+ * Resolution order (matches the spirit of `bun-runtime.ts#findBun()`):
9
+ * 1. Common system install locations
10
+ * 2. `Bun.which("sqlite3")` (PATH lookup)
11
+ *
12
+ * Unlike `bun-runtime.ts`, this module does **not** download `sqlite3`
13
+ * when missing. The async path is opt-out (callers fall back to the
14
+ * synchronous in-process `bun:sqlite` connection); if a user wants the
15
+ * non-blocking behavior they install one package.
16
+ *
17
+ * On platform (k8s assistant container) `sqlite3` is installed in the
18
+ * Dockerfile, so the primary path is always available there. On macOS
19
+ * `sqlite3` ships with the OS. On most Linux distros it's available via
20
+ * the system package manager.
21
+ */
22
+
23
+ import { existsSync } from "node:fs";
24
+
25
+ let cachedSqlite3Path: string | undefined | null;
26
+
27
+ /**
28
+ * Synchronous lookup for a usable `sqlite3` CLI binary.
29
+ * Returns the path if found, `undefined` otherwise. Result is cached
30
+ * per-process so the filesystem checks only happen once.
31
+ */
32
+ export function findSqlite3(): string | undefined {
33
+ if (cachedSqlite3Path !== undefined) {
34
+ return cachedSqlite3Path ?? undefined;
35
+ }
36
+
37
+ // 1. Common install locations. We check these before `Bun.which` so we
38
+ // pick a deterministic, predictable binary even when PATH is
39
+ // unusual (e.g. a daemon launched with a stripped env).
40
+ for (const p of [
41
+ "/usr/bin/sqlite3",
42
+ "/usr/local/bin/sqlite3",
43
+ "/opt/homebrew/bin/sqlite3",
44
+ ]) {
45
+ if (existsSync(p)) {
46
+ cachedSqlite3Path = p;
47
+ return p;
48
+ }
49
+ }
50
+
51
+ // 2. PATH lookup.
52
+ const which = Bun.which("sqlite3");
53
+ if (which) {
54
+ cachedSqlite3Path = which;
55
+ return which;
56
+ }
57
+
58
+ cachedSqlite3Path = null;
59
+ return undefined;
60
+ }
61
+
62
+ /** Reset the cached lookup. Test-only. */
63
+ export function _resetSqlite3Cache(): void {
64
+ cachedSqlite3Path = undefined;
65
+ }
@@ -140,6 +140,7 @@ const GEMINI_CATALOG_MODELS = new Set<string>([
140
140
  "gemini-3.1-pro-preview-customtools",
141
141
  "gemini-3-flash-preview",
142
142
  "gemini-3.1-flash-lite-preview",
143
+ "gemini-3.1-flash-lite",
143
144
  "gemini-2.5-flash",
144
145
  "gemini-2.5-flash-lite",
145
146
  "gemini-2.5-pro",
@@ -0,0 +1,86 @@
1
+ import * as fs from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ import { getLogger } from "../../util/logger.js";
5
+ import type { WorkspaceMigration } from "./types.js";
6
+
7
+ const log = getLogger("workspace-migration-089-move-memory-tree-out-of-v3");
8
+
9
+ function isNotFoundError(err: unknown): boolean {
10
+ return (
11
+ typeof err === "object" &&
12
+ err !== null &&
13
+ "code" in err &&
14
+ err.code === "ENOENT"
15
+ );
16
+ }
17
+
18
+ /**
19
+ * Move `<workspace>/memory/<fromRel>` to `<workspace>/memory/<toRel>` when the
20
+ * source exists and the destination does not. Idempotent: a missing source is a
21
+ * no-op (already migrated, or never created), and an existing destination is
22
+ * left untouched (we never clobber). Both directions go through here so `run`
23
+ * and `down` share the same safety checks.
24
+ */
25
+ function moveMemorySubdir(
26
+ workspaceDir: string,
27
+ fromRel: string,
28
+ toRel: string,
29
+ ): void {
30
+ const memoryDir = join(workspaceDir, "memory");
31
+ const src = join(memoryDir, fromRel);
32
+ const dest = join(memoryDir, toRel);
33
+ try {
34
+ if (!fs.existsSync(src)) return;
35
+ if (fs.existsSync(dest)) {
36
+ log.warn(
37
+ { src, dest },
38
+ "Both source and destination tree dirs exist; leaving in place for manual resolution",
39
+ );
40
+ return;
41
+ }
42
+ fs.mkdirSync(dirname(dest), { recursive: true });
43
+ fs.renameSync(src, dest);
44
+ log.info({ src, dest }, "Moved memory tree directory");
45
+ } catch (err) {
46
+ if (isNotFoundError(err)) return;
47
+ log.warn({ err, src, dest }, "Failed to move memory tree directory");
48
+ throw err;
49
+ }
50
+ }
51
+
52
+ /** Remove `<workspace>/memory/v3` if it is now an empty wrapper (the tree was
53
+ * its only child). Best-effort — a non-empty or missing dir is left alone. */
54
+ function removeEmptyV3Wrapper(workspaceDir: string): void {
55
+ const v3Dir = join(workspaceDir, "memory", "v3");
56
+ try {
57
+ if (fs.existsSync(v3Dir) && fs.readdirSync(v3Dir).length === 0) {
58
+ fs.rmdirSync(v3Dir);
59
+ }
60
+ } catch {
61
+ // Non-fatal: leaving an empty memory/v3 wrapper is harmless.
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Relocate the v3 memory tree from `memory/v3/tree` to `memory/tree`.
67
+ *
68
+ * The tree is a DAG overlay over the flat `memory/concepts/` pages and is now a
69
+ * top-level sibling of `concepts/` (matching the storage design), no longer
70
+ * nested under a `v3/` wrapper. `getTreeDir` reads `memory/tree` after this
71
+ * change, so any pre-existing hand-authored tree must move with it.
72
+ */
73
+ export const moveMemoryTreeOutOfV3Migration: WorkspaceMigration = {
74
+ id: "089-move-memory-tree-out-of-v3",
75
+ description: "Relocate the v3 memory tree from memory/v3/tree to memory/tree",
76
+ retryFailedCheckpoint: true,
77
+
78
+ run(workspaceDir: string): void {
79
+ moveMemorySubdir(workspaceDir, join("v3", "tree"), "tree");
80
+ removeEmptyV3Wrapper(workspaceDir);
81
+ },
82
+
83
+ down(workspaceDir: string): void {
84
+ moveMemorySubdir(workspaceDir, "tree", join("v3", "tree"));
85
+ },
86
+ };
@@ -86,6 +86,7 @@ import { memoryV2Bm25BReembedDisabledV2PagesMigration } from "./085-memory-v2-bm
86
86
  import { revertStaleGeminiMisRewritesMigration } from "./086-revert-stale-gemini-mis-rewrites.js";
87
87
  import { memoryRouterBalancedProfileMigration } from "./087-memory-router-balanced-profile.js";
88
88
  import { deprecateBackgroundConversationOverrideMigration } from "./088-deprecate-background-conversation-override.js";
89
+ import { moveMemoryTreeOutOfV3Migration } from "./089-move-memory-tree-out-of-v3.js";
89
90
  import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
90
91
  import type { WorkspaceMigration } from "./types.js";
91
92
 
@@ -183,4 +184,5 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
183
184
  revertStaleGeminiMisRewritesMigration,
184
185
  memoryRouterBalancedProfileMigration,
185
186
  deprecateBackgroundConversationOverrideMigration,
187
+ moveMemoryTreeOutOfV3Migration,
186
188
  ];