@vellumai/assistant 0.7.3 → 0.8.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 (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -1,7 +1,6 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { basename } from "node:path";
3
3
 
4
- import { emitFeedEvent } from "../../../../home/emit-feed-event.js";
5
4
  import {
6
5
  addMessage,
7
6
  getConversation,
@@ -150,14 +149,6 @@ export async function run(
150
149
  ccList.length > 0
151
150
  ? `To: ${toList.join(", ")}; Cc: ${ccList.join(", ")}`
152
151
  : `To: ${toList.join(", ")}`;
153
- void emitFeedEvent({
154
- source: "gmail",
155
- title: "Email Draft Created",
156
- summary: `Drafted reply to ${recipientSummary}.`,
157
- dedupKey: `email-draft:${draft.id}`,
158
- }).catch((err) => {
159
- log.warn({ err }, "Failed to emit email draft feed event");
160
- });
161
152
  return ok(
162
153
  `Gmail draft created with ${attachments.length} attachment(s): ${filenames} (Draft ID: ${draft.id}). ${recipientSummary}. Review in Gmail Drafts, then tell me to send it or send it yourself.`,
163
154
  );
@@ -178,14 +169,6 @@ export async function run(
178
169
  ccList.length > 0
179
170
  ? `To: ${toList.join(", ")}; Cc: ${ccList.join(", ")}`
180
171
  : `To: ${toList.join(", ")}`;
181
- void emitFeedEvent({
182
- source: "gmail",
183
- title: "Email Draft Created",
184
- summary: `Drafted reply to ${recipientSummary}.`,
185
- dedupKey: `email-draft:${draft.id}`,
186
- }).catch((err) => {
187
- log.warn({ err }, "Failed to emit email draft feed event");
188
- });
189
172
  return ok(
190
173
  `Gmail draft created (ID: ${draft.id}). ${recipientSummary}. Review in Gmail Drafts, then tell me to send it or send it yourself.`,
191
174
  );
@@ -212,14 +195,6 @@ export async function run(
212
195
  const draft = await createDraftRaw(gmailConn, raw, threadId);
213
196
 
214
197
  const filenames = attachments.map((a) => a.filename).join(", ");
215
- void emitFeedEvent({
216
- source: "gmail",
217
- title: "Email Draft Created",
218
- summary: "Created an email draft.",
219
- dedupKey: `email-draft:${draft.id}`,
220
- }).catch((err) => {
221
- log.warn({ err }, "Failed to emit email draft feed event");
222
- });
223
198
  return ok(
224
199
  `Gmail draft created with ${attachments.length} attachment(s): ${filenames} (Draft ID: ${draft.id}). Review in Gmail Drafts, then tell me to send it or send it yourself.`,
225
200
  );
@@ -236,14 +211,6 @@ export async function run(
236
211
  undefined,
237
212
  threadId,
238
213
  );
239
- void emitFeedEvent({
240
- source: "gmail",
241
- title: "Email Draft Created",
242
- summary: "Created an email draft.",
243
- dedupKey: `email-draft:${draft.id}`,
244
- }).catch((err) => {
245
- log.warn({ err }, "Failed to emit email draft feed event");
246
- });
247
214
  return ok(
248
215
  `Gmail draft created (ID: ${draft.id}). Review it in your Gmail Drafts, then tell me to send it or send it yourself from Gmail.`,
249
216
  );
@@ -257,31 +224,6 @@ export async function run(
257
224
  assistantId: context.assistantId,
258
225
  });
259
226
 
260
- const sendSummary =
261
- provider.id === "slack"
262
- ? "Sent a Slack message."
263
- : provider.id === "telegram"
264
- ? "Sent a Telegram message."
265
- : "Sent an email.";
266
- void emitFeedEvent({
267
- source:
268
- provider.id === "slack"
269
- ? "slack"
270
- : provider.id === "telegram"
271
- ? "telegram"
272
- : "gmail",
273
- title:
274
- provider.id === "slack"
275
- ? "Slack Message Sent"
276
- : provider.id === "telegram"
277
- ? "Telegram Message Sent"
278
- : "Email Sent",
279
- summary: sendSummary,
280
- dedupKey: `message-sent:${result.id}`,
281
- }).catch((err) => {
282
- log.warn({ err }, "Failed to emit message send feed event");
283
- });
284
-
285
227
  const threadSuffix = result.threadId
286
228
  ? `, "thread_id": "${result.threadId}"`
287
229
  : "";
@@ -49,7 +49,6 @@ import * as computerUseWait from "./bundled-skills/computer-use/tools/computer-u
49
49
  // ── contacts ───────────────────────────────────────────────────────────────────
50
50
  import * as contactMerge from "./bundled-skills/contacts/tools/contact-merge.js";
51
51
  import * as contactSearch from "./bundled-skills/contacts/tools/contact-search.js";
52
- import * as contactUpsert from "./bundled-skills/contacts/tools/contact-upsert.js";
53
52
  import * as googleContacts from "./bundled-skills/contacts/tools/google-contacts.js";
54
53
  // ── document ───────────────────────────────────────────────────────────────────
55
54
  import * as documentCreate from "./bundled-skills/document/tools/document-create.js";
@@ -163,7 +162,6 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
163
162
  ["computer-use:tools/computer-use-respond.ts", computerUseRespond],
164
163
 
165
164
  // contacts
166
- ["contacts:tools/contact-upsert.ts", contactUpsert],
167
165
  ["contacts:tools/contact-search.ts", contactSearch],
168
166
  ["contacts:tools/contact-merge.ts", contactMerge],
169
167
  ["contacts:tools/google-contacts.ts", googleContacts],
@@ -9,6 +9,14 @@
9
9
  "description": "Automatically trigger conversation analysis on the same cadence as memory extraction (batch threshold, idle debounce, end-of-conversation). The analysis agent has full tool access and writes back to memory and skills without user approval.",
10
10
  "defaultEnabled": false
11
11
  },
12
+ {
13
+ "id": "memory-retrospective",
14
+ "scope": "assistant",
15
+ "key": "memory-retrospective",
16
+ "label": "Memory retrospective pass",
17
+ "description": "Run a focused, memory-only retrospective during active conversations and at conversation lifecycle. The retrospective agent re-reads the messages added since the last successful run, dedupes against memory/archive/, and calls `remember` for what wasn't captured in the moment. Enabling this also relaxes the in-conversation pressure to call `remember` (lighter PKB reminder + relaxed tool description) so the assistant can stay present and trust the retrospective as the backstop.",
18
+ "defaultEnabled": false
19
+ },
12
20
  {
13
21
  "id": "user-hosted-enabled",
14
22
  "scope": "client",
@@ -193,6 +201,14 @@
193
201
  "description": "Route embedding requests through the platform runtime proxy using Vellum-managed Gemini credentials when available",
194
202
  "defaultEnabled": false
195
203
  },
204
+ {
205
+ "id": "bookmarks",
206
+ "scope": "client",
207
+ "key": "bookmarks",
208
+ "label": "Message Bookmarks",
209
+ "description": "Show the bookmark icon on messages and enable the Bookmarks tab in Settings",
210
+ "defaultEnabled": false
211
+ },
196
212
  {
197
213
  "id": "fork-from-message",
198
214
  "scope": "client",
@@ -249,14 +265,6 @@
249
265
  "description": "Enable disk pressure protection flows that block background work and remote actors while storage is critically low.",
250
266
  "defaultEnabled": false
251
267
  },
252
- {
253
- "id": "memory-v2-enabled",
254
- "scope": "assistant",
255
- "key": "memory-v2-enabled",
256
- "label": "Memory v2 (concept-page activation model)",
257
- "description": "Enables the v2 memory subsystem: prose concept pages with bidirectional edges, activation-based retrieval, and hourly LLM-driven consolidation. When on, v1 graph extraction/maintenance and PKB filing are suppressed; flipping the flag back off re-engages the full v1 pipeline.",
258
- "defaultEnabled": true
259
- },
260
268
  {
261
269
  "id": "account-deletion",
262
270
  "scope": "client",
@@ -286,15 +294,7 @@
286
294
  "scope": "assistant",
287
295
  "key": "pro-plan-adjust",
288
296
  "label": "Pro Plan Adjust",
289
- "description": "Show the rich Plan card (current plan, features, Manage/Upgrade CTA) at the top of the macOS Settings → Billing tab. The 'Configure Auto Top Ups' CTA is gated separately on `auto-credit-topup`.",
290
- "defaultEnabled": false
291
- },
292
- {
293
- "id": "auto-credit-topup",
294
- "scope": "assistant",
295
- "key": "auto-credit-topup",
296
- "label": "Auto Credit Top-Up",
297
- "description": "Show the 'Configure Auto Top Ups' CTA in the macOS Settings → Billing tab. Mirrors the platform web flag of the same name that gates the auto-reload card and /v1/organizations/billing/auto-top-up/ API.",
297
+ "description": "Show the rich Plan card (current plan, features, Manage/Upgrade CTA) at the top of the macOS Settings → Billing tab.",
298
298
  "defaultEnabled": false
299
299
  }
300
300
  ]
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
 
3
+ import { getCatalogProviderForModel } from "../providers/model-catalog.js";
3
4
  import {
4
5
  type LLMCallSite,
5
6
  LLMConfigBase,
@@ -67,7 +68,7 @@ export function resolveCallSiteConfig(
67
68
  appendCallSiteLayers(layers, callSite, llm, site);
68
69
  }
69
70
 
70
- return finalize(deepMerge(...layers));
71
+ return finalize(deepMerge(...layers.map(withImpliedProviderForKnownModel)));
71
72
  }
72
73
 
73
74
  // ---------------------------------------------------------------------------
@@ -76,6 +77,20 @@ export function resolveCallSiteConfig(
76
77
 
77
78
  type Mergeable = Record<string, unknown>;
78
79
 
80
+ function withImpliedProviderForKnownModel(source: Mergeable): Mergeable {
81
+ if (source.provider !== undefined) return source;
82
+ const model = source.model;
83
+ if (typeof model !== "string" || model.length === 0) return source;
84
+
85
+ const provider = getCatalogProviderForModel(model);
86
+ if (provider === undefined) return source;
87
+
88
+ return {
89
+ ...source,
90
+ provider,
91
+ };
92
+ }
93
+
79
94
  function appendProfileLayer(
80
95
  layers: Mergeable[],
81
96
  profile: ProfileEntry | undefined,
@@ -108,21 +108,22 @@ function cloneDefaultConfig(): AssistantConfig {
108
108
 
109
109
  /**
110
110
  * Returns deployment-context-aware config defaults that override schema
111
- * defaults for platform-managed assistants. Only applied when initializing
112
- * a fresh config (config.json does not yet exist).
111
+ * defaults for platform-managed assistants. Applied to every `loadConfig()`
112
+ * call as a fill-only pass they only fill keys that are absent from the
113
+ * raw config on disk, so an explicit user choice (e.g. saving "your-own"
114
+ * via the macOS Models & Services UI) always wins.
113
115
  *
114
116
  * IS_PLATFORM is set by the Vellum platform launcher for all hosted
115
117
  * assistant deployments. Local, Docker, and bare-metal assistants are
116
118
  * unaffected.
117
119
  */
118
- function getDeploymentContextDefaults(): Record<string, unknown> {
120
+ export function getDeploymentContextDefaults(): Record<string, unknown> {
119
121
  if (process.env.IS_PLATFORM !== "true" && process.env.IS_PLATFORM !== "1") {
120
122
  return {};
121
123
  }
122
124
  const managed = { mode: "managed" as const };
123
125
  return {
124
126
  services: {
125
- inference: managed,
126
127
  "image-generation": managed,
127
128
  "web-search": managed,
128
129
  "google-oauth": managed,
@@ -138,6 +139,49 @@ function getDeploymentContextDefaults(): Record<string, unknown> {
138
139
  };
139
140
  }
140
141
 
142
+ /**
143
+ * Apply `contextDefaults` to `target` for any leaf keys that are absent from
144
+ * `fileConfig` (the raw config-on-disk payload). Mutates `target` in place.
145
+ *
146
+ * "Absent" is checked at the leaf level by walking the `contextDefaults`
147
+ * shape: nested objects recurse so a partial override on disk (e.g.
148
+ * `{services: {inference: {model: "x"}}}` with no explicit `mode`) lets the
149
+ * context default for `mode` win while leaving the user's `model` untouched.
150
+ *
151
+ * Pre-condition: `target` has already been passed through `validateWithSchema`
152
+ * so every nested object in `contextDefaults` has a corresponding object in
153
+ * `target`. The defensive whole-subtree assignment in the `!targetChild`
154
+ * branch only fires for malformed inputs.
155
+ */
156
+ export function fillContextDefaultsForMissingKeys(
157
+ target: Record<string, unknown>,
158
+ fileConfig: Record<string, unknown>,
159
+ contextDefaults: Record<string, unknown>,
160
+ ): void {
161
+ for (const [key, value] of Object.entries(contextDefaults)) {
162
+ const fileVal = fileConfig[key];
163
+ if (
164
+ value !== null &&
165
+ typeof value === "object" &&
166
+ !Array.isArray(value)
167
+ ) {
168
+ const targetChild = readPlainObject(target[key]);
169
+ const fileChild = readPlainObject(fileVal);
170
+ if (targetChild) {
171
+ fillContextDefaultsForMissingKeys(
172
+ targetChild,
173
+ fileChild ?? {},
174
+ value as Record<string, unknown>,
175
+ );
176
+ } else {
177
+ target[key] = structuredClone(value);
178
+ }
179
+ } else if (fileVal === undefined) {
180
+ target[key] = value;
181
+ }
182
+ }
183
+ }
184
+
141
185
  /**
142
186
  * Build a filesystem-safe ISO-8601 timestamp for use in quarantine filenames.
143
187
  * Replaces `:` (invalid on Windows, confusing on macOS Finder) with `-` so the
@@ -475,12 +519,14 @@ export function deepMergeOverwrite(
475
519
  }
476
520
 
477
521
  export type DefaultWorkspaceConfigMergeResult = {
522
+ hadOverlay: boolean;
478
523
  providedLlmProfileNames: Set<string>;
479
524
  providedLlmActiveProfile: boolean;
480
525
  };
481
526
 
482
527
  function emptyDefaultWorkspaceConfigMergeResult(): DefaultWorkspaceConfigMergeResult {
483
528
  return {
529
+ hadOverlay: false,
484
530
  providedLlmProfileNames: new Set(),
485
531
  providedLlmActiveProfile: false,
486
532
  };
@@ -526,6 +572,7 @@ export function mergeDefaultWorkspaceConfig(): DefaultWorkspaceConfigMergeResult
526
572
  );
527
573
  const providedProfiles = readPlainObject(llmDefaults?.profiles);
528
574
  const mergeResult: DefaultWorkspaceConfigMergeResult = {
575
+ hadOverlay: true,
529
576
  providedLlmProfileNames: new Set(
530
577
  providedProfiles ? Object.keys(providedProfiles) : [],
531
578
  ),
@@ -604,7 +651,24 @@ export function loadConfig(): AssistantConfig {
604
651
  let configFileExisted = true;
605
652
  if (existsSync(configPath)) {
606
653
  try {
607
- fileConfig = JSON.parse(readFileSync(configPath, "utf-8"));
654
+ const parsed: unknown = JSON.parse(readFileSync(configPath, "utf-8"));
655
+ if (!isPlainObject(parsed)) {
656
+ // Same shape contract as `loadRawConfig`: top-level value must be a
657
+ // plain object. A `null`, primitive, or array is treated like a
658
+ // parse error so downstream code (`warnAndStripDeprecatedFields`,
659
+ // `setNestedValue` in the managed-Gemini migration block, etc.)
660
+ // never iterates a non-record. Quarantine + fall through to defaults.
661
+ quarantineCorruptConfig(
662
+ configPath,
663
+ new Error(
664
+ `config.json must contain a JSON object at the top level; got ${describeJsonShape(parsed)}`,
665
+ ),
666
+ );
667
+ fileConfig = {};
668
+ configFileExisted = false;
669
+ } else {
670
+ fileConfig = parsed;
671
+ }
608
672
  } catch (err) {
609
673
  // The daemon must never block startup (assistant/CLAUDE.md). A config
610
674
  // file that fails JSON.parse — truncated during a mid-write crash, or
@@ -665,11 +729,31 @@ export function loadConfig(): AssistantConfig {
665
729
  }
666
730
  }
667
731
 
732
+ // Layer deployment-context defaults (e.g. IS_PLATFORM=true → all service
733
+ // modes = "managed") onto the in-memory config for any leaves that aren't
734
+ // explicitly set in `fileConfig`. This runs on every load — not just the
735
+ // first — because the workspace config file is written by upstream
736
+ // lifecycle steps (`mergeDefaultWorkspaceConfig`, `seedInferenceProfiles`)
737
+ // before `loadConfig()` is reached. Gating on `!configFileExisted` would
738
+ // make the context defaults dead code on platform-managed daemons whose
739
+ // config.json was created by those earlier steps without service-mode
740
+ // entries. Explicit user choices on disk are preserved because the helper
741
+ // only fills missing keys.
742
+ const contextDefaults = getDeploymentContextDefaults();
743
+ if (Object.keys(contextDefaults).length > 0) {
744
+ fillContextDefaultsForMissingKeys(
745
+ config as unknown as Record<string, unknown>,
746
+ fileConfig,
747
+ contextDefaults,
748
+ );
749
+ }
750
+
668
751
  // First-launch seed only: when config.json does not exist, write the full
669
- // schema defaults to disk so users can discover and edit all available
670
- // options. When the file already exists, leave it alone disk represents
671
- // user intent, while the in-memory `cached: AssistantConfig` (above) has
672
- // all schema defaults applied via `applyNestedDefaults`/`validateWithSchema`,
752
+ // schema defaults (with any deployment-context overrides already applied
753
+ // above) to disk so users can discover and edit all available options.
754
+ // When the file already exists, leave it alone disk represents user
755
+ // intent, while the in-memory `cached: AssistantConfig` (above) has all
756
+ // schema defaults applied via `applyNestedDefaults`/`validateWithSchema`,
673
757
  // so consumers calling `getConfig().memory.v2.bm25_b` continue to receive
674
758
  // the schema default whenever the field is absent on disk.
675
759
  //
@@ -687,18 +771,6 @@ export function loadConfig(): AssistantConfig {
687
771
  }
688
772
  // Strip dataDir (runtime-derived) from the persisted config
689
773
  const { dataDir: _, ...persistable } = config;
690
-
691
- // Layer deployment context defaults on top of schema defaults.
692
- // These are overrides the daemon derives from its environment (e.g.
693
- // IS_PLATFORM → all service modes = "managed"). Schema defaults
694
- // remain the fallback for non-platform deployments.
695
- const contextDefaults = getDeploymentContextDefaults();
696
- if (Object.keys(contextDefaults).length > 0) {
697
- deepMergeOverwrite(
698
- persistable as Record<string, unknown>,
699
- contextDefaults,
700
- );
701
- }
702
774
  writeFileSync(configPath, JSON.stringify(persistable, null, 2) + "\n");
703
775
  log.info("Wrote default config to %s", configPath);
704
776
  } catch (err) {
@@ -774,24 +846,67 @@ export function invalidateConfigCache(): void {
774
846
  * Load the raw config from disk without any secure-storage merging.
775
847
  * Used by CLI config commands to read/write the file directly.
776
848
  * API keys in secure storage are managed via `assistant keys` commands.
849
+ *
850
+ * Contract: returns a plain object (`Record<string, unknown>`). When
851
+ * `config.json` is missing → returns `{}`. When the file is unparseable
852
+ * (truncated, hand-edited to invalid JSON) OR when it parses to a value
853
+ * that is technically valid JSON but NOT a plain object (`null`, a
854
+ * primitive like `42`, `"hello"`, `true`, or an array `[…]`) → quarantines
855
+ * the file and returns `{}`. Callers can therefore rely on the return
856
+ * type without runtime shape-checking — the boundary check happens here.
777
857
  */
778
858
  export function loadRawConfig(): Record<string, unknown> {
779
859
  ensureMigratedDataDir();
780
860
  const configPath = getConfigPath();
781
- let raw: Record<string, unknown> = {};
782
- if (existsSync(configPath)) {
783
- try {
784
- raw = JSON.parse(readFileSync(configPath, "utf-8"));
785
- } catch (err) {
786
- // Mirror loadConfig(): quarantine the corrupt file and return an empty
787
- // object rather than throwing. This prevents /v1/config from surfacing
788
- // a 500 when the user's config.json is malformed.
789
- quarantineCorruptConfig(configPath, err);
790
- raw = {};
791
- }
861
+ if (!existsSync(configPath)) {
862
+ return {};
792
863
  }
793
864
 
794
- return raw;
865
+ let parsed: unknown;
866
+ try {
867
+ parsed = JSON.parse(readFileSync(configPath, "utf-8"));
868
+ } catch (err) {
869
+ // Mirror loadConfig(): quarantine the corrupt file and return an empty
870
+ // object rather than throwing. This prevents /v1/config from surfacing
871
+ // a 500 when the user's config.json is malformed.
872
+ quarantineCorruptConfig(configPath, err);
873
+ return {};
874
+ }
875
+
876
+ if (!isPlainObject(parsed)) {
877
+ // Valid JSON but the wrong shape — `null`, a primitive, or an array.
878
+ // Treat the same as a parse error so the return-type contract above is
879
+ // truthful and downstream callers (e.g. /v1/config handlers, twilio
880
+ // integration routes, settings routes) can iterate keys safely.
881
+ quarantineCorruptConfig(
882
+ configPath,
883
+ new Error(
884
+ `config.json must contain a JSON object at the top level; got ${describeJsonShape(parsed)}`,
885
+ ),
886
+ );
887
+ return {};
888
+ }
889
+
890
+ return parsed;
891
+ }
892
+
893
+ /**
894
+ * Predicate for "the value is a plain JSON object" — i.e. not `null`, not
895
+ * a primitive, and not an array. The cast on the truthy branch is safe
896
+ * because the caller's static type narrowed accordingly.
897
+ */
898
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
899
+ return value !== null && typeof value === "object" && !Array.isArray(value);
900
+ }
901
+
902
+ /**
903
+ * Human-readable shape label for error messages. Distinguishes the four
904
+ * non-object JSON shapes the loader rejects.
905
+ */
906
+ function describeJsonShape(value: unknown): string {
907
+ if (value === null) return "null";
908
+ if (Array.isArray(value)) return "an array";
909
+ return `a ${typeof value}`;
795
910
  }
796
911
 
797
912
  export function saveRawConfig(config: Record<string, unknown>): void {
@@ -1,39 +1,11 @@
1
- /**
2
- * Safely set a nested field on a raw config object's `llm.default` map.
3
- *
4
- * Ensures the `llm` and `llm.default` objects exist before writing, so
5
- * callers don't need to guard against undefined intermediate keys.
6
- *
7
- * Example: `setLlmDefaultField(raw, "model", "claude-sonnet-4-6")`
8
- * produces `raw.llm.default.model = "claude-sonnet-4-6"`.
9
- */
10
- export function setLlmDefaultField(
11
- raw: Record<string, unknown>,
12
- field: string,
13
- value: unknown,
14
- ): void {
15
- const llm: Record<string, unknown> =
16
- raw.llm != null && typeof raw.llm === "object" && !Array.isArray(raw.llm)
17
- ? (raw.llm as Record<string, unknown>)
18
- : {};
19
- const existing = llm.default;
20
- const defaultBlock: Record<string, unknown> =
21
- existing != null && typeof existing === "object" && !Array.isArray(existing)
22
- ? (existing as Record<string, unknown>)
23
- : {};
24
- defaultBlock[field] = value;
25
- llm.default = defaultBlock;
26
- raw.llm = llm;
27
- }
28
-
29
1
  /**
30
2
  * Safely set a nested field on a raw config object's `services` map.
31
3
  *
32
4
  * Ensures the `services` and service-level objects exist before writing,
33
5
  * so callers don't need to guard against undefined intermediate keys.
34
6
  *
35
- * Example: `setServiceField(raw, "inference", "mode", "managed")`
36
- * produces `raw.services.inference.mode = "managed"`.
7
+ * Example: `setServiceField(raw, "image-generation", "mode", "managed")`
8
+ * produces `raw.services["image-generation"].mode = "managed"`.
37
9
  */
38
10
  export function setServiceField(
39
11
  raw: Record<string, unknown>,
@@ -32,6 +32,7 @@ import { HostBrowserConfigSchema } from "./schemas/host-browser.js";
32
32
  import { IngressConfigSchema } from "./schemas/ingress.js";
33
33
  import { JournalConfigSchema } from "./schemas/journal.js";
34
34
  import { LLMSchema } from "./schemas/llm.js";
35
+ import { LlmRequestLogsConfigSchema } from "./schemas/llm-request-logs.js";
35
36
  import {
36
37
  AuditLogConfigSchema,
37
38
  LogFileConfigSchema,
@@ -81,6 +82,9 @@ export const AssistantConfigSchema = z
81
82
  // ensures the loader's leaf-deletion recovery path can repair a partially
82
83
  // invalid `llm` block without falling back to `cloneDefaultConfig()`.
83
84
  llm: LLMSchema.default(LLMSchema.parse({})),
85
+ llmRequestLogs: LlmRequestLogsConfigSchema.default(
86
+ LlmRequestLogsConfigSchema.parse({}),
87
+ ),
84
88
  filing: FilingConfigSchema.default(FilingConfigSchema.parse({})),
85
89
  heartbeat: HeartbeatConfigSchema.default(HeartbeatConfigSchema.parse({})),
86
90
  updates: UpdatesConfigSchema.default(UpdatesConfigSchema.parse({})),
@@ -32,6 +32,11 @@ describe("MemoryV2ConfigSchema", () => {
32
32
  model: "Alibaba-NLP/gte-reranker-modernbert-base",
33
33
  dtype: "q8",
34
34
  },
35
+ router: {
36
+ enabled: false,
37
+ max_page_ids: 25,
38
+ router_prompt_path: null,
39
+ },
35
40
  });
36
41
  });
37
42
 
@@ -155,6 +160,50 @@ describe("MemoryV2ConfigSchema", () => {
155
160
  expect(() => MemoryV2ConfigSchema.parse({ epsilon: -0.01 })).toThrow();
156
161
  expect(() => MemoryV2ConfigSchema.parse({ epsilon: 1.5 })).toThrow();
157
162
  });
163
+
164
+ test("router defaults to disabled with max_page_ids=25", () => {
165
+ const parsed = MemoryV2ConfigSchema.parse({});
166
+ expect(parsed.router.enabled).toBe(false);
167
+ expect(parsed.router.max_page_ids).toBe(25);
168
+ });
169
+
170
+ test("accepts explicit router overrides", () => {
171
+ const parsed = MemoryV2ConfigSchema.parse({
172
+ router: { enabled: true, max_page_ids: 50 },
173
+ });
174
+ expect(parsed.router.enabled).toBe(true);
175
+ expect(parsed.router.max_page_ids).toBe(50);
176
+ });
177
+
178
+ test("rejects router.max_page_ids below 1", () => {
179
+ expect(() =>
180
+ MemoryV2ConfigSchema.parse({ router: { max_page_ids: 0 } }),
181
+ ).toThrow();
182
+ });
183
+
184
+ test("rejects router.max_page_ids above 100", () => {
185
+ expect(() =>
186
+ MemoryV2ConfigSchema.parse({ router: { max_page_ids: 101 } }),
187
+ ).toThrow();
188
+ });
189
+
190
+ test("router_prompt_path defaults to null", () => {
191
+ const parsed = MemoryV2ConfigSchema.parse({});
192
+ expect(parsed.router.router_prompt_path).toBeNull();
193
+ });
194
+
195
+ test("accepts an explicit router_prompt_path override", () => {
196
+ const parsed = MemoryV2ConfigSchema.parse({
197
+ router: { router_prompt_path: "~/prompts/router.md" },
198
+ });
199
+ expect(parsed.router.router_prompt_path).toBe("~/prompts/router.md");
200
+ });
201
+
202
+ test("rejects non-string router_prompt_path", () => {
203
+ expect(() =>
204
+ MemoryV2ConfigSchema.parse({ router: { router_prompt_path: 42 } }),
205
+ ).toThrow();
206
+ });
158
207
  });
159
208
 
160
209
  describe("MemoryConfigSchema integration with v2 block", () => {
@@ -114,6 +114,27 @@ const CATALOG_RECORD: CatalogRecord = {
114
114
  description: "Background sweep pass for V2 memory maintenance.",
115
115
  domain: "memory",
116
116
  },
117
+ memoryRouter: {
118
+ id: "memoryRouter",
119
+ displayName: "Memory Router",
120
+ description:
121
+ "Selects which concept pages to inject for the next agent turn by routing over a cached page index.",
122
+ domain: "memory",
123
+ },
124
+ memoryV2Consolidation: {
125
+ id: "memoryV2Consolidation",
126
+ displayName: "Memory V2 Consolidation",
127
+ description:
128
+ "Routes accumulated buffer entries into concept pages and rewrites the recent summary during V2 memory maintenance.",
129
+ domain: "memory",
130
+ },
131
+ memoryRetrospective: {
132
+ id: "memoryRetrospective",
133
+ displayName: "Memory Retrospective",
134
+ description:
135
+ "Background agent that re-reads recent conversation messages and saves what wasn't captured in the moment by calling the `remember` tool.",
136
+ domain: "memory",
137
+ },
117
138
  recall: {
118
139
  id: "recall",
119
140
  displayName: "Recall",
@@ -152,7 +173,14 @@ const CATALOG_RECORD: CatalogRecord = {
152
173
  id: "conversationStarters",
153
174
  displayName: "Conversation Starters",
154
175
  description:
155
- "Generates suggested conversation openers for the home screen.",
176
+ "Generates the personalized starter chips on the empty conversation page.",
177
+ domain: "ui",
178
+ },
179
+ replySuggestion: {
180
+ id: "replySuggestion",
181
+ displayName: "Reply Suggestion",
182
+ description:
183
+ "Generates the tab-to-accept reply hint shown in the chat composer after each assistant turn.",
156
184
  domain: "ui",
157
185
  },
158
186
  conversationTitle: {
@@ -191,12 +219,6 @@ const CATALOG_RECORD: CatalogRecord = {
191
219
  description: "Handles conversational approval flows.",
192
220
  domain: "ui",
193
221
  },
194
- feedEventCopy: {
195
- id: "feedEventCopy",
196
- displayName: "Feed Event Copy",
197
- description: "Generates copy for home feed event cards.",
198
- domain: "ui",
199
- },
200
222
  trustRuleSuggestion: {
201
223
  id: "trustRuleSuggestion",
202
224
  displayName: "Trust Rule Suggestion",