@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
@@ -4,6 +4,7 @@
4
4
  * can delegate without exposing its full surface.
5
5
  */
6
6
 
7
+ import { getConfig } from "../config/loader.js";
7
8
  import { createContextSummaryMessage } from "../context/window-manager.js";
8
9
  import type { EventBus } from "../events/bus.js";
9
10
  import type { AssistantDomainEvents } from "../events/domain-events.js";
@@ -16,6 +17,7 @@ import {
16
17
  type MessageRow,
17
18
  } from "../memory/conversation-crud.js";
18
19
  import { enqueueMemoryJob } from "../memory/jobs-store.js";
20
+ import { enqueueMemoryRetrospectiveIfEnabled } from "../memory/memory-retrospective-enqueue.js";
19
21
  import type { PermissionPrompter } from "../permissions/prompter.js";
20
22
  import type { SecretPrompter } from "../permissions/secret-prompter.js";
21
23
  import type { ContentBlock, Message } from "../providers/types.js";
@@ -182,6 +184,7 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
182
184
  ctx.contextCompactedAt = conv?.contextCompactedAt ?? null;
183
185
  }
184
186
 
187
+ const personalMemoryAllowed = !isUntrustedTrustClass(trustClass);
185
188
  const parsedMessages: Message[] = dbMessages
186
189
  .slice(ctx.contextCompactedMessageCount)
187
190
  .map((m, index, arr) => {
@@ -214,7 +217,8 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
214
217
  // shape right-to-left, since each prepend shifts previously-
215
218
  // prepended blocks one slot right:
216
219
  // [<workspace>, <turn_context>, <NOW.md>, <memory __injected>,
217
- // <system_reminder>, <knowledge_base>, ...original]
220
+ // <memory>\n…</memory>, <system_reminder>, <knowledge_base>,
221
+ // ...original]
218
222
  //
219
223
  // Persisted non-tail rows rehydrate the full set so Anthropic's
220
224
  // prefix cache keeps matching msg[0] across daemon restarts and
@@ -237,15 +241,37 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
237
241
  ];
238
242
  }
239
243
 
244
+ // The v2 static memory block (essentials/threads/recent/buffer
245
+ // wrapped in `<memory>…</memory>`) carries personal user memory.
246
+ // Trust-gated to mirror `shouldExposePersonalMemory` at injection
247
+ // time — untrusted-actor views must not read persisted personal
248
+ // memory back through metadata. Skipped on the tail row because
249
+ // the next turn re-injects fresh content on full-mode turns.
250
+ if (
251
+ !isTail &&
252
+ personalMemoryAllowed &&
253
+ typeof meta.memoryV2StaticBlock === "string"
254
+ ) {
255
+ content = [
256
+ { type: "text" as const, text: meta.memoryV2StaticBlock },
257
+ ...content,
258
+ ];
259
+ }
260
+
240
261
  // Memory remains rehydrated on all rows (existing behavior).
241
262
  // Strip any pre-existing wrapper before re-wrapping so historical
242
263
  // rows persisted with the wrapper (v2 path before the
243
264
  // injectedBlockText contract was unified with v1's unwrapped form)
244
- // don't render double-wrapped after rehydrate.
265
+ // don't render double-wrapped after rehydrate. Only unwrap when
266
+ // the full <memory>...</memory> pair is present so we don't mutate
267
+ // legitimate unwrapped payloads that happen to start with
268
+ // "<memory>\n" or end with "\n</memory>".
245
269
  if (typeof meta.memoryInjectedBlock === "string") {
246
- const inner = meta.memoryInjectedBlock
247
- .replace(/^<memory>\n/, "")
248
- .replace(/\n<\/memory>$/, "");
270
+ const block = meta.memoryInjectedBlock;
271
+ const inner =
272
+ block.startsWith("<memory>\n") && block.endsWith("\n</memory>")
273
+ ? block.slice("<memory>\n".length, -"\n</memory>".length)
274
+ : block;
249
275
  content = [
250
276
  {
251
277
  type: "text" as const,
@@ -373,16 +399,29 @@ export function disposeConversation(ctx: DisposeContext): void {
373
399
  // Best-effort — don't block conversation disposal
374
400
  }
375
401
  if (!isAutoAnalysis) {
402
+ // Suppress v1 graph extraction when memory v2 is active — v2 reads
403
+ // from buffer.md and concept pages, so the v1 graph would be stale
404
+ // data nobody consumes. Mirrors the gate applied in `indexer.ts`
405
+ // for the per-message indexing path. Fail open to v1 if config
406
+ // can't load, since the worker handler also short-circuits.
407
+ let v2Enabled = false;
376
408
  try {
377
- enqueueMemoryJob("graph_extract", {
378
- conversationId: ctx.conversationId,
379
- scopeId: "default",
380
- ...(ctx.activeContextNodeIds?.length
381
- ? { activeContextNodeIds: ctx.activeContextNodeIds }
382
- : {}),
383
- });
409
+ v2Enabled = getConfig().memory.v2.enabled;
384
410
  } catch {
385
- // Best-effort — don't block conversation disposal
411
+ // Best-effort — fall through to legacy v1 enqueue
412
+ }
413
+ if (!v2Enabled) {
414
+ try {
415
+ enqueueMemoryJob("graph_extract", {
416
+ conversationId: ctx.conversationId,
417
+ scopeId: "default",
418
+ ...(ctx.activeContextNodeIds?.length
419
+ ? { activeContextNodeIds: ctx.activeContextNodeIds }
420
+ : {}),
421
+ });
422
+ } catch {
423
+ // Best-effort — don't block conversation disposal
424
+ }
386
425
  }
387
426
  }
388
427
 
@@ -397,6 +436,22 @@ export function disposeConversation(ctx: DisposeContext): void {
397
436
  } catch {
398
437
  // Best-effort — don't block conversation disposal
399
438
  }
439
+
440
+ try {
441
+ // Memory-retrospective lifecycle safety-net. The periodic triggers
442
+ // (interval / message_count / pre-compaction) handle the common
443
+ // path; lifecycle catches the gap between the last interval fire
444
+ // and conversation eviction. The job's `no_new_messages` early
445
+ // return makes this a cheap no-op when the periodic path already
446
+ // covered things. `enqueueMemoryRetrospectiveIfEnabled` has its
447
+ // own internal recursion guard.
448
+ enqueueMemoryRetrospectiveIfEnabled({
449
+ conversationId: ctx.conversationId,
450
+ trigger: "lifecycle",
451
+ });
452
+ } catch {
453
+ // Best-effort — don't block conversation disposal
454
+ }
400
455
  }
401
456
 
402
457
  abortConversation(
@@ -12,6 +12,7 @@ import {
12
12
  createUserMessage,
13
13
  } from "../agent/message-types.js";
14
14
  import {
15
+ type InterfaceId,
15
16
  parseChannelId,
16
17
  parseInterfaceId,
17
18
  type TurnChannelContext,
@@ -179,7 +180,9 @@ export interface ProcessConversationContext {
179
180
  statusText?: string,
180
181
  ): void;
181
182
  /** Force context compaction regardless of threshold/cooldown. */
182
- forceCompact(): Promise<ContextWindowResult>;
183
+ forceCompact(options?: {
184
+ targetInputTokensOverride?: number;
185
+ }): Promise<ContextWindowResult>;
183
186
  /** Set transport-derived hints for the conversation. */
184
187
  setTransportHints(hints: string[] | undefined): void;
185
188
  /** IANA timezone reported by the active client for the current turn. */
@@ -195,6 +198,13 @@ export interface ProcessConversationContext {
195
198
  applyClientTimezoneFromTransport(
196
199
  transport: ConversationTransportMetadata,
197
200
  ): void;
201
+ /**
202
+ * Instantiate host proxies for capabilities that have become reachable
203
+ * mid-queue (e.g. a macOS client connected after a web turn was enqueued
204
+ * without a proxy). Called from drain paths before preactivation so skills
205
+ * are only activated when the proxy that services them is present.
206
+ */
207
+ ensureHostProxiesForTurn(sourceInterface: InterfaceId | undefined): void;
198
208
  }
199
209
 
200
210
  function resolveQueuedTurnContext(
@@ -432,19 +442,19 @@ async function drainSingleMessage(
432
442
  conversation.applyClientTimezoneFromTransport(next.transport);
433
443
  }
434
444
 
435
- // Re-preactivate host-proxy skills for interactive desktop turns. The
436
- // dequeue path reset `preactivatedSkillIds` above, so without these
437
- // re-adds the relevant skill tools wouldn't be projected to the LLM
438
- // for queued messages 2+ even though the underlying proxies (HostCuProxy,
439
- // HostAppControlProxy) are still attached. Mirrors the per-message
440
- // instantiation block in `conversation-routes.ts` / `process-message.ts`.
445
+ // Re-attach and re-preactivate host-proxy skills for interactive turns.
446
+ // The dequeue path reset `preactivatedSkillIds` above; without these
447
+ // re-adds the relevant skill tools won't be projected to the LLM for
448
+ // queued messages 2+. Also instantiates proxies that may not have been
449
+ // present when the message was first enqueued (e.g. a macOS client
450
+ // connects between enqueue and drain). Mirrors the per-message block in
451
+ // `conversation-routes.ts` / `process-message.ts`.
441
452
  if (next.isInteractive !== false) {
442
453
  const interfaceCtx =
443
454
  queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
444
- preactivateHostProxySkills(
445
- conversation,
446
- interfaceCtx?.userMessageInterface,
447
- );
455
+ const sourceInterface = interfaceCtx?.userMessageInterface;
456
+ conversation.ensureHostProxiesForTurn(sourceInterface);
457
+ preactivateHostProxySkills(conversation, sourceInterface);
448
458
  }
449
459
 
450
460
  // Snapshot persona context at turn start so later tool turns can't pick up
@@ -628,7 +638,9 @@ async function drainSingleMessage(
628
638
  "assistant_turn",
629
639
  next.requestId,
630
640
  );
631
- const result = await conversation.forceCompact();
641
+ const result = await conversation.forceCompact({
642
+ targetInputTokensOverride: slashResult.targetInputTokensOverride,
643
+ });
632
644
  const responseText = formatCompactResult(result);
633
645
 
634
646
  const assistantMsg = createAssistantMessage(responseText);
@@ -875,15 +887,14 @@ async function drainBatch(
875
887
  conversation.applyClientTimezoneFromTransport(head.transport);
876
888
  }
877
889
 
878
- // Re-preactivate host-proxy skills for interactive desktop turns.
890
+ // Re-attach and re-preactivate host-proxy skills for interactive turns.
879
891
  // Mirrors the single-message path exactly — sourced from `head`.
880
892
  if (head.isInteractive !== false) {
881
893
  const interfaceCtx =
882
894
  queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
883
- preactivateHostProxySkills(
884
- conversation,
885
- interfaceCtx?.userMessageInterface,
886
- );
895
+ const sourceInterface = interfaceCtx?.userMessageInterface;
896
+ conversation.ensureHostProxiesForTurn(sourceInterface);
897
+ preactivateHostProxySkills(conversation, sourceInterface);
887
898
  }
888
899
 
889
900
  // Snapshot persona context at turn start so later tool turns can't pick up
@@ -1314,7 +1325,11 @@ export async function processMessage(
1314
1325
  );
1315
1326
  conversation.messages.push(assistantMsg);
1316
1327
 
1317
- onEvent({ type: "assistant_text_delta", text: replyText });
1328
+ onEvent({
1329
+ type: "assistant_text_delta",
1330
+ text: replyText,
1331
+ conversationId: conversation.conversationId,
1332
+ });
1318
1333
  onEvent({
1319
1334
  type: "message_complete",
1320
1335
  conversationId: conversation.conversationId,
@@ -1474,7 +1489,9 @@ export async function processMessage(
1474
1489
  "assistant_turn",
1475
1490
  requestId,
1476
1491
  );
1477
- const result = await conversation.forceCompact();
1492
+ const result = await conversation.forceCompact({
1493
+ targetInputTokensOverride: slashResult.targetInputTokensOverride,
1494
+ });
1478
1495
  const responseText = formatCompactResult(result);
1479
1496
 
1480
1497
  const assistantMsg = createAssistantMessage(responseText);
@@ -1641,12 +1641,15 @@ const RUNTIME_INJECTION_PREFIXES = [
1641
1641
  // blocks persist in history so the assistant retains temporal/actor grounding.
1642
1642
  "<memory_context __injected>",
1643
1643
  "<memory_context>", // backward-compat: strip legacy blocks from pre-__injected history
1644
- // NOTE: `<memory>` blocks (both the dynamic activation block from
1645
- // `injectTextBlock` and the static `memory-v2-static` injector) are
1646
- // intentionally NOT stripped memory injections persist in history so
1647
- // the assistant retains intra-turn memory state. The activation pipeline
1648
- // dedupes via `everInjected`, and compaction handles aggregate growth, so
1644
+ // The static `memory-v2-static` block (opens `<memory>\n…`) IS stripped
1645
+ // so each compaction re-injects the freshest essentials/threads/recent/
1646
+ // buffer view, matching the `<knowledge_base>` cadence. The dynamic
1647
+ // activation block (opens `<memory __injected>…`) is intentionally NOT
1648
+ // stripped `startsWith("<memory>\n")` does not match it so per-turn
1649
+ // memory activations persist in history. The activation pipeline dedupes
1650
+ // via `everInjected`, and compaction handles aggregate growth, so
1649
1651
  // accumulation does not cause unbounded context growth.
1652
+ "<memory>\n",
1650
1653
  "<voice_call_control>",
1651
1654
  "<workspace_top_level>", // backward-compat: strip legacy workspace blocks
1652
1655
  // NOTE: <workspace> is intentionally NOT stripped — workspace context
@@ -1736,6 +1739,7 @@ export interface RuntimeInjectionBlocks {
1736
1739
  workspaceBlock?: string;
1737
1740
  nowScratchpadBlock?: string;
1738
1741
  pkbContextBlock?: string;
1742
+ memoryV2StaticBlock?: string;
1739
1743
  /**
1740
1744
  * Composed output of every plugin-registered {@link Injector}, concatenated
1741
1745
  * in ascending `order`. Empty string when every injector opted out (returned
@@ -2153,6 +2157,7 @@ export async function applyRuntimeInjections(
2153
2157
  let nowScratchpadCaptured: string | undefined;
2154
2158
  let pkbContextCaptured: string | undefined;
2155
2159
  let pkbSystemReminderCaptured: string | undefined;
2160
+ let memoryV2StaticCaptured: string | undefined;
2156
2161
  const initialTail = runMessages[runMessages.length - 1];
2157
2162
  const initialTailIsUser = !!initialTail && initialTail.role === "user";
2158
2163
  if (initialTailIsUser) {
@@ -2173,6 +2178,9 @@ export async function applyRuntimeInjections(
2173
2178
  case "pkb-reminder":
2174
2179
  pkbSystemReminderCaptured = block.text;
2175
2180
  break;
2181
+ case "memory-v2-static":
2182
+ memoryV2StaticCaptured = block.text;
2183
+ break;
2176
2184
  }
2177
2185
  }
2178
2186
  }
@@ -2354,6 +2362,7 @@ export async function applyRuntimeInjections(
2354
2362
  workspaceBlock: workspaceCaptured,
2355
2363
  nowScratchpadBlock: nowScratchpadCaptured,
2356
2364
  pkbContextBlock: pkbContextCaptured,
2365
+ memoryV2StaticBlock: memoryV2StaticCaptured,
2357
2366
  injectorChainBlock,
2358
2367
  },
2359
2368
  };
@@ -1,6 +1,12 @@
1
1
  import type { InterfaceId } from "../channels/types.js";
2
2
  import { resolveEffectiveContextWindow } from "../config/llm-context-resolution.js";
3
- import { getConfig } from "../config/loader.js";
3
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
4
+ import {
5
+ getConfig,
6
+ invalidateConfigCache,
7
+ loadRawConfig,
8
+ saveRawConfig,
9
+ } from "../config/loader.js";
4
10
  import { getConversationOverrideProfile } from "../memory/conversation-crud.js";
5
11
  import { PROVIDER_CATALOG } from "../providers/model-catalog.js";
6
12
  import { getConfiguredProviders } from "../providers/provider-availability.js";
@@ -8,7 +14,43 @@ import { getConfiguredProviders } from "../providers/provider-availability.js";
8
14
  export type SlashResolution =
9
15
  | { kind: "passthrough"; content: string }
10
16
  | { kind: "unknown"; message: string }
11
- | { kind: "compact" };
17
+ | { kind: "compact"; targetInputTokensOverride?: number };
18
+
19
+ const COMPACT_USAGE_HINT =
20
+ "Usage: `/compact [<tokens>]` (e.g. `/compact 30000`, `/compact 30k`, `/compact 1m`).";
21
+
22
+ type CompactParse =
23
+ | { kind: "compact"; targetInputTokensOverride?: number }
24
+ | { kind: "unknown"; message: string };
25
+
26
+ const TOKEN_COUNT_PATTERN = /^(\d+(?:\.\d+)?)([km])?$/i;
27
+ const COMPACT_COMMAND_PATTERN = /^\/compact(?:\s+(.+?))?\s*$/i;
28
+
29
+ function parseTokenCount(input: string): number | null {
30
+ const match = input.match(TOKEN_COUNT_PATTERN);
31
+ if (!match) return null;
32
+ const value = Number.parseFloat(match[1]);
33
+ if (!Number.isFinite(value) || value <= 0) return null;
34
+ const suffix = match[2]?.toLowerCase();
35
+ const multiplier = suffix === "m" ? 1_000_000 : suffix === "k" ? 1_000 : 1;
36
+ const tokens = Math.floor(value * multiplier);
37
+ return tokens > 0 ? tokens : null;
38
+ }
39
+
40
+ function parseCompactCommand(trimmed: string): CompactParse | null {
41
+ const match = trimmed.match(COMPACT_COMMAND_PATTERN);
42
+ if (!match) return null;
43
+ const rest = match[1]?.trim();
44
+ if (!rest) return { kind: "compact" };
45
+ const tokens = parseTokenCount(rest);
46
+ if (tokens == null) {
47
+ return {
48
+ kind: "unknown",
49
+ message: `Unrecognized argument to \`/compact\`: \`${rest}\`. ${COMPACT_USAGE_HINT}`,
50
+ };
51
+ }
52
+ return { kind: "compact", targetInputTokensOverride: tokens };
53
+ }
12
54
 
13
55
  // ── /context and /status commands ────────────────────────────────────
14
56
 
@@ -71,10 +113,125 @@ const DEPRECATED_MODEL_SHORTCUTS = new Set([
71
113
  "grok-multi",
72
114
  ]);
73
115
 
116
+ // ── /model command (inference profile switcher) ──────────────────────
117
+
118
+ type ModelCommandParse =
119
+ | { kind: "list" }
120
+ | { kind: "switch"; profileName: string };
121
+
122
+ /**
123
+ * Parse `/model` and `/model <name>` forms. Returns `null` for any input
124
+ * that isn't a `/model` invocation (so the caller can fall through).
125
+ */
126
+ function parseModelCommand(trimmed: string): ModelCommandParse | null {
127
+ if (trimmed === "/model") return { kind: "list" };
128
+ if (!trimmed.startsWith("/model ")) return null;
129
+ const rest = trimmed.slice("/model ".length).trim();
130
+ if (rest.length === 0) return { kind: "list" };
131
+ return { kind: "switch", profileName: rest };
132
+ }
133
+
134
+ function orderedProfileNames(
135
+ profiles: Record<string, { label?: string; description?: string; status?: "active" | "disabled" }>,
136
+ profileOrder: readonly string[] | undefined,
137
+ ): string[] {
138
+ const order = profileOrder ?? [];
139
+ const seen = new Set<string>();
140
+ const ordered: string[] = [];
141
+ for (const name of order) {
142
+ if (profiles[name] != null && !seen.has(name)) {
143
+ ordered.push(name);
144
+ seen.add(name);
145
+ }
146
+ }
147
+ const tail = Object.keys(profiles)
148
+ .filter((n) => !seen.has(n))
149
+ .sort();
150
+ return [...ordered, ...tail];
151
+ }
152
+
153
+ async function resolveModelCommand(
154
+ parse: ModelCommandParse,
155
+ ): Promise<SlashResolution> {
156
+ const config = getConfig();
157
+ const profiles = (config.llm.profiles ?? {}) as Record<
158
+ string,
159
+ { label?: string; description?: string; status?: "active" | "disabled" }
160
+ >;
161
+ const profileNames = orderedProfileNames(profiles, config.llm.profileOrder);
162
+ const activeProfile = config.llm.activeProfile;
163
+
164
+ if (parse.kind === "list") {
165
+ if (profileNames.length === 0) {
166
+ return {
167
+ kind: "unknown",
168
+ message:
169
+ "No inference profiles are defined. Use **Settings → Models & Services** to create one.",
170
+ };
171
+ }
172
+ const lines = ["Inference profiles:\n"];
173
+ for (const name of profileNames) {
174
+ const profile = profiles[name];
175
+ const label = profile.label ?? name;
176
+ const isCurrent = name === activeProfile;
177
+ const isDisabled = profile.status === "disabled";
178
+ const marker = isCurrent ? " **[current]**" : "";
179
+ const disabled = isDisabled ? " *(disabled)*" : "";
180
+ const description = profile.description ? ` — ${profile.description}` : "";
181
+ lines.push(` - \`${name}\` (${label})${marker}${disabled}${description}`);
182
+ }
183
+ lines.push("\nSwitch with `/model <name>`.");
184
+ return { kind: "unknown", message: lines.join("\n") };
185
+ }
186
+
187
+ const target = parse.profileName;
188
+ if (!(target in profiles)) {
189
+ const available = profileNames.map((n) => `\`${n}\``).join(", ");
190
+ const hint = available.length > 0 ? ` Available: ${available}.` : "";
191
+ return {
192
+ kind: "unknown",
193
+ message: `Profile \`${target}\` not found.${hint}`,
194
+ };
195
+ }
196
+ if (profiles[target].status === "disabled") {
197
+ return {
198
+ kind: "unknown",
199
+ message: `Profile \`${target}\` is disabled. Enable it in **Settings → Models & Services** first.`,
200
+ };
201
+ }
202
+ if (target === activeProfile) {
203
+ const label = profiles[target].label ?? target;
204
+ return {
205
+ kind: "unknown",
206
+ message: `Already using profile \`${target}\` (${label}).`,
207
+ };
208
+ }
209
+
210
+ // Write `llm.activeProfile` directly to the raw config file. We invalidate
211
+ // the in-process cache so the very next `getConfig()` reflects the switch;
212
+ // the file watcher will also pick this up but its debounce can lag a tick.
213
+ const raw = loadRawConfig();
214
+ const llm: Record<string, unknown> =
215
+ raw.llm != null && typeof raw.llm === "object" && !Array.isArray(raw.llm)
216
+ ? (raw.llm as Record<string, unknown>)
217
+ : {};
218
+ llm.activeProfile = target;
219
+ raw.llm = llm;
220
+ saveRawConfig(raw);
221
+ invalidateConfigCache();
222
+
223
+ const label = profiles[target].label ?? target;
224
+ return {
225
+ kind: "unknown",
226
+ message: `Switched to profile \`${target}\` (${label}).`,
227
+ };
228
+ }
229
+
74
230
  // ── /models command ──────────────────────────────────────────────────
75
231
 
76
232
  async function resolveModelList(): Promise<SlashResolution> {
77
233
  const config = getConfig();
234
+ const resolvedMainAgent = resolveCallSiteConfig("mainAgent", config.llm);
78
235
  const configuredProviders = new Set<string>(await getConfiguredProviders());
79
236
 
80
237
  const lines = ["Available models:\n"];
@@ -89,8 +246,8 @@ async function resolveModelList(): Promise<SlashResolution> {
89
246
  lines.push(`**${providerName}** ${status}`);
90
247
  for (const { id, displayName } of models) {
91
248
  const isCurrent =
92
- config.llm.default.provider === provider &&
93
- config.llm.default.model === id;
249
+ resolvedMainAgent.provider === provider &&
250
+ resolvedMainAgent.model === id;
94
251
  const current = isCurrent ? " **[current]**" : "";
95
252
  lines.push(` - ${displayName} (\`${id}\`)${current}`);
96
253
  }
@@ -146,6 +303,7 @@ function resolveCommandsList(context?: SlashContext): string[] {
146
303
  if (context) {
147
304
  fallbackLines.push("/context — Show conversation context usage");
148
305
  }
306
+ fallbackLines.push("/model — List or switch inference profile");
149
307
  fallbackLines.push("/models — List all available models");
150
308
  if (context) {
151
309
  fallbackLines.push("/status — Show conversation status and context usage");
@@ -158,6 +316,7 @@ function resolveCommandsList(context?: SlashContext): string[] {
158
316
  "/commands — List all available commands",
159
317
  "/compact — Force context compaction immediately",
160
318
  "/context — Show conversation context usage",
319
+ "/model — List or switch inference profile",
161
320
  "/models — List all available models",
162
321
  "/status — Show conversation status and context usage",
163
322
  "/btw — Ask a side question while the assistant is working",
@@ -170,6 +329,7 @@ function resolveCommandsList(context?: SlashContext): string[] {
170
329
  "/commands — List all available commands",
171
330
  "/compact — Force context compaction immediately",
172
331
  "/context — Show conversation context usage",
332
+ "/model — List or switch inference profile",
173
333
  "/models — List all available models",
174
334
  "/status — Show conversation status and context usage",
175
335
  "/btw — Ask a side question while the assistant is working",
@@ -181,6 +341,7 @@ function resolveCommandsList(context?: SlashContext): string[] {
181
341
  "/commands — List all available commands",
182
342
  "/compact — Force context compaction immediately",
183
343
  "/context — Show conversation context usage",
344
+ "/model — List or switch inference profile",
184
345
  "/models — List all available models",
185
346
  "/status — Show conversation status and context usage",
186
347
  "/btw — Ask a side question while the assistant is working",
@@ -200,10 +361,7 @@ export function classifySlash(
200
361
  content: string,
201
362
  ): "passthrough" | "compact" | "unknown" {
202
363
  const trimmed = content.trim();
203
- if (
204
- trimmed === "/model" ||
205
- (trimmed.startsWith("/model ") && trimmed !== "/models")
206
- ) {
364
+ if (parseModelCommand(trimmed) != null) {
207
365
  return "unknown";
208
366
  }
209
367
  const shortcutMatch = trimmed.match(/^\/([a-z0-9-]+)(\s|$)/i);
@@ -214,7 +372,8 @@ export function classifySlash(
214
372
  return "unknown";
215
373
  }
216
374
  if (trimmed === "/models") return "unknown";
217
- if (trimmed === "/compact") return "compact";
375
+ const compactParse = parseCompactCommand(trimmed);
376
+ if (compactParse) return compactParse.kind;
218
377
  if (trimmed === "/context") return "unknown";
219
378
  if (trimmed === "/status") return "unknown";
220
379
  if (trimmed === "/commands") return "unknown";
@@ -230,17 +389,11 @@ export async function resolveSlash(
230
389
  content: string,
231
390
  context?: SlashContext,
232
391
  ): Promise<SlashResolution> {
233
- // Handle deprecated model-switching commands direct users to Settings
392
+ // Handle `/model`list profiles (no arg) or switch active profile.
234
393
  const trimmed = content.trim();
235
- if (
236
- trimmed === "/model" ||
237
- (trimmed.startsWith("/model ") && trimmed !== "/models")
238
- ) {
239
- return {
240
- kind: "unknown",
241
- message:
242
- "The `/model` command has been removed. Use **Settings → Models & Services** to change your model and provider.",
243
- };
394
+ const modelParse = parseModelCommand(trimmed);
395
+ if (modelParse != null) {
396
+ return await resolveModelCommand(modelParse);
244
397
  }
245
398
 
246
399
  // Reject deprecated provider shortcut commands (/opus, /sonnet, /haiku, etc.)
@@ -260,10 +413,9 @@ export async function resolveSlash(
260
413
  return await resolveModelList();
261
414
  }
262
415
 
263
- // Handle /compact command
264
- if (trimmed === "/compact") {
265
- return { kind: "compact" };
266
- }
416
+ // Handle /compact command (with optional `<tokens>` override).
417
+ const compactParse = parseCompactCommand(trimmed);
418
+ if (compactParse) return compactParse;
267
419
 
268
420
  // Handle /context and legacy /status commands
269
421
  if (trimmed === "/context" || trimmed === "/status") {
@@ -14,12 +14,13 @@
14
14
  * shared rate-limit timestamps, broadcast).
15
15
  */
16
16
 
17
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
17
18
  import { getConfig } from "../config/loader.js";
18
19
  import type { CesClient } from "../credential-execution/client.js";
19
20
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
20
- import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
21
+ import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
22
+ import { resolveDefaultProvider } from "../providers/connection-resolution.js";
21
23
  import { RateLimitProvider } from "../providers/ratelimit.js";
22
- import { getProvider } from "../providers/registry.js";
23
24
  import { getSubagentManager } from "../subagent/index.js";
24
25
  import { getSandboxWorkingDir } from "../util/platform.js";
25
26
  import { Conversation } from "./conversation.js";
@@ -222,14 +223,20 @@ export async function getOrCreateConversation(
222
223
 
223
224
  const createPromise = (async () => {
224
225
  const config = getConfig();
225
- let provider = getProvider(config.llm.default.provider);
226
- provider = new CallSiteRoutingProvider(provider, (name) => {
227
- try {
228
- return getProvider(name);
229
- } catch {
230
- return undefined;
231
- }
232
- });
226
+ // Connection-aware default-provider resolution. Throws
227
+ // `ConnectionResolutionError` when the default profile's
228
+ // `provider_connection` is unset / unknown / mismatched (config
229
+ // bugs). Returns null on soft credential failures (handled below
230
+ // as "default provider not registered").
231
+ const baseProvider = await resolveDefaultProvider(config);
232
+ if (!baseProvider) {
233
+ throw new Error(
234
+ `Conversation: default provider '${resolveCallSiteConfig("mainAgent", config.llm).provider}' is not registered`,
235
+ );
236
+ }
237
+ // Per-call `callSite` routing layered on top, with connection-awareness
238
+ // for alternate profiles (matches the canonical dispatch path).
239
+ let provider = wrapWithCallSiteRouting(baseProvider, config);
233
240
  const { rateLimit } = config;
234
241
  if (rateLimit.maxRequestsPerMinute > 0) {
235
242
  provider = new RateLimitProvider(