@vellumai/assistant 0.8.0 → 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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -17,13 +17,20 @@
17
17
  // channel separately and fuses with the configured `dense_weight` /
18
18
  // `sparse_weight` (which the schema validates sum to 1.0).
19
19
  //
20
- // Sparse normalization:
21
- // Dense cosine similarity is already in [0, 1]. Qdrant's sparse score is
22
- // on a different, unbounded scale (it depends on query and document term
23
- // weights), so we divide by the per-batch maximum sparse score to bring
24
- // it into [0, 1] before fusing. This is the design doc's choice (§4) —
25
- // batch-relative normalization is sufficient because the score is consumed
26
- // only as a per-turn ordering signal, not compared across turns.
20
+ // Score normalization:
21
+ // Qdrant returns cosine similarity in [-1, 1]. We clamp negative cosines
22
+ // to 0 before fusion so anti-correlated documents contribute zero, rather
23
+ // than a negative term that subtracts from the sparse channel and can
24
+ // depress the fused score below the sparse-only floor. Positive cosines
25
+ // pass through unchanged affine-rescaling them into [0, 1] via
26
+ // `(cos + 1) / 2` would halve every pairwise dense difference and shift
27
+ // ranking toward the sparse channel, the opposite of intent. Qdrant's
28
+ // sparse score is on a different, unbounded scale (it depends on query
29
+ // and document term weights), so we divide by the per-batch maximum
30
+ // sparse score to bring it into [0, 1] before fusing. This is the design
31
+ // doc's choice (§4) — batch-relative normalization is sufficient because
32
+ // the score is consumed only as a per-turn ordering signal, not compared
33
+ // across turns.
27
34
 
28
35
  import type { AssistantConfig } from "../../config/types.js";
29
36
  import { applyCorrectionIfCalibrated } from "../anisotropy.js";
@@ -264,11 +271,17 @@ function computeMaxSparse<T>(
264
271
 
265
272
  /**
266
273
  * Fuse one half of a hit (body or summary) into a normalized [0, 1] score
267
- * via `clamp01(dense_weight · dense + sparse_weight · sparse/maxSparse)`.
268
- * Returns `undefined` when neither channel hit a signal the half had no
269
- * match at all, so the caller can fall back to the other half cleanly.
274
+ * via `clamp01(dense_weight · max(0, cosine) + sparse_weight ·
275
+ * sparse/maxSparse)`. Negative cosines clamp to 0 so they don't subtract
276
+ * from sparse; positive cosines pass through unchanged so the
277
+ * operator-configured dense/sparse balance is preserved. Returns
278
+ * `undefined` when neither channel hit — a signal the half had no match
279
+ * at all, so the caller can fall back to the other half cleanly.
280
+ *
281
+ * Exported so the context-search adapter can reuse the same fusion math
282
+ * for its own activation pipeline.
270
283
  */
271
- function fuseHalf(
284
+ export function fuseHalf(
272
285
  denseScore: number | undefined,
273
286
  sparseScore: number | undefined,
274
287
  maxSparse: number,
@@ -276,7 +289,7 @@ function fuseHalf(
276
289
  sparseWeight: number,
277
290
  ): number | undefined {
278
291
  if (denseScore === undefined && sparseScore === undefined) return undefined;
279
- const dense = denseScore ?? 0;
292
+ const dense = denseScore !== undefined ? Math.max(0, denseScore) : 0;
280
293
  const sparseNormalized =
281
294
  sparseScore !== undefined && maxSparse > 0 ? sparseScore / maxSparse : 0;
282
295
  return clamp01(denseWeight * dense + sparseWeight * sparseNormalized);
@@ -34,6 +34,7 @@ import {
34
34
  embedWithBackend,
35
35
  generateSparseEmbedding,
36
36
  } from "../embedding-backend.js";
37
+ import { invalidatePageIndex } from "./page-index.js";
37
38
  import {
38
39
  pruneSlugsWithPrefixExcept,
39
40
  upsertConceptPageEmbedding,
@@ -42,6 +43,10 @@ import {
42
43
  augmentMcpSetupDescription,
43
44
  buildSkillContent,
44
45
  } from "./skill-content.js";
46
+ import {
47
+ generateBm25DocEmbedding,
48
+ getConceptPageCorpusStats,
49
+ } from "./sparse-bm25.js";
45
50
  import type { SkillEntry } from "./types.js";
46
51
 
47
52
  const log = getLogger("memory-v2-skill-store");
@@ -54,6 +59,14 @@ const log = getLogger("memory-v2-skill-store");
54
59
  */
55
60
  export const SKILL_SLUG_PREFIX = "skills/";
56
61
 
62
+ /**
63
+ * Payload discriminator written on every skill-seeded Qdrant point. Keeps
64
+ * skill rows distinguishable from user-authored concept pages that happen to
65
+ * be slugged under `skills/...`, so prefix pruning never deletes a hand-
66
+ * authored page sitting in the same namespace.
67
+ */
68
+ const SKILL_PAYLOAD_KIND = "skill";
69
+
57
70
  /** Compose the unified-collection slug for a skill id. */
58
71
  export function skillSlugFor(id: string): string {
59
72
  return `${SKILL_SLUG_PREFIX}${id}`;
@@ -68,10 +81,39 @@ let entries: Map<string, SkillEntry> | null = null;
68
81
 
69
82
  /**
70
83
  * Seed (or re-seed) skill embeddings into the unified concept-page collection.
71
- * Idempotent: safe to call repeatedly. Best-effort: never throws any
72
- * failure leaves the prior `entries` cache in place and logs a warning.
84
+ * Idempotent. Defaults to best-effort (errors are logged but swallowed) for
85
+ * background callers like daemon startup; pass `{ throwOnError: true }` from
86
+ * synchronous CLI-driven paths that need to surface failures to the operator.
73
87
  *
74
- * Steps:
88
+ * Single-flight + coalesced: at most one seed runs at a time, and concurrent
89
+ * callers are coalesced into one follow-up re-snapshot that runs after the
90
+ * in-flight seed completes. Without this, an older snapshot can finish after
91
+ * a newer one and overwrite the newer skill state. Strict callers observe
92
+ * the most recent run's outcome via `lastSeedError`.
93
+ */
94
+ let seedTail: Promise<void> = Promise.resolve();
95
+ let seedPending: Promise<void> | null = null;
96
+ let lastSeedError: unknown = null;
97
+
98
+ export async function seedV2SkillEntries(
99
+ opts: { throwOnError?: boolean } = {},
100
+ ): Promise<void> {
101
+ if (!seedPending) {
102
+ const next = seedTail.then(async () => {
103
+ seedPending = null;
104
+ await runSeedOnce();
105
+ });
106
+ seedTail = next.catch(() => {});
107
+ seedPending = next;
108
+ }
109
+ await seedPending;
110
+ if (opts.throwOnError && lastSeedError) {
111
+ throw lastSeedError;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Steps (per run):
75
117
  * 1. Enumerate the local skill catalog and resolve each skill's enabled
76
118
  * state (`resolveSkillStates`).
77
119
  * 2. Build a `SkillEntry` per enabled skill, applying the mcp-setup
@@ -90,7 +132,7 @@ let entries: Map<string, SkillEntry> | null = null;
90
132
  * stale points from prior catalog state (e.g. uninstalled skills).
91
133
  * 7. Replace the module-level `entries` cache with the freshly built map.
92
134
  */
93
- export async function seedV2SkillEntries(): Promise<void> {
135
+ async function runSeedOnce(): Promise<void> {
94
136
  try {
95
137
  const config = getConfig();
96
138
  const catalog = loadSkillCatalog();
@@ -137,32 +179,53 @@ export async function seedV2SkillEntries(): Promise<void> {
137
179
  );
138
180
  }
139
181
 
140
- // Embed all content strings in one batched call. Sparse vectors are
141
- // computed in-process (no network).
142
- const embedded = await embedWithBackend(
143
- config,
144
- seeds.map((s) => s.content),
145
- );
146
- const denseVectors = await Promise.all(
147
- embedded.vectors.map((v) =>
148
- applyCorrectionIfCalibrated(v, embedded.provider, embedded.model),
149
- ),
150
- );
151
-
152
- const now = Date.now();
182
+ // Embed all content strings in one batched call when there is anything to
183
+ // embed. Skipping the call when `seeds` is empty avoids throwing on an
184
+ // unavailable embedding backend in the all-disabled case, so pruning and
185
+ // cache replacement still run and clear stale state.
153
186
  const nextEntries = new Map<string, SkillEntry>();
154
- await Promise.all(
155
- seeds.map((seed, i) =>
156
- upsertConceptPageEmbedding({
157
- slug: skillSlugFor(seed.id),
158
- dense: denseVectors[i],
159
- sparse: generateSparseEmbedding(seed.content),
160
- updatedAt: now,
161
- }),
162
- ),
163
- );
164
- for (const seed of seeds) {
165
- nextEntries.set(seed.id, seed);
187
+ if (seeds.length > 0) {
188
+ const embedded = await embedWithBackend(
189
+ config,
190
+ seeds.map((s) => s.content),
191
+ );
192
+ const denseVectors = await Promise.all(
193
+ embedded.vectors.map((v) =>
194
+ applyCorrectionIfCalibrated(v, embedded.provider, embedded.model),
195
+ ),
196
+ );
197
+
198
+ // Skills share the concept-page Qdrant collection, so the sparse vector
199
+ // must use the same stemmed BM25 encoding the concept-page documents
200
+ // carry — otherwise the stemmed BM25 query vectors used by callers (see
201
+ // `simBatch`, `activation.selectCandidates`, recall) hash to different
202
+ // buckets than the stored skill vectors and skip the sparse channel
203
+ // entirely. Fall back to the legacy TF encoder only during the cold-start
204
+ // window before corpus stats finish building.
205
+ const corpusStats = getConceptPageCorpusStats();
206
+ const encodeSparse = (input: string) =>
207
+ corpusStats
208
+ ? generateBm25DocEmbedding(input, corpusStats, {
209
+ k1: config.memory.v2.bm25_k1,
210
+ b: config.memory.v2.bm25_b,
211
+ })
212
+ : generateSparseEmbedding(input);
213
+
214
+ const now = Date.now();
215
+ await Promise.all(
216
+ seeds.map((seed, i) =>
217
+ upsertConceptPageEmbedding({
218
+ slug: skillSlugFor(seed.id),
219
+ dense: denseVectors[i],
220
+ sparse: encodeSparse(seed.content),
221
+ updatedAt: now,
222
+ kind: SKILL_PAYLOAD_KIND,
223
+ }),
224
+ ),
225
+ );
226
+ for (const seed of seeds) {
227
+ nextEntries.set(seed.id, seed);
228
+ }
166
229
  }
167
230
 
168
231
  // Prune stale skill slugs. When the catalog is unavailable (empty array
@@ -173,6 +236,7 @@ export async function seedV2SkillEntries(): Promise<void> {
173
236
  await pruneSlugsWithPrefixExcept(
174
237
  SKILL_SLUG_PREFIX,
175
238
  seeds.map((s) => s.id),
239
+ { kind: SKILL_PAYLOAD_KIND },
176
240
  );
177
241
  } else {
178
242
  log.info(
@@ -182,7 +246,13 @@ export async function seedV2SkillEntries(): Promise<void> {
182
246
 
183
247
  // Atomically replace the cache only after every step above succeeds.
184
248
  entries = nextEntries;
249
+ // Drop the page-index cache so the next router invocation observes the
250
+ // freshly seeded skill set (skill entries share the unified concept-page
251
+ // collection and surface in the same index).
252
+ invalidatePageIndex();
253
+ lastSeedError = null;
185
254
  } catch (err) {
255
+ lastSeedError = err;
186
256
  log.warn({ err }, "Failed to seed v2 skill entries");
187
257
  }
188
258
  }
@@ -208,7 +278,26 @@ export function isSkillSlug(slug: string): boolean {
208
278
  return slug.startsWith(SKILL_SLUG_PREFIX);
209
279
  }
210
280
 
281
+ /**
282
+ * Snapshot of the in-process skill cache, sorted by skill id (ASCII order)
283
+ * for determinism. Returns a freshly allocated array on each call so callers
284
+ * cannot mutate the underlying cache.
285
+ *
286
+ * The cache is replaced atomically by `seedV2SkillEntries`, so a snapshot
287
+ * may be stale once a subsequent seed run completes. Callers that need
288
+ * up-to-the-moment state must re-call this after awaiting the seed.
289
+ */
290
+ export function listSkillEntries(): SkillEntry[] {
291
+ if (!entries) return [];
292
+ return [...entries.values()].sort((a, b) =>
293
+ a.id < b.id ? -1 : a.id > b.id ? 1 : 0,
294
+ );
295
+ }
296
+
211
297
  /** @internal Test-only: clear the module-level cache. */
212
298
  export function _resetSkillStoreForTests(): void {
213
299
  entries = null;
300
+ seedTail = Promise.resolve();
301
+ seedPending = null;
302
+ lastSeedError = null;
214
303
  }
@@ -60,19 +60,26 @@ export function readMemoryV2StaticContent(): string | null {
60
60
  }
61
61
 
62
62
  /**
63
- * Static memory holds the user's aggregate personal pages
64
- * (essentials/threads/recent/buffer). Block injection when a non-guardian
65
- * actor reaches the assistant over a remote channel otherwise the model
66
- * can be prompt-injected into reciting private memory. Internal flows
67
- * (`sourceChannel: "vellum"`) and turns with no trust context pass through
68
- * unchanged; this gate exists only to keep remote untrusted actors out.
63
+ * Trust-class predicate for personal-memory injection. Personal memory
64
+ * spans v2 static blocks (essentials/threads/recent/buffer), the PKB
65
+ * context, and NOW.md all of which can hold private user content. Block
66
+ * injection when a non-guardian actor reaches the assistant over a remote
67
+ * channel otherwise the model can be prompt-injected into reciting
68
+ * private memory. Internal flows (`sourceChannel: "vellum"`) and turns
69
+ * with no trust context pass through unchanged; this gate exists only to
70
+ * keep remote untrusted actors out.
71
+ *
72
+ * This is the trust-only gate. Cadence (first-turn / post-compaction) is
73
+ * applied separately by the caller so that the freshest content remains
74
+ * available for re-injection after a mid-turn reducer-triggered compaction
75
+ * — the initial-injection turn may not have been a `shouldInjectNowAndPkb`
76
+ * turn, but compaction strips the existing personal-memory blocks and we
77
+ * still need the freshest content to re-inject.
69
78
  */
70
- export function shouldLoadMemoryV2Static(args: {
71
- shouldInjectNowAndPkb: boolean;
79
+ export function shouldExposePersonalMemory(args: {
72
80
  sourceChannel: ChannelId | undefined;
73
81
  isTrustedActor: boolean;
74
82
  }): boolean {
75
- if (!args.shouldInjectNowAndPkb) return false;
76
83
  const isRemoteUntrustedActor =
77
84
  args.sourceChannel !== undefined &&
78
85
  args.sourceChannel !== "vellum" &&
@@ -22,11 +22,15 @@
22
22
  import { readFileSync } from "node:fs";
23
23
  import { join } from "node:path";
24
24
 
25
- import { desc, gt } from "drizzle-orm";
25
+ import { and, desc, eq, gt, notInArray } from "drizzle-orm";
26
26
  import { z } from "zod";
27
27
 
28
28
  import type { AssistantConfig } from "../../config/types.js";
29
- import { getAssistantName } from "../../daemon/identity-helpers.js";
29
+ import {
30
+ getAssistantName,
31
+ resolveUserName,
32
+ } from "../../daemon/identity-helpers.js";
33
+ import { emitNotificationSignal } from "../../notifications/emit-signal.js";
30
34
  import {
31
35
  extractToolUse,
32
36
  getConfiguredProvider,
@@ -41,11 +45,15 @@ import {
41
45
  formatRememberEntry,
42
46
  } from "../graph/tool-handlers.js";
43
47
  import type { MemoryJob } from "../jobs-store.js";
44
- import { messages } from "../schema.js";
48
+ import { stringifyMessageContent } from "../message-content.js";
49
+ import { conversations, messages } from "../schema.js";
45
50
  import { renderSweepPrompt } from "./prompts/sweep.js";
46
51
 
47
52
  const log = getLogger("memory-v2-sweep");
48
53
 
54
+ /** Stable job identifier surfaced in `activity.failed` notifications. */
55
+ const JOB_NAME = "memory.v2.sweep";
56
+
49
57
  /** Window of conversation history the sweep inspects on each run. */
50
58
  const RECENT_MESSAGES_WINDOW_MS = 30 * 60 * 1000;
51
59
 
@@ -100,7 +108,7 @@ const SweepResultSchema = z.object({
100
108
  * progress without inspecting the filesystem.
101
109
  */
102
110
  export async function memoryV2SweepJob(
103
- _job: MemoryJob,
111
+ job: MemoryJob,
104
112
  config: AssistantConfig,
105
113
  ): Promise<number> {
106
114
  if (!config.memory?.v2?.enabled) {
@@ -115,59 +123,116 @@ export async function memoryV2SweepJob(
115
123
 
116
124
  const workspaceDir = getWorkspaceDir();
117
125
  const memoryDir = join(workspaceDir, "memory");
118
- const recentText = loadRecentMessagesText(Date.now());
119
- if (!recentText) {
120
- log.debug("No recent messages in window; sweep skipped");
121
- return 0;
122
- }
123
126
 
124
- const existingBuffer = readBufferText(memoryDir);
127
+ // Once we're committed to running (past the flag/feature gates), any
128
+ // unexpected error is surfaced via an `activity.failed` notification —
129
+ // mirrors v1 filing's post-migration treatment, but hand-rolled because
130
+ // the sweep makes a single forced-tool `provider.sendMessage` call rather
131
+ // than driving a conversation through `runBackgroundJob`. The function
132
+ // continues to return 0 on caught failures (preserving the existing
133
+ // silent-failure contract); only the notification side-effect is new.
134
+ try {
135
+ const recentText = loadRecentMessagesText(Date.now());
136
+ if (!recentText) {
137
+ log.debug("No recent messages in window; sweep skipped");
138
+ return 0;
139
+ }
140
+
141
+ const existingBuffer = readBufferText(memoryDir);
125
142
 
126
- const provider = await getConfiguredProvider("memoryV2Sweep");
127
- if (!provider) {
128
- log.warn("memoryV2Sweep provider unavailable; sweep skipped");
129
- return 0;
130
- }
143
+ const provider = await getConfiguredProvider("memoryV2Sweep");
144
+ if (!provider) {
145
+ log.warn("memoryV2Sweep provider unavailable; sweep skipped");
146
+ return 0;
147
+ }
131
148
 
132
- const systemPrompt = renderSweepPrompt({
133
- assistantName: getAssistantName(),
134
- userName: resolveUserName(workspaceDir),
135
- });
136
- const userText =
137
- `## existingBuffer\n\n${existingBuffer || "(empty)"}\n\n` +
138
- `## recentMessages\n\n${recentText}`;
149
+ const systemPrompt = renderSweepPrompt({
150
+ assistantName: getAssistantName(),
151
+ userName: resolveUserName(workspaceDir),
152
+ });
153
+ const userText =
154
+ `## existingBuffer\n\n${existingBuffer || "(empty)"}\n\n` +
155
+ `## recentMessages\n\n${recentText}`;
139
156
 
140
- const response = await provider.sendMessage(
141
- [userMessage(userText)],
142
- [SWEEP_TOOL],
143
- systemPrompt,
144
- {
145
- config: {
146
- callSite: "memoryV2Sweep" as const,
147
- tool_choice: { type: "tool" as const, name: SWEEP_TOOL_NAME },
157
+ const response = await provider.sendMessage(
158
+ [userMessage(userText)],
159
+ [SWEEP_TOOL],
160
+ systemPrompt,
161
+ {
162
+ config: {
163
+ callSite: "memoryV2Sweep" as const,
164
+ tool_choice: { type: "tool" as const, name: SWEEP_TOOL_NAME },
165
+ },
148
166
  },
149
- },
150
- );
167
+ );
168
+
169
+ const toolBlock = extractToolUse(response);
170
+ if (!toolBlock || toolBlock.name !== SWEEP_TOOL_NAME) {
171
+ log.debug("Sweep model returned no tool_use block");
172
+ return 0;
173
+ }
174
+ const parsed = SweepResultSchema.safeParse(toolBlock.input);
175
+ if (!parsed.success) {
176
+ log.warn(
177
+ { error: parsed.error.message },
178
+ "Sweep tool input did not match schema",
179
+ );
180
+ return 0;
181
+ }
151
182
 
152
- const toolBlock = extractToolUse(response);
153
- if (!toolBlock || toolBlock.name !== SWEEP_TOOL_NAME) {
154
- log.debug("Sweep model returned no tool_use block");
183
+ const written = appendEntries(memoryDir, parsed.data.entries);
184
+ if (written > 0) {
185
+ log.info({ written }, "Memory v2 sweep wrote new buffer entries");
186
+ }
187
+ return written;
188
+ } catch (err) {
189
+ const errorMessage = err instanceof Error ? err.message : String(err);
190
+ log.error({ err }, "memory v2 sweep failed");
191
+ emitSweepActivityFailed({
192
+ jobId: job.id,
193
+ errorMessage,
194
+ });
155
195
  return 0;
156
196
  }
157
- const parsed = SweepResultSchema.safeParse(toolBlock.input);
158
- if (!parsed.success) {
197
+ }
198
+
199
+ /**
200
+ * Emit an `activity.failed` notification for a failed sweep run. Mirrors
201
+ * the shape `runBackgroundJob` produces for its own failures so the home
202
+ * feed and native notifications stay consistent regardless of which code
203
+ * path executed the work. Fire-and-forget — a notification failure must
204
+ * never break sweep operation.
205
+ */
206
+ function emitSweepActivityFailed(args: {
207
+ jobId: string;
208
+ errorMessage: string;
209
+ }): void {
210
+ const day = new Date().toISOString().slice(0, 10);
211
+ emitNotificationSignal({
212
+ sourceChannel: "scheduler",
213
+ sourceContextId: args.jobId,
214
+ sourceEventName: "activity.failed",
215
+ dedupeKey: `activity-failed:${JOB_NAME}:${day}`,
216
+ contextPayload: {
217
+ jobName: JOB_NAME,
218
+ errorMessage: args.errorMessage,
219
+ errorKind: "exception",
220
+ },
221
+ attentionHints: {
222
+ requiresAction: false,
223
+ urgency: "medium",
224
+ isAsyncBackground: true,
225
+ visibleInSourceNow: false,
226
+ },
227
+ }).catch((emitErr) => {
159
228
  log.warn(
160
- { error: parsed.error.message },
161
- "Sweep tool input did not match schema",
229
+ {
230
+ err: emitErr instanceof Error ? emitErr.message : String(emitErr),
231
+ jobId: args.jobId,
232
+ },
233
+ "Failed to emit activity.failed notification for memory v2 sweep",
162
234
  );
163
- return 0;
164
- }
165
-
166
- const written = appendEntries(memoryDir, parsed.data.entries);
167
- if (written > 0) {
168
- log.info({ written }, "Memory v2 sweep wrote new buffer entries");
169
- }
170
- return written;
235
+ });
171
236
  }
172
237
 
173
238
  /**
@@ -219,14 +284,22 @@ function loadRecentMessagesText(nowMs: number): string {
219
284
  const db = getDb();
220
285
  // Pull newest-first then reverse for chronological output. Bounding the
221
286
  // initial limit (1000) defends against pathological busy windows where a
222
- // naive scan would touch every recent message.
287
+ // naive scan would touch every recent message. Joining conversations and
288
+ // excluding background/scheduled types keeps automation chatter
289
+ // (heartbeats, filing, update bulletins, scheduled jobs) out of buffer.md.
223
290
  const rows = db
224
291
  .select({
225
292
  role: messages.role,
226
293
  content: messages.content,
227
294
  })
228
295
  .from(messages)
229
- .where(gt(messages.createdAt, cutoff))
296
+ .innerJoin(conversations, eq(messages.conversationId, conversations.id))
297
+ .where(
298
+ and(
299
+ gt(messages.createdAt, cutoff),
300
+ notInArray(conversations.conversationType, ["background", "scheduled"]),
301
+ ),
302
+ )
230
303
  .orderBy(desc(messages.createdAt))
231
304
  .limit(1000)
232
305
  .all();
@@ -248,50 +321,3 @@ function loadRecentMessagesText(nowMs: number): string {
248
321
  }
249
322
  return joined;
250
323
  }
251
-
252
- /**
253
- * Coerce stored message content (JSON-serialized `ContentBlock[]` *or* plain
254
- * string in legacy rows) into a single text string. Image / tool blocks are
255
- * dropped — the sweep model only needs the spoken context.
256
- */
257
- function stringifyMessageContent(stored: string): string {
258
- let parsed: unknown;
259
- try {
260
- parsed = JSON.parse(stored);
261
- } catch {
262
- return stored.trim();
263
- }
264
- if (typeof parsed === "string") return parsed.trim();
265
- if (!Array.isArray(parsed)) return "";
266
- const parts: string[] = [];
267
- for (const block of parsed) {
268
- if (
269
- block &&
270
- typeof block === "object" &&
271
- (block as { type?: string }).type === "text" &&
272
- typeof (block as { text?: unknown }).text === "string"
273
- ) {
274
- parts.push((block as { text: string }).text);
275
- }
276
- }
277
- return parts.join("\n").trim();
278
- }
279
-
280
- /**
281
- * Read the guardian's display name from `users/default.md`. We look for the
282
- * markdown-bold "Name" label (matching the IDENTITY.md convention) and fall
283
- * back to `null` on any miss; the prompt template substitutes a generic
284
- * label.
285
- */
286
- function resolveUserName(workspaceDir: string): string | null {
287
- try {
288
- const content = readFileSync(
289
- join(workspaceDir, "users", "default.md"),
290
- "utf-8",
291
- );
292
- const match = content.match(/\*\*Name:\*\*\s*(.+)/);
293
- return match?.[1]?.trim() || null;
294
- } catch {
295
- return null;
296
- }
297
- }
@@ -25,7 +25,8 @@ import { z } from "zod";
25
25
  * `edges:` means "activating A pulls in B" — activation flows A → B but not
26
26
  * B → A. The full graph is the union of every page's `edges:` list — there
27
27
  * is no separate edges-index file. `ref_files` lists paths to attached media
28
- * (images, audio, etc.).
28
+ * (images, audio, etc.). `ref_urls` lists external URL references (e.g.
29
+ * citations, source links).
29
30
  *
30
31
  * `summary` is a 1-4 sentence prose description of the page. When present,
31
32
  * retrieval injects the path + summary instead of the full page so the agent
@@ -33,11 +34,14 @@ import { z } from "zod";
33
34
  * the summary field still parse — those fall back to full-page injection and
34
35
  * full-page-only similarity.
35
36
  */
36
- export const ConceptPageFrontmatterSchema = z.object({
37
- edges: z.array(z.string()).default([]),
38
- ref_files: z.array(z.string()).default([]),
39
- summary: z.string().optional(),
40
- });
37
+ export const ConceptPageFrontmatterSchema = z
38
+ .object({
39
+ edges: z.array(z.string()).default([]),
40
+ ref_files: z.array(z.string()).default([]),
41
+ ref_urls: z.array(z.string().url()).default([]),
42
+ summary: z.string().optional(),
43
+ })
44
+ .strict();
41
45
 
42
46
  export type ConceptPageFrontmatter = z.infer<
43
47
  typeof ConceptPageFrontmatterSchema
@@ -8,3 +8,16 @@
8
8
  export function clampUnitInterval(value: number): number {
9
9
  return Math.min(1, Math.max(0, value));
10
10
  }
11
+
12
+ /**
13
+ * Map cosine similarity [-1, 1] into the unit interval [0, 1] via
14
+ * `(x + 1) / 2`, then clamp. Single-channel display normalization for the
15
+ * legacy v1 semantic-search path; do **not** use before hybrid fusion —
16
+ * the affine rescale halves pairwise dense differences and shifts ranking
17
+ * toward sparse. Hybrid fusion (`v2/sim.ts`) instead clamps negative
18
+ * cosines to 0 with `Math.max(0, x)` and lets positive cosines pass
19
+ * through unchanged.
20
+ */
21
+ export function mapCosineToUnit(value: number): number {
22
+ return clampUnitInterval((value + 1) / 2);
23
+ }