@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
@@ -39,16 +39,29 @@ import {
39
39
  import { getConversationDirPath } from "../memory/conversation-disk-view.js";
40
40
  import { getDb } from "../memory/db-connection.js";
41
41
  import { initializeDb } from "../memory/db-init.js";
42
+ import {
43
+ loadGraphMemoryState,
44
+ saveGraphMemoryState,
45
+ } from "../memory/graph/graph-memory-state-store.js";
42
46
  import { getRequestLogsByMessageId } from "../memory/llm-request-log-store.js";
43
47
  import {
48
+ bumpRetrospectiveLastRunAt,
49
+ getRetrospectiveState,
50
+ upsertRetrospectiveState,
51
+ } from "../memory/memory-retrospective-state.js";
52
+ import {
53
+ activationState,
44
54
  channelInboundEvents,
45
55
  conversationAssistantAttentionState,
56
+ conversationGraphMemoryState,
46
57
  conversations,
47
58
  externalConversationBindings,
48
59
  llmRequestLogs,
49
60
  memoryJobs,
61
+ memoryRetrospectiveState,
50
62
  toolInvocations,
51
63
  } from "../memory/schema.js";
64
+ import { hydrate as hydrateActivationState } from "../memory/v2/activation-store.js";
52
65
 
53
66
  initializeDb();
54
67
 
@@ -57,6 +70,9 @@ function resetTables(): void {
57
70
  db.delete(channelInboundEvents).run();
58
71
  db.delete(externalConversationBindings).run();
59
72
  db.delete(conversationAssistantAttentionState).run();
73
+ db.delete(activationState).run();
74
+ db.delete(conversationGraphMemoryState).run();
75
+ db.delete(memoryRetrospectiveState).run();
60
76
  db.delete(llmRequestLogs).run();
61
77
  db.delete(toolInvocations).run();
62
78
  db.delete(memoryJobs).run();
@@ -137,7 +153,6 @@ describe("forkConversation", () => {
137
153
  ).toBe(true);
138
154
  });
139
155
 
140
-
141
156
  test("preserves source order when source messages share a timestamp", () => {
142
157
  const source = createConversation("Equal timestamp thread");
143
158
  const db = getDb();
@@ -500,4 +515,229 @@ describe("forkConversation", () => {
500
515
  expect(forkInboundEventCount).toBe(0);
501
516
  expect(forkQueuedWorkCount).toBe(0);
502
517
  });
518
+
519
+ test("copies the parent's v2 activation state into the fork", async () => {
520
+ const source = createConversation("Activation thread");
521
+ const sourceMessage = await addMessage(
522
+ source.id,
523
+ "user",
524
+ "Tell me about the Q3 launch plan",
525
+ undefined,
526
+ { skipIndexing: true },
527
+ );
528
+
529
+ const db = getDb();
530
+ db.insert(activationState)
531
+ .values({
532
+ conversationId: source.id,
533
+ messageId: sourceMessage.id,
534
+ stateJson: JSON.stringify({
535
+ "concepts/q3-launch-plan": 0.71,
536
+ "concepts/marketing-ops": 0.34,
537
+ }),
538
+ everInjectedJson: JSON.stringify([
539
+ { slug: "concepts/q3-launch-plan", turn: 1 },
540
+ { slug: "concepts/marketing-ops", turn: 1 },
541
+ ]),
542
+ currentTurn: 2,
543
+ updatedAt: 1_700_000_000_000,
544
+ })
545
+ .run();
546
+
547
+ const fork = forkConversation({ conversationId: source.id });
548
+
549
+ const childState = await hydrateActivationState(db, fork.id);
550
+ expect(childState).toEqual({
551
+ messageId: sourceMessage.id,
552
+ state: {
553
+ "concepts/q3-launch-plan": 0.71,
554
+ "concepts/marketing-ops": 0.34,
555
+ },
556
+ everInjected: [
557
+ { slug: "concepts/q3-launch-plan", turn: 1 },
558
+ { slug: "concepts/marketing-ops", turn: 1 },
559
+ ],
560
+ currentTurn: 2,
561
+ updatedAt: 1_700_000_000_000,
562
+ });
563
+
564
+ // Parent state is untouched.
565
+ const parentState = await hydrateActivationState(db, source.id);
566
+ expect(parentState?.currentTurn).toBe(2);
567
+ });
568
+
569
+ test("copies the parent's v1 graph memory state into the fork", async () => {
570
+ const source = createConversation("Graph tracker thread");
571
+ await addMessage(
572
+ source.id,
573
+ "user",
574
+ "Look up alice's preferences",
575
+ undefined,
576
+ {
577
+ skipIndexing: true,
578
+ },
579
+ );
580
+
581
+ const trackerSnapshot = JSON.stringify({
582
+ initialized: true,
583
+ needsReload: false,
584
+ inContext: ["node-alice", "node-bob"],
585
+ log: [
586
+ { nodeId: "node-alice", turn: 1 },
587
+ { nodeId: "node-bob", turn: 2 },
588
+ ],
589
+ currentTurn: 3,
590
+ });
591
+ saveGraphMemoryState(source.id, trackerSnapshot);
592
+
593
+ const fork = forkConversation({ conversationId: source.id });
594
+
595
+ expect(loadGraphMemoryState(fork.id)).toBe(trackerSnapshot);
596
+ // Parent row is untouched.
597
+ expect(loadGraphMemoryState(source.id)).toBe(trackerSnapshot);
598
+ });
599
+
600
+ test("leaves both memory state tables empty when the parent has none", async () => {
601
+ const source = createConversation("Pristine thread");
602
+ await addMessage(source.id, "user", "first message", undefined, {
603
+ skipIndexing: true,
604
+ });
605
+
606
+ const fork = forkConversation({ conversationId: source.id });
607
+
608
+ const db = getDb();
609
+ expect(await hydrateActivationState(db, fork.id)).toBeNull();
610
+ expect(loadGraphMemoryState(fork.id)).toBeNull();
611
+ });
612
+ });
613
+
614
+ describe("forkConversation + memory_retrospective_state", () => {
615
+ beforeEach(() => {
616
+ resetTables();
617
+ });
618
+
619
+ test("does not seed state when the source has none", async () => {
620
+ const source = createConversation("Untouched thread");
621
+ await addMessage(source.id, "user", "Message 1", undefined, {
622
+ skipIndexing: true,
623
+ });
624
+
625
+ const fork = forkConversation({ conversationId: source.id });
626
+
627
+ expect(getRetrospectiveState(fork.id)).toBeNull();
628
+ });
629
+
630
+ test("maps the source pointer when it falls within the copied range", async () => {
631
+ const source = createConversation("In-range thread");
632
+ await addMessage(source.id, "user", "Message 1", undefined, {
633
+ skipIndexing: true,
634
+ });
635
+ const processedMessage = await addMessage(
636
+ source.id,
637
+ "assistant",
638
+ "Message 2",
639
+ undefined,
640
+ { skipIndexing: true },
641
+ );
642
+ await addMessage(source.id, "user", "Message 3", undefined, {
643
+ skipIndexing: true,
644
+ });
645
+
646
+ upsertRetrospectiveState({
647
+ conversationId: source.id,
648
+ lastProcessedMessageId: processedMessage.id,
649
+ lastRunAt: 1_700_000_000_000,
650
+ });
651
+
652
+ const fork = forkConversation({ conversationId: source.id });
653
+ const forkState = getRetrospectiveState(fork.id);
654
+ const forkMessages = getMessages(fork.id);
655
+ const mappedProcessedId = forkMessages.find((m) => {
656
+ const md = parseMetadata(m.metadata) as {
657
+ forkSourceMessageId?: string;
658
+ } | null;
659
+ return md?.forkSourceMessageId === processedMessage.id;
660
+ })?.id;
661
+
662
+ expect(mappedProcessedId).toBeDefined();
663
+ expect(forkState).not.toBeNull();
664
+ expect(forkState?.lastProcessedMessageId).toBe(mappedProcessedId);
665
+ expect(forkState?.lastRunAt).toBe(1_700_000_000_000);
666
+ });
667
+
668
+ test("clamps to the last copied message when the source pointer is past the fork boundary", async () => {
669
+ const source = createConversation("Past-boundary thread");
670
+ await addMessage(source.id, "user", "Message 1", undefined, {
671
+ skipIndexing: true,
672
+ });
673
+ const branchPoint = await addMessage(
674
+ source.id,
675
+ "assistant",
676
+ "Message 2",
677
+ undefined,
678
+ { skipIndexing: true },
679
+ );
680
+ const pastBoundaryMessage = await addMessage(
681
+ source.id,
682
+ "user",
683
+ "Message 3",
684
+ undefined,
685
+ { skipIndexing: true },
686
+ );
687
+ await addMessage(source.id, "assistant", "Message 4", undefined, {
688
+ skipIndexing: true,
689
+ });
690
+
691
+ upsertRetrospectiveState({
692
+ conversationId: source.id,
693
+ lastProcessedMessageId: pastBoundaryMessage.id,
694
+ lastRunAt: 1_700_000_000_000,
695
+ });
696
+
697
+ const fork = forkConversation({
698
+ conversationId: source.id,
699
+ throughMessageId: branchPoint.id,
700
+ });
701
+ const forkState = getRetrospectiveState(fork.id);
702
+ const forkMessages = getMessages(fork.id);
703
+ const lastForkedMessageId = forkMessages.at(-1)?.id;
704
+
705
+ expect(forkMessages).toHaveLength(2);
706
+ expect(forkState?.lastProcessedMessageId).toBe(lastForkedMessageId);
707
+ expect(forkState?.lastRunAt).toBe(1_700_000_000_000);
708
+ });
709
+
710
+ test("preserves the empty-string sentinel from a failure-only source", async () => {
711
+ const source = createConversation("Failure-only thread");
712
+ await addMessage(source.id, "user", "Message 1", undefined, {
713
+ skipIndexing: true,
714
+ });
715
+ bumpRetrospectiveLastRunAt(source.id, 1_700_000_000_000);
716
+
717
+ const fork = forkConversation({ conversationId: source.id });
718
+ const forkState = getRetrospectiveState(fork.id);
719
+
720
+ expect(forkState?.lastProcessedMessageId).toBe("");
721
+ expect(forkState?.lastRunAt).toBe(1_700_000_000_000);
722
+ });
723
+
724
+ test("copies lastRunAt so the cooldown gate inherits from the source", async () => {
725
+ const source = createConversation("Cooldown thread");
726
+ const message = await addMessage(
727
+ source.id,
728
+ "user",
729
+ "Message 1",
730
+ undefined,
731
+ { skipIndexing: true },
732
+ );
733
+ upsertRetrospectiveState({
734
+ conversationId: source.id,
735
+ lastProcessedMessageId: message.id,
736
+ lastRunAt: 1_700_000_000_000,
737
+ });
738
+
739
+ const fork = forkConversation({ conversationId: source.id });
740
+
741
+ expect(getRetrospectiveState(fork.id)?.lastRunAt).toBe(1_700_000_000_000);
742
+ });
503
743
  });
@@ -78,7 +78,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
78
78
  },
79
79
  });
80
80
 
81
- const result = profileRoute.handler({
81
+ const result = await profileRoute.handler({
82
82
  pathParams: { id: conversation.id },
83
83
  body: { profile: "quality-optimized" },
84
84
  headers: {},
@@ -86,7 +86,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
86
86
 
87
87
  await Promise.resolve();
88
88
 
89
- expect(result).toEqual({
89
+ expect(result).toMatchObject({
90
90
  conversationId: conversation.id,
91
91
  profile: "quality-optimized",
92
92
  });
@@ -104,23 +104,23 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
104
104
  subscription.dispose();
105
105
  });
106
106
 
107
- test("rejects unknown profile names with BadRequestError", () => {
107
+ test("rejects unknown profile names with BadRequestError", async () => {
108
108
  const conversation = createConversation("inference-profile-unknown");
109
109
 
110
- expect(() =>
110
+ await expect(
111
111
  profileRoute.handler({
112
112
  pathParams: { id: conversation.id },
113
113
  body: { profile: "does-not-exist" },
114
114
  headers: {},
115
115
  }),
116
- ).toThrow(BadRequestError);
116
+ ).rejects.toThrow(BadRequestError);
117
117
  expect(getConversation(conversation.id)?.inferenceProfile).toBeNull();
118
118
  });
119
119
 
120
120
  test("clears the override when profile is null", async () => {
121
121
  const conversation = createConversation("inference-profile-clear");
122
122
 
123
- profileRoute.handler({
123
+ await profileRoute.handler({
124
124
  pathParams: { id: conversation.id },
125
125
  body: { profile: "balanced" },
126
126
  headers: {},
@@ -137,7 +137,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
137
137
  },
138
138
  });
139
139
 
140
- const result = profileRoute.handler({
140
+ const result = await profileRoute.handler({
141
141
  pathParams: { id: conversation.id },
142
142
  body: { profile: null },
143
143
  headers: {},
@@ -145,7 +145,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
145
145
 
146
146
  await Promise.resolve();
147
147
 
148
- expect(result).toEqual({
148
+ expect(result).toMatchObject({
149
149
  conversationId: conversation.id,
150
150
  profile: null,
151
151
  });
@@ -158,7 +158,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
158
158
  test("skips write and event when the profile is unchanged", async () => {
159
159
  const conversation = createConversation("inference-profile-noop");
160
160
 
161
- profileRoute.handler({
161
+ await profileRoute.handler({
162
162
  pathParams: { id: conversation.id },
163
163
  body: { profile: "balanced" },
164
164
  headers: {},
@@ -175,7 +175,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
175
175
  },
176
176
  });
177
177
 
178
- const result = profileRoute.handler({
178
+ const result = await profileRoute.handler({
179
179
  pathParams: { id: conversation.id },
180
180
  body: { profile: "balanced" },
181
181
  headers: {},
@@ -183,7 +183,7 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
183
183
 
184
184
  await Promise.resolve();
185
185
 
186
- expect(result).toEqual({
186
+ expect(result).toMatchObject({
187
187
  conversationId: conversation.id,
188
188
  profile: "balanced",
189
189
  });
@@ -193,13 +193,13 @@ describe("PUT /v1/conversations/:id/inference-profile", () => {
193
193
  subscription.dispose();
194
194
  });
195
195
 
196
- test("throws NotFoundError when the conversation does not exist", () => {
197
- expect(() =>
196
+ test("throws NotFoundError when the conversation does not exist", async () => {
197
+ await expect(
198
198
  profileRoute.handler({
199
199
  pathParams: { id: "missing" },
200
200
  body: { profile: "balanced" },
201
201
  headers: {},
202
202
  }),
203
- ).toThrow(NotFoundError);
203
+ ).rejects.toThrow(NotFoundError);
204
204
  });
205
205
  });
@@ -136,6 +136,7 @@ mock.module("../config/loader.js", () => ({
136
136
  "fireworks",
137
137
  "brave",
138
138
  "perplexity",
139
+ "tavily",
139
140
  ],
140
141
  getConfig: () => mockConfig,
141
142
  getConfigReadOnly: () => mockConfig,
@@ -368,4 +368,128 @@ describe("loadFromDb metadata injection rehydration", () => {
368
368
  expect(messages).toHaveLength(2);
369
369
  expect(messages[0].content).toEqual([{ type: "text", text: "First" }]);
370
370
  });
371
+
372
+ test("historical user row rehydrates memoryV2StaticBlock between memory and system_reminder", async () => {
373
+ mockConversation = defaultConv();
374
+ mockDbMessages = [
375
+ {
376
+ id: "m1",
377
+ role: "user",
378
+ content: JSON.stringify([{ type: "text", text: "First turn" }]),
379
+ metadata: JSON.stringify({
380
+ memoryInjectedBlock: "mem payload",
381
+ memoryV2StaticBlock:
382
+ "<memory>\n## Essentials\n\nAlice prefers VS Code.\n</memory>",
383
+ pkbSystemReminderBlock:
384
+ "<system_reminder>\npkb payload\n</system_reminder>",
385
+ }),
386
+ },
387
+ {
388
+ id: "m2",
389
+ role: "assistant",
390
+ content: JSON.stringify([{ type: "text", text: "Reply" }]),
391
+ },
392
+ {
393
+ id: "m3",
394
+ role: "user",
395
+ content: JSON.stringify([{ type: "text", text: "Tail turn" }]),
396
+ },
397
+ ];
398
+
399
+ const conversation = makeConversation();
400
+ await conversation.loadFromDb();
401
+ const messages = conversation.getMessages();
402
+
403
+ expect(messages).toHaveLength(3);
404
+ expect(messages[0].role).toBe("user");
405
+ expect(messages[0].content).toEqual([
406
+ { type: "text", text: "<memory>\nmem payload\n</memory>" },
407
+ {
408
+ type: "text",
409
+ text: "<memory>\n## Essentials\n\nAlice prefers VS Code.\n</memory>",
410
+ },
411
+ {
412
+ type: "text",
413
+ text: "<system_reminder>\npkb payload\n</system_reminder>",
414
+ },
415
+ { type: "text", text: "First turn" },
416
+ ]);
417
+ });
418
+
419
+ test("tail user row skips memoryV2StaticBlock", async () => {
420
+ mockConversation = defaultConv();
421
+ mockDbMessages = [
422
+ {
423
+ id: "m1",
424
+ role: "user",
425
+ content: JSON.stringify([{ type: "text", text: "First" }]),
426
+ },
427
+ {
428
+ id: "m2",
429
+ role: "assistant",
430
+ content: JSON.stringify([{ type: "text", text: "Reply" }]),
431
+ },
432
+ {
433
+ id: "m3",
434
+ role: "user",
435
+ content: JSON.stringify([{ type: "text", text: "Tail" }]),
436
+ metadata: JSON.stringify({
437
+ memoryV2StaticBlock: "<memory>\n## Essentials\n\nleak\n</memory>",
438
+ }),
439
+ },
440
+ ];
441
+
442
+ const conversation = makeConversation();
443
+ await conversation.loadFromDb();
444
+ const messages = conversation.getMessages();
445
+
446
+ expect(messages).toHaveLength(3);
447
+ expect(messages[2].role).toBe("user");
448
+ // Tail row receives fresh injection on the next turn — the persisted
449
+ // static block must not rehydrate here.
450
+ expect(messages[2].content).toEqual([{ type: "text", text: "Tail" }]);
451
+ });
452
+
453
+ test("untrusted-actor view does not rehydrate memoryV2StaticBlock", async () => {
454
+ mockConversation = defaultConv();
455
+ // Rows with `trusted_contact` / `unknown` provenance survive the
456
+ // untrusted-actor row filter, so this isolates the rehydrate gate.
457
+ mockDbMessages = [
458
+ {
459
+ id: "m1",
460
+ role: "user",
461
+ content: JSON.stringify([{ type: "text", text: "First" }]),
462
+ metadata: JSON.stringify({
463
+ provenanceTrustClass: "trusted_contact",
464
+ memoryV2StaticBlock:
465
+ "<memory>\n## Essentials\n\nprivate memory\n</memory>",
466
+ }),
467
+ },
468
+ {
469
+ id: "m2",
470
+ role: "assistant",
471
+ content: JSON.stringify([{ type: "text", text: "Reply" }]),
472
+ metadata: JSON.stringify({ provenanceTrustClass: "unknown" }),
473
+ },
474
+ {
475
+ id: "m3",
476
+ role: "user",
477
+ content: JSON.stringify([{ type: "text", text: "Tail" }]),
478
+ metadata: JSON.stringify({ provenanceTrustClass: "trusted_contact" }),
479
+ },
480
+ ];
481
+
482
+ const conversation = makeConversation();
483
+ conversation.setTrustContext({
484
+ trustClass: "trusted_contact",
485
+ sourceChannel: "telegram",
486
+ });
487
+ await conversation.loadFromDb();
488
+ const messages = conversation.getMessages();
489
+
490
+ expect(messages).toHaveLength(3);
491
+ // The historical row survives row-level filtering but the rehydrate gate
492
+ // suppresses the personal-memory block.
493
+ expect(messages[0].content).toEqual([{ type: "text", text: "First" }]);
494
+ });
371
495
  });
@@ -15,7 +15,7 @@
15
15
  * instantiation block use at first-message time.
16
16
  */
17
17
 
18
- import { describe, expect, mock, test } from "bun:test";
18
+ import { afterEach, describe, expect, mock, test } from "bun:test";
19
19
 
20
20
  // ---------------------------------------------------------------------------
21
21
  // Module mocks for downstream side effects (DB writes, slash resolution,
@@ -28,6 +28,20 @@ mock.module("../util/logger.js", () => ({
28
28
  new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
29
29
  }));
30
30
 
31
+ /**
32
+ * Per-test capability client roster. Set in individual tests to simulate
33
+ * a connected macOS client for cross-client drain-path coverage. Reset in
34
+ * afterEach so tests don't bleed state.
35
+ */
36
+ let mockCapabilityClients: Array<{ clientId: string; actorPrincipalId?: string }> = [];
37
+
38
+ mock.module("../runtime/assistant-event-hub.js", () => ({
39
+ assistantEventHub: {
40
+ listClientsByCapability: () => mockCapabilityClients,
41
+ },
42
+ broadcastMessage: () => {},
43
+ }));
44
+
31
45
  mock.module("../memory/conversation-crud.js", () => ({
32
46
  setConversationOriginChannelIfUnset: () => {},
33
47
  setConversationOriginInterfaceIfUnset: () => {},
@@ -145,6 +159,7 @@ function makeFakeContext(opts: {
145
159
  },
146
160
  setTransportHints() {},
147
161
  applyHostEnvFromTransport() {},
162
+ ensureHostProxiesForTurn() {},
148
163
  } as unknown as ProcessConversationContext & FakeRecord;
149
164
  return ctx;
150
165
  }
@@ -170,6 +185,10 @@ function makeQueuedMessage(opts: {
170
185
  // ---------------------------------------------------------------------------
171
186
 
172
187
  describe("drainQueue preactivation re-add for host-proxy interfaces", () => {
188
+ afterEach(() => {
189
+ mockCapabilityClients = [];
190
+ });
191
+
173
192
  test("drainSingleMessage re-adds 'app-control' for macOS-sourced queued message", async () => {
174
193
  const queue = new MessageQueue();
175
194
  const ifCtx: TurnInterfaceContext = {
@@ -280,4 +299,84 @@ describe("drainQueue preactivation re-add for host-proxy interfaces", () => {
280
299
  expect(ctx.preactivatedSkillIdCalls).not.toContain("computer-use");
281
300
  expect(ctx.preactivatedSkillIdCalls).not.toContain("app-control");
282
301
  });
302
+
303
+ // ── Cross-client drain-path: web source + macOS client connected ──────
304
+
305
+ test("drainSingleMessage re-adds 'app-control' for web-sourced message when macOS client is connected", async () => {
306
+ mockCapabilityClients = [
307
+ { clientId: "macos-client-1", actorPrincipalId: "user-1" },
308
+ ];
309
+ const queue = new MessageQueue();
310
+ const ifCtx: TurnInterfaceContext = {
311
+ userMessageInterface: "web",
312
+ assistantMessageInterface: "web",
313
+ };
314
+ queue.push(
315
+ makeQueuedMessage({ requestId: "req-web-1", turnInterfaceContext: ifCtx }),
316
+ );
317
+ const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
318
+
319
+ await drainQueue(ctx);
320
+
321
+ // web natively supports neither host_cu nor host_app_control, but the
322
+ // connected macOS client provides both via cross-client routing — so
323
+ // both skills must be re-preactivated.
324
+ expect(ctx.preactivatedSkillIdCalls).toContain("app-control");
325
+ expect(ctx.preactivatedSkillIds).toContain("app-control");
326
+ expect(ctx.preactivatedSkillIdCalls).toContain("computer-use");
327
+ });
328
+
329
+ test("drainSingleMessage does NOT re-add 'app-control' for web-sourced message when no capable client is connected", async () => {
330
+ // mockCapabilityClients remains [] (reset by afterEach from prior test)
331
+ const queue = new MessageQueue();
332
+ const ifCtx: TurnInterfaceContext = {
333
+ userMessageInterface: "web",
334
+ assistantMessageInterface: "web",
335
+ };
336
+ queue.push(
337
+ makeQueuedMessage({ requestId: "req-web-2", turnInterfaceContext: ifCtx }),
338
+ );
339
+ const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
340
+
341
+ await drainQueue(ctx);
342
+
343
+ expect(ctx.preactivatedSkillIdCalls).not.toContain("app-control");
344
+ expect(ctx.preactivatedSkillIdCalls).not.toContain("computer-use");
345
+ });
346
+
347
+ test("drainSingleMessage re-adds 'computer-use' for web-sourced message when macOS client is connected", async () => {
348
+ mockCapabilityClients = [
349
+ { clientId: "macos-client-1", actorPrincipalId: "user-1" },
350
+ ];
351
+ const queue = new MessageQueue();
352
+ const ifCtx: TurnInterfaceContext = {
353
+ userMessageInterface: "web",
354
+ assistantMessageInterface: "web",
355
+ };
356
+ queue.push(
357
+ makeQueuedMessage({ requestId: "req-web-3", turnInterfaceContext: ifCtx }),
358
+ );
359
+ const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
360
+
361
+ await drainQueue(ctx);
362
+
363
+ expect(ctx.preactivatedSkillIdCalls).toContain("computer-use");
364
+ expect(ctx.preactivatedSkillIds).toContain("computer-use");
365
+ });
366
+
367
+ test("drainSingleMessage does NOT re-add 'computer-use' for web-sourced message when no capable client is connected", async () => {
368
+ const queue = new MessageQueue();
369
+ const ifCtx: TurnInterfaceContext = {
370
+ userMessageInterface: "web",
371
+ assistantMessageInterface: "web",
372
+ };
373
+ queue.push(
374
+ makeQueuedMessage({ requestId: "req-web-4", turnInterfaceContext: ifCtx }),
375
+ );
376
+ const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
377
+
378
+ await drainQueue(ctx);
379
+
380
+ expect(ctx.preactivatedSkillIdCalls).not.toContain("computer-use");
381
+ });
283
382
  });
@@ -40,9 +40,28 @@ mock.module("../memory/guardian-action-store.js", () => ({
40
40
  resolveGuardianActionRequest: () => {},
41
41
  }));
42
42
 
43
+ const mockProviderStub = { name: "mock-provider" };
43
44
  mock.module("../providers/registry.js", () => ({
44
- getProvider: () => ({ name: "mock-provider" }),
45
+ getProvider: () => mockProviderStub,
45
46
  initializeProviders: () => {},
47
+ listProviders: () => ["anthropic", "openai", "gemini"],
48
+ resolveProviderFromConnection: async () => mockProviderStub,
49
+ }));
50
+
51
+ // Connection-aware resolver path: satisfy
52
+ // `tryResolveProviderForConnectionName` lookups so resolveDefaultProvider
53
+ // returns a usable provider for the inline `anthropic-conn` fixture.
54
+ mock.module("../providers/inference/connections.js", () => ({
55
+ getConnection: (_db: unknown, name: string) => ({
56
+ id: 1,
57
+ name,
58
+ provider: "anthropic",
59
+ auth_strategy: "user_managed_credential",
60
+ credential_alias: null,
61
+ metadata_json: null,
62
+ created_at: new Date().toISOString(),
63
+ updated_at: new Date().toISOString(),
64
+ }),
46
65
  }));
47
66
 
48
67
  mock.module("../config/loader.js", () => ({
@@ -51,6 +70,7 @@ mock.module("../config/loader.js", () => ({
51
70
  llm: {
52
71
  default: {
53
72
  provider: "anthropic",
73
+ provider_connection: "anthropic-conn",
54
74
  model: "claude-opus-4-6",
55
75
  maxTokens: 4096,
56
76
  effort: "max" as const,