@vellumai/assistant 0.7.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -32,6 +32,19 @@ const COMPACTION_TOOL_RESULT_MAX_CHARS = 6_000;
32
32
  const MIN_COMPACTABLE_PERSISTED_MESSAGES = 2;
33
33
  const INTERNAL_CONTEXT_SUMMARY_MESSAGES = new WeakSet<Message>();
34
34
 
35
+ /**
36
+ * Hard cap on the verbatim tail-anchor block we splice into the
37
+ * post-compaction summary message (see `extractTailAssistantText`). 1500
38
+ * chars (~375 tokens) covers a few paragraphs of recent assistant
39
+ * narration without bloating the summary. When the tail exceeds this
40
+ * size we keep the END (most recent text), since "next step" / "now I'll
41
+ * …" statements typically live at the end of the assistant's last text
42
+ * block and that's the part the post-compaction model needs most.
43
+ */
44
+ const TAIL_ANCHOR_MAX_CHARS = 1500;
45
+ const TAIL_ANCHOR_OPEN_TAG = "<verbatim_tail>";
46
+ const TAIL_ANCHOR_CLOSE_TAG = "</verbatim_tail>";
47
+
35
48
  /**
36
49
  * When the existing summary is this fraction or more of the per-summary
37
50
  * token budget, inject a "compress older content aggressively" instruction
@@ -488,13 +501,45 @@ export class ContextWindowManager {
488
501
  };
489
502
  }
490
503
 
491
- const keepPlan = this.pickKeepBoundary(messages, userTurnStarts, {
504
+ const keepPlanInitial = this.pickKeepBoundary(messages, userTurnStarts, {
492
505
  minKeepRecentUserTurns: options?.minKeepRecentUserTurns,
493
506
  targetInputTokensOverride: options?.targetInputTokensOverride,
494
507
  conversationOriginChannel: options?.conversationOriginChannel,
495
508
  force: options?.force,
496
509
  previousEstimatedInputTokens,
497
510
  });
511
+ // Under force (user-explicit `/compact`), never route through the
512
+ // "already fits" / "truncated tool results without summarization"
513
+ // early-return — those are no-op responses to a direct user command.
514
+ // The boundary can collapse to the summary in two cases the
515
+ // projection-optimism clamp in pickKeepBoundary does not cover:
516
+ // 1. `adjustForToolPairs` walked the boundary back through a
517
+ // tool_use/tool_result chain at the start of the conversation.
518
+ // 2. The binary search settled below `userTurnStarts.length` (so
519
+ // the clamp at the top of pickKeepBoundary did not fire) but
520
+ // `adjustForToolPairs` still walked the resulting boundary
521
+ // backwards past `summaryOffset`.
522
+ // Rescue: restore the binary search's intended keep depth (capped at
523
+ // `length - 1` so we always summarize at least one turn) and bypass
524
+ // `adjustForToolPairs`. The kept region's first message may then
525
+ // contain a `tool_result` whose matching `tool_use` lives in the
526
+ // compacted region; we strip such orphans below before assembling
527
+ // the final messages array so the next agent turn does not fail
528
+ // when sending to the LLM.
529
+ const forceRescueApplied =
530
+ options?.force === true &&
531
+ keepPlanInitial.keepFromIndex <= summaryOffset &&
532
+ userTurnStarts.length >= 2;
533
+ const safeKeepTurns = Math.max(
534
+ 1,
535
+ Math.min(keepPlanInitial.keepTurns, userTurnStarts.length - 1),
536
+ );
537
+ const keepPlan = forceRescueApplied
538
+ ? {
539
+ keepFromIndex: userTurnStarts[userTurnStarts.length - safeKeepTurns],
540
+ keepTurns: safeKeepTurns,
541
+ }
542
+ : keepPlanInitial;
498
543
  if (keepPlan.keepFromIndex <= summaryOffset) {
499
544
  // All turns fit after truncation projection, but the real in-memory
500
545
  // messages may still contain un-truncated tool results. Apply truncation
@@ -511,6 +556,14 @@ export class ContextWindowManager {
511
556
  toolTokenBudget: this.toolTokenBudget,
512
557
  })
513
558
  : previousEstimatedInputTokens;
559
+ // Under force with only one user turn, the rescue above could not
560
+ // fire — there is nothing earlier to summarize. Surface that
561
+ // explicitly instead of "conversation already fits..." so the user
562
+ // knows why `/compact` did not produce a summary.
563
+ const noSummarizationReason =
564
+ options?.force && userTurnStarts.length < 2
565
+ ? "only one user turn — nothing earlier to compact"
566
+ : "conversation already fits within the compaction target";
514
567
  return {
515
568
  messages: truncatedMessages,
516
569
  compacted: didTruncate,
@@ -527,7 +580,7 @@ export class ContextWindowManager {
527
580
  summaryText: existingSummary ?? "",
528
581
  reason: didTruncate
529
582
  ? "truncated tool results without summarization"
530
- : "conversation already fits within the compaction target",
583
+ : noSummarizationReason,
531
584
  };
532
585
  }
533
586
 
@@ -645,9 +698,15 @@ export class ContextWindowManager {
645
698
  };
646
699
  }
647
700
 
701
+ // `severePressure` already bypasses this guard to keep context from
702
+ // overflowing. Forced compaction also bypasses: when the user
703
+ // explicitly types `/compact` we must summarize whatever is
704
+ // available rather than return "insufficient compactable persisted
705
+ // messages" — that is a no-op response to a direct user command.
648
706
  if (
649
707
  compactedPersistedMessages < MIN_COMPACTABLE_PERSISTED_MESSAGES &&
650
- !severePressure
708
+ !severePressure &&
709
+ !options?.force
651
710
  ) {
652
711
  return {
653
712
  messages,
@@ -688,7 +747,6 @@ export class ContextWindowManager {
688
747
  signal,
689
748
  options?.overrideProfile ?? null,
690
749
  );
691
- const summary = summaryUpdate.summary;
692
750
  const summaryInputTokens = summaryUpdate.inputTokens;
693
751
  const summaryOutputTokens = summaryUpdate.outputTokens;
694
752
  const summaryModel = summaryUpdate.model;
@@ -704,6 +762,19 @@ export class ContextWindowManager {
704
762
  }
705
763
  const summaryCalls = 1;
706
764
 
765
+ // Force-keep the most recent assistant text from the compactable region
766
+ // by splicing it verbatim into the summary message. This is independent
767
+ // of what the LLM summarizer chose to surface — when compaction
768
+ // interrupts a long assistant work span, this anchor preserves the
769
+ // model's last self-narration ("Next step: …", "About to …") so the
770
+ // post-compaction model has unambiguous continuity instead of falling
771
+ // back to a "where am I?" recovery shape.
772
+ const tailAnchorText = extractTailAssistantText(compactableMessages);
773
+ const summary =
774
+ tailAnchorText != null
775
+ ? appendTailAnchorToSummary(summaryUpdate.summary, tailAnchorText)
776
+ : summaryUpdate.summary;
777
+
707
778
  // Media (images, files) in kept turns is preserved naturally — those
708
779
  // turns are carried forward as-is and their token cost is already
709
780
  // accounted for by pickKeepBoundary's estimatePromptTokens call.
@@ -716,7 +787,14 @@ export class ContextWindowManager {
716
787
  messages.slice(keepPlan.keepFromIndex),
717
788
  COMPACTION_TOOL_RESULT_MAX_CHARS,
718
789
  );
719
- const compactedMessages = [summaryMessage, ...truncatedKeptMessages];
790
+ // The force-rescue boundary bypasses `adjustForToolPairs`, so the
791
+ // kept region may contain `tool_result` blocks whose matching
792
+ // `tool_use` is in the (now-compacted) prefix. Strip those orphans
793
+ // so the next agent turn does not fail with an LLM API error.
794
+ const keptMessages = forceRescueApplied
795
+ ? stripOrphanToolResults(truncatedKeptMessages)
796
+ : truncatedKeptMessages;
797
+ const compactedMessages = [summaryMessage, ...keptMessages];
720
798
  const estimatedInputTokens = estimatePromptTokens(
721
799
  compactedMessages,
722
800
  this.systemPrompt,
@@ -1251,6 +1329,53 @@ function adjustForToolPairs(
1251
1329
  return idx;
1252
1330
  }
1253
1331
 
1332
+ /**
1333
+ * Strip `tool_result` blocks whose matching `tool_use` is not present in
1334
+ * the message array. Used by the force-rescue path in `_maybeCompact`
1335
+ * which bypasses `adjustForToolPairs` to honor user-explicit `/compact`
1336
+ * commands — the kept region's first user message can otherwise contain
1337
+ * an orphan `tool_result`, which the LLM API rejects.
1338
+ *
1339
+ * A user message that contains only orphan `tool_result` blocks is
1340
+ * dropped entirely; partial messages keep the surviving content blocks.
1341
+ */
1342
+ function stripOrphanToolResults(messages: Message[]): Message[] {
1343
+ const knownToolUseIds = new Set<string>();
1344
+ for (const msg of messages) {
1345
+ if (msg.role !== "assistant") continue;
1346
+ for (const block of msg.content) {
1347
+ if (
1348
+ (block.type === "tool_use" || block.type === "server_tool_use") &&
1349
+ "id" in block
1350
+ ) {
1351
+ knownToolUseIds.add((block as { id: string }).id);
1352
+ }
1353
+ }
1354
+ }
1355
+
1356
+ return messages.flatMap((msg) => {
1357
+ if (msg.role !== "user") return [msg];
1358
+ let stripped = false;
1359
+ const filtered = msg.content.filter((block) => {
1360
+ if (
1361
+ (block.type === "tool_result" ||
1362
+ block.type === "web_search_tool_result") &&
1363
+ "tool_use_id" in block
1364
+ ) {
1365
+ const id = (block as { tool_use_id: string }).tool_use_id;
1366
+ if (!knownToolUseIds.has(id)) {
1367
+ stripped = true;
1368
+ return false;
1369
+ }
1370
+ }
1371
+ return true;
1372
+ });
1373
+ if (!stripped) return [msg];
1374
+ if (filtered.length === 0) return [];
1375
+ return [{ ...msg, content: filtered }];
1376
+ });
1377
+ }
1378
+
1254
1379
  export function getSummaryFromContextMessage(
1255
1380
  message: Message | undefined,
1256
1381
  ): string | null {
@@ -1286,6 +1411,67 @@ export function createContextSummaryMessage(summary: string): Message {
1286
1411
  return message;
1287
1412
  }
1288
1413
 
1414
+ /**
1415
+ * Walk `messages` backward and return the concatenated text content of the
1416
+ * most recent assistant message that contains at least one non-empty text
1417
+ * block. tool_use / tool_result / image / unknown blocks are skipped. The
1418
+ * result is trimmed and (if longer than `maxChars`) clamped from the START
1419
+ * so the END — where "next step" / "now I'll …" narration tends to land —
1420
+ * is preserved.
1421
+ *
1422
+ * Returns `null` when no eligible assistant text is found (e.g. compactable
1423
+ * region was all user/tool messages, or all assistant messages were
1424
+ * tool_use-only). The caller treats `null` as "no anchor to splice".
1425
+ *
1426
+ * Used by `_maybeCompact` to force-keep the last assistant text from the
1427
+ * compactable region into the post-compaction summary message, so the
1428
+ * model's most recent self-narration survives summarization regardless of
1429
+ * whether the LLM summarizer chose to surface it.
1430
+ */
1431
+ export function extractTailAssistantText(
1432
+ messages: Message[],
1433
+ maxChars: number = TAIL_ANCHOR_MAX_CHARS,
1434
+ ): string | null {
1435
+ for (let i = messages.length - 1; i >= 0; i--) {
1436
+ const message = messages[i];
1437
+ if (message?.role !== "assistant") continue;
1438
+ const text = extractText(message.content).trim();
1439
+ if (text.length === 0) continue;
1440
+ if (text.length <= maxChars) return text;
1441
+ // Keep the END — most recent narration wins.
1442
+ const truncated = safeStringSlice(
1443
+ text,
1444
+ text.length - maxChars,
1445
+ text.length,
1446
+ );
1447
+ return `[...truncated] ${truncated}`;
1448
+ }
1449
+ return null;
1450
+ }
1451
+
1452
+ /**
1453
+ * Splice a verbatim tail-anchor block onto the end of the LLM-produced
1454
+ * summary text. The tag-wrapped block is structurally distinct from any
1455
+ * `## ` section the LLM might generate, so it survives section-boundary
1456
+ * clamping in `clampSummaryAtSectionBoundary` (which only runs on the LLM
1457
+ * summary itself, before this splice).
1458
+ *
1459
+ * Idempotent: if the summary already ends with a `<verbatim_tail>…` block
1460
+ * (e.g. from a prior compaction whose summary was carried forward as
1461
+ * `existingSummary`), it is replaced rather than stacked, so successive
1462
+ * compactions don't accumulate stale tails.
1463
+ */
1464
+ export function appendTailAnchorToSummary(
1465
+ summary: string,
1466
+ tailText: string,
1467
+ ): string {
1468
+ const trimmed = summary.trimEnd();
1469
+ const existingOpen = trimmed.lastIndexOf(TAIL_ANCHOR_OPEN_TAG);
1470
+ const base =
1471
+ existingOpen >= 0 ? trimmed.slice(0, existingOpen).trimEnd() : trimmed;
1472
+ return `${base}\n\n${TAIL_ANCHOR_OPEN_TAG}\n${tailText.trim()}\n${TAIL_ANCHOR_CLOSE_TAG}`;
1473
+ }
1474
+
1289
1475
  /**
1290
1476
  * Build content blocks for the summary prompt. Returns a mix of text blocks
1291
1477
  * (for the scaffolding, existing summary, and serialized non-image content)
@@ -56,6 +56,16 @@ let autoAnalyzeEnabled = true;
56
56
  // `disposeConversation` must skip the `graph_extract` enqueue.
57
57
  const autoAnalysisConversations = new Set<string>();
58
58
 
59
+ // Toggles the `memory.v2.enabled` flag the disposal code reads via
60
+ // `getConfig()`. Defaults to false so the bulk of the suite — which asserts
61
+ // v1 graph_extract still fires — keeps its semantics. The dedicated v2 cases
62
+ // flip this to true.
63
+ let v2Enabled = false;
64
+
65
+ mock.module("../../config/loader.js", () => ({
66
+ getConfig: () => ({ memory: { v2: { enabled: v2Enabled } } }),
67
+ }));
68
+
59
69
  mock.module("../../memory/auto-analysis-guard.js", () => ({
60
70
  AUTO_ANALYSIS_SOURCE: "auto-analysis",
61
71
  isAutoAnalysisConversation: (conversationId: string) =>
@@ -81,6 +91,27 @@ mock.module("../../memory/auto-analysis-enqueue.js", () => ({
81
91
  },
82
92
  }));
83
93
 
94
+ let memoryRetroEnabled = false;
95
+ const memoryRetroCalls: Array<{
96
+ conversationId: string;
97
+ trigger: string;
98
+ }> = [];
99
+
100
+ mock.module("../../memory/memory-retrospective-enqueue.js", () => ({
101
+ enqueueMemoryRetrospectiveIfEnabled: (args: {
102
+ conversationId: string;
103
+ trigger: string;
104
+ }) => {
105
+ if (!memoryRetroEnabled) return;
106
+ memoryRetroCalls.push(args);
107
+ },
108
+ // Also export sibling functions other modules import from this file, so
109
+ // mocking it here doesn't break transitive imports loaded during the
110
+ // `disposeConversation` dynamic-import chain.
111
+ enqueueMemoryRetrospectiveOnCompaction: () => {},
112
+ isMemoryRetrospectiveConversation: (_id: string) => false,
113
+ }));
114
+
84
115
  // Stub all side-effecting cleanup helpers that disposeConversation chains
85
116
  // into after the enqueue block. We assert on enqueue behavior only.
86
117
  mock.module("../../tools/browser/browser-screencast.js", () => ({
@@ -158,8 +189,11 @@ describe("disposeConversation — auto-analysis enqueue", () => {
158
189
  beforeEach(() => {
159
190
  memoryJobCalls.length = 0;
160
191
  autoAnalyzeCalls.length = 0;
192
+ memoryRetroCalls.length = 0;
161
193
  autoAnalyzeEnabled = true;
194
+ memoryRetroEnabled = false;
162
195
  autoAnalysisConversations.clear();
196
+ v2Enabled = false;
163
197
  });
164
198
 
165
199
  test("guardian conversation with auto-analyze ON — enqueues both graph_extract and conversation_analyze (via helper)", () => {
@@ -313,4 +347,81 @@ describe("disposeConversation — auto-analysis enqueue", () => {
313
347
  }));
314
348
  autoAnalyzeEnabled = originalEnabled;
315
349
  });
350
+
351
+ test("memory v2 enabled — graph_extract enqueue is suppressed (auto-analysis still runs)", () => {
352
+ // Under memory v2, the v1 graph has no readers (retrieval is bypassed at
353
+ // conversation-graph-memory.ts), so producing extraction jobs just fills
354
+ // the queue with stale work. Auto-analysis is orthogonal and must keep
355
+ // running.
356
+ v2Enabled = true;
357
+ const ctx = makeDisposeContext({
358
+ conversationId: "conv-v2-on",
359
+ trustClass: "guardian",
360
+ });
361
+
362
+ disposeConversation(ctx);
363
+
364
+ expect(memoryJobCalls).toHaveLength(0);
365
+ expect(autoAnalyzeCalls).toHaveLength(1);
366
+ expect(autoAnalyzeCalls[0]).toEqual({
367
+ conversationId: "conv-v2-on",
368
+ trigger: "lifecycle",
369
+ });
370
+ });
371
+ });
372
+
373
+ describe("disposeConversation — memory-retrospective lifecycle safety net", () => {
374
+ beforeEach(() => {
375
+ memoryJobCalls.length = 0;
376
+ autoAnalyzeCalls.length = 0;
377
+ memoryRetroCalls.length = 0;
378
+ autoAnalyzeEnabled = false;
379
+ memoryRetroEnabled = false;
380
+ autoAnalysisConversations.clear();
381
+ v2Enabled = false;
382
+ });
383
+
384
+ test("guardian conversation + flag on — enqueues memory-retrospective with trigger 'lifecycle'", () => {
385
+ memoryRetroEnabled = true;
386
+ const ctx = makeDisposeContext({
387
+ conversationId: "conv-retro",
388
+ trustClass: "guardian",
389
+ });
390
+
391
+ disposeConversation(ctx);
392
+
393
+ expect(memoryRetroCalls).toHaveLength(1);
394
+ expect(memoryRetroCalls[0]).toEqual({
395
+ conversationId: "conv-retro",
396
+ trigger: "lifecycle",
397
+ });
398
+ });
399
+
400
+ test("flag off — no memory-retrospective enqueue", () => {
401
+ memoryRetroEnabled = false;
402
+ const ctx = makeDisposeContext({
403
+ conversationId: "conv-retro-off",
404
+ trustClass: "guardian",
405
+ });
406
+
407
+ disposeConversation(ctx);
408
+
409
+ expect(memoryRetroCalls).toHaveLength(0);
410
+ });
411
+
412
+ test("untrusted actor — no memory-retrospective enqueue even when flag is on", () => {
413
+ memoryRetroEnabled = true;
414
+ const ctx = makeDisposeContext({
415
+ conversationId: "conv-retro-untrusted",
416
+ trustClass: "unknown",
417
+ });
418
+
419
+ disposeConversation(ctx);
420
+
421
+ // The outer trust-class guard in disposeConversation gates ALL three
422
+ // enqueues (graph_extract, auto-analyze, memory-retrospective). When
423
+ // the actor is untrusted, none of them fire.
424
+ expect(memoryRetroCalls).toHaveLength(0);
425
+ expect(autoAnalyzeCalls).toHaveLength(0);
426
+ });
316
427
  });
@@ -20,10 +20,11 @@
20
20
  * hasNoClient flag.
21
21
  *
22
22
  * Cross-client exception: tools whose capabilities are in
23
- * CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file) are allowed for
24
- * non-host-proxy interfaces (e.g. "web") when at least one capable client
25
- * is connected via the event hub. host_browser is excluded (chrome-extension
26
- * is its own executor; web turns have no CDP target model).
23
+ * CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file, host_browser)
24
+ * are allowed for non-host-proxy interactive interfaces ("web", "ios")
25
+ * when at least one capable client is connected via the event hub.
26
+ * chrome-extension is excluded as a security boundary, regardless of
27
+ * whether the capability is technically supported elsewhere.
27
28
  */
28
29
 
29
30
  import { beforeEach, describe, expect, mock, test } from "bun:test";
@@ -358,6 +359,110 @@ describe("isToolActiveForContext — cross-client exposure for host_file_*", ()
358
359
  });
359
360
  });
360
361
 
362
+ describe("isToolActiveForContext — cross-client exposure for host_browser", () => {
363
+ // host_browser cross-client routing was shipped in PR #27489 (host-
364
+ // browser-via-macos-host-proxy); LLM-exposure for non-host-proxy
365
+ // transports is added by including "host_browser" in
366
+ // CROSS_CLIENT_EXPOSED_CAPABILITIES. Web and iOS turns can now drive a
367
+ // connected macOS or chrome-extension client via the event hub.
368
+ test("host_browser is exposed for web transport when a host_browser client is connected", () => {
369
+ mockClientCountByCapability.set("host_browser", 1);
370
+ expect(
371
+ isToolActiveForContext(
372
+ "host_browser",
373
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
374
+ ),
375
+ ).toBe(true);
376
+ });
377
+
378
+ test("host_browser is exposed for ios transport when a host_browser client is connected", () => {
379
+ // INTERACTIVE_INTERFACES = {macos, ios, web}; ios goes through the same
380
+ // cross-client branch as web because supportsHostProxy("ios", *) is
381
+ // false. This pins the parity guarantee.
382
+ mockClientCountByCapability.set("host_browser", 1);
383
+ expect(
384
+ isToolActiveForContext(
385
+ "host_browser",
386
+ makeCtx({ hasNoClient: false, transportInterface: "ios" }),
387
+ ),
388
+ ).toBe(true);
389
+ });
390
+
391
+ test("host_browser is NOT exposed for web when no host_browser client is connected", () => {
392
+ mockClientCountByCapability.set("host_browser", 0);
393
+ expect(
394
+ isToolActiveForContext(
395
+ "host_browser",
396
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
397
+ ),
398
+ ).toBe(false);
399
+ });
400
+
401
+ test("host_browser is NOT exposed for ios when no host_browser client is connected", () => {
402
+ mockClientCountByCapability.set("host_browser", 0);
403
+ expect(
404
+ isToolActiveForContext(
405
+ "host_browser",
406
+ makeCtx({ hasNoClient: false, transportInterface: "ios" }),
407
+ ),
408
+ ).toBe(false);
409
+ });
410
+
411
+ test("host_browser is NOT exposed when hasNoClient is true (no approval UI)", () => {
412
+ // hasNoClient gate: cross-client exception must not bypass this.
413
+ mockClientCountByCapability.set("host_browser", 1);
414
+ expect(
415
+ isToolActiveForContext(
416
+ "host_browser",
417
+ makeCtx({ hasNoClient: true, transportInterface: "web" }),
418
+ ),
419
+ ).toBe(false);
420
+ });
421
+
422
+ test("host_browser for macos transport is unaffected by the cross-client exception", () => {
423
+ // macos natively supports host_browser via host proxy — the
424
+ // supportsHostProxy check passes, so the cross-client branch is never
425
+ // reached.
426
+ mockClientCountByCapability.set("host_browser", 0);
427
+ expect(
428
+ isToolActiveForContext(
429
+ "host_browser",
430
+ makeCtx({ hasNoClient: false, transportInterface: "macos" }),
431
+ ),
432
+ ).toBe(true);
433
+ });
434
+
435
+ test("host_browser for chrome-extension transport is unaffected by the cross-client exception", () => {
436
+ // chrome-extension natively supports host_browser via its own
437
+ // executor (supportsHostProxy("chrome-extension", "host_browser")
438
+ // returns true), so the cross-client branch is never reached. The
439
+ // hasNoClient gate is also bypassed for chrome-extension transports
440
+ // because the extension provides its own approval UI.
441
+ mockClientCountByCapability.set("host_browser", 0);
442
+ expect(
443
+ isToolActiveForContext(
444
+ "host_browser",
445
+ makeCtx({ hasNoClient: true, transportInterface: "chrome-extension" }),
446
+ ),
447
+ ).toBe(true);
448
+ });
449
+
450
+ test("listClientsByCapability is queried with host_browser, not host_bash or host_file (per-capability invariant)", () => {
451
+ // Defense against any future regression that hardcodes a different
452
+ // capability in the cross-client check. Only host_browser-capable
453
+ // clients should satisfy host_browser exposure.
454
+ mockClientCountByCapability.set("host_bash", 1);
455
+ mockClientCountByCapability.set("host_file", 1);
456
+ mockClientCountByCapability.set("host_browser", 0);
457
+ expect(
458
+ isToolActiveForContext(
459
+ "host_browser",
460
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
461
+ ),
462
+ ).toBe(false);
463
+ });
464
+ });
465
+
361
466
  describe("HOST_TOOL_NAMES derivation", () => {
362
467
  test("HOST_TOOL_NAMES is derived from HOST_TOOL_TO_CAPABILITY", () => {
363
468
  // Sanity check: every tool in the names set has a capability mapping.
@@ -23,8 +23,9 @@ const loggerSpy = {
23
23
  warn: mock(() => {}),
24
24
  error: mock(() => {}),
25
25
  };
26
+ const getLoggerSpy = mock((_name: string) => loggerSpy);
26
27
  mock.module("../../util/logger.js", () => ({
27
- getLogger: () => loggerSpy,
28
+ getLogger: getLoggerSpy,
28
29
  }));
29
30
 
30
31
  mock.module("../../config/loader.js", () => ({
@@ -163,12 +164,13 @@ describe("createDaemonSkillHost", () => {
163
164
  expect(host.speakers).toBeDefined();
164
165
  });
165
166
 
166
- test("logger.get returns an object with the four severity methods", () => {
167
+ test("logger.get prefixes the scope with the skillId", () => {
167
168
  const log = host.logger.get("test-scope");
168
169
  log.debug("d", { k: "v" });
169
170
  log.info("i");
170
171
  log.warn("w");
171
172
  log.error("e");
173
+ expect(getLoggerSpy).toHaveBeenCalledWith("meet-join:test-scope");
172
174
  expect(loggerSpy.debug).toHaveBeenCalled();
173
175
  expect(loggerSpy.info).toHaveBeenCalled();
174
176
  expect(loggerSpy.warn).toHaveBeenCalled();
@@ -255,8 +257,12 @@ describe("createDaemonSkillHost", () => {
255
257
  });
256
258
  expect(handle).toBeDefined();
257
259
  expect(registerSkillRouteSpy).toHaveBeenCalled();
258
- host.registries.registerShutdownHook("test-hook", async () => {});
259
- expect(registerShutdownHookSpy).toHaveBeenCalled();
260
+ const hook = async () => {};
261
+ host.registries.registerShutdownHook("test-hook", hook);
262
+ expect(registerShutdownHookSpy).toHaveBeenCalledWith(
263
+ "meet-join:test-hook",
264
+ hook,
265
+ );
260
266
  });
261
267
 
262
268
  test("speakers.createTracker yields a concrete tracker instance", () => {
@@ -1,6 +1,6 @@
1
1
  import { loadConfig } from "../config/loader.js";
2
- import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
3
- import { getProvider, listProviders } from "../providers/registry.js";
2
+ import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
3
+ import { resolveDefaultProvider } from "../providers/connection-resolution.js";
4
4
  import type { Provider } from "../providers/types.js";
5
5
  import {
6
6
  APPROVAL_COPY_MAX_TOKENS,
@@ -79,15 +79,18 @@ const VALID_DISPOSITIONS: ReadonlySet<string> = new Set([
79
79
  export function createApprovalCopyGenerator(): ApprovalCopyGenerator {
80
80
  return async (context, options = {}) => {
81
81
  const config = loadConfig();
82
- let baseProvider: Provider;
83
- try {
84
- baseProvider = getProvider(config.llm.default.provider);
85
- } catch {
86
- return null;
87
- }
82
+ // Connection-aware default-provider resolution. Throws
83
+ // `ConnectionResolutionError` on hard config errors (missing /
84
+ // unknown / mismatched connection). Returns null on soft credential
85
+ // failures (vault miss, transient auth) — we treat null as "no
86
+ // provider available" and skip generating copy.
87
+ const baseProvider: Provider | null = await resolveDefaultProvider(config);
88
+ if (!baseProvider) return null;
88
89
  // Wrap so per-call `callSite` can route to an alternative provider
89
90
  // transport when `llm.callSites.<id>.provider` overrides the default.
90
- const provider = wrapWithCallSiteRouting(baseProvider);
91
+ // The `wrapWithCallSiteRouting` helper threads `config` through so the
92
+ // wrapper's per-call resolution is also connection-aware.
93
+ const provider = wrapWithCallSiteRouting(baseProvider, config);
91
94
 
92
95
  const fallbackText =
93
96
  options.fallbackText?.trim() || getFallbackMessage(context);
@@ -136,12 +139,19 @@ export function createApprovalCopyGenerator(): ApprovalCopyGenerator {
136
139
  export function createApprovalConversationGenerator(): ApprovalConversationGenerator {
137
140
  return async (context) => {
138
141
  const config = loadConfig();
139
- if (!listProviders().includes(config.llm.default.provider)) {
142
+ // Connection-aware default + per-call routing. `resolveDefaultProvider`
143
+ // throws `ConnectionResolutionError` on hard config errors (missing /
144
+ // unknown / mismatched connection) and returns null on soft credential
145
+ // failures (vault miss, transient auth) — we treat null as "no
146
+ // provider available" and throw a domain-specific error below. We do
147
+ // not pre-gate on `listProviders()` because the default provider lives
148
+ // behind a `provider_connection` and never appears in the registry's
149
+ // initialization-time provider list.
150
+ const baseProvider = await resolveDefaultProvider(config);
151
+ if (!baseProvider) {
140
152
  throw new Error("No provider available for approval conversation");
141
153
  }
142
- const provider = wrapWithCallSiteRouting(
143
- getProvider(config.llm.default.provider),
144
- );
154
+ const provider = wrapWithCallSiteRouting(baseProvider, config);
145
155
 
146
156
  const pendingDescription = context.pendingApprovals
147
157
  .map((p) => `- Request ${p.requestId}: tool "${p.toolName}"`)
@@ -212,19 +222,3 @@ export function createApprovalConversationGenerator(): ApprovalConversationGener
212
222
  return result;
213
223
  };
214
224
  }
215
-
216
- /**
217
- * Wrap a base Provider so per-call `callSite` metadata can route the actual
218
- * transport to a different provider when `llm.callSites.<id>.provider`
219
- * differs from the default. Without this wrapper, only request metadata
220
- * reflects the callSite — the HTTP transport stays bound to the default.
221
- */
222
- function wrapWithCallSiteRouting(base: Provider): Provider {
223
- return new CallSiteRoutingProvider(base, (name) => {
224
- try {
225
- return getProvider(name);
226
- } catch {
227
- return undefined;
228
- }
229
- });
230
- }
@@ -18,6 +18,7 @@ import { getConfig, invalidateConfigCache } from "../config/loader.js";
18
18
  import type { MemoryCleanupConfig } from "../config/schemas/memory-lifecycle.js";
19
19
  import { resetCleanupScheduleThrottle } from "../memory/cleanup-schedule-state.js";
20
20
  import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
21
+ import { invalidateLlmRequestLogSourceCache } from "../memory/llm-request-log-source.js";
21
22
  import { initializeProviders } from "../providers/registry.js";
22
23
  import { handleCancelSignal } from "../signals/cancel.js";
23
24
  import { handleConversationUndoSignal } from "../signals/conversation-undo.js";
@@ -140,6 +141,7 @@ export class ConfigWatcher {
140
141
  return false;
141
142
  }
142
143
  clearEmbeddingBackendCache();
144
+ invalidateLlmRequestLogSourceCache();
143
145
  // If cleanup retention settings changed, reset the cleanup scheduler
144
146
  // throttle so the next worker tick re-enqueues jobs with the new values
145
147
  // instead of waiting out the remaining enqueueIntervalMs (default 6h).