@vellumai/assistant 0.6.4 → 0.6.5

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 (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -24,7 +24,7 @@ import type {
24
24
  } from "../channels/types.js";
25
25
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
26
26
  import { getConfig } from "../config/loader.js";
27
- import type { Speed } from "../config/schemas/inference.js";
27
+ import type { LLMCallSite, Speed } from "../config/schemas/llm.js";
28
28
  import {
29
29
  ContextWindowManager,
30
30
  type ContextWindowResult,
@@ -47,6 +47,7 @@ import { getHookManager } from "../hooks/manager.js";
47
47
  import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
48
48
  import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
49
49
  import {
50
+ getConversationOriginChannel,
50
51
  updateConversationContextWindow,
51
52
  updateConversationHostAccess,
52
53
  } from "../memory/conversation-crud.js";
@@ -62,19 +63,22 @@ import {
62
63
  } from "../permissions/v2-consent-policy.js";
63
64
  import { resolvePersonaContext } from "../prompts/persona-resolver.js";
64
65
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
65
- import { resolveModelIntent } from "../providers/model-intents.js";
66
- import type { Message, ModelIntent } from "../providers/types.js";
66
+ import type { Message } from "../providers/types.js";
67
67
  import type { Provider } from "../providers/types.js";
68
68
  import type { TrustClass } from "../runtime/actor-trust-resolver.js";
69
69
  import type { AuthContext } from "../runtime/auth/types.js";
70
70
  import * as approvalOverrides from "../runtime/conversation-approval-overrides.js";
71
+ import type { InteractiveUiResult } from "../runtime/interactive-ui.js";
71
72
  import * as pendingInteractions from "../runtime/pending-interactions.js";
72
73
  import { ToolExecutor } from "../tools/executor.js";
73
74
  import type { OnboardingContext } from "../types/onboarding-context.js";
74
75
  import type { AbortReason } from "../util/abort-reasons.js";
75
76
  import { getLogger } from "../util/logger.js";
76
77
  import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
77
- import { runAgentLoopImpl } from "./conversation-agent-loop.js";
78
+ import {
79
+ runAgentLoopImpl,
80
+ trackCompactionOutcome,
81
+ } from "./conversation-agent-loop.js";
78
82
  import type { HistoryConversationContext } from "./conversation-history.js";
79
83
  import {
80
84
  regenerate as regenerateImpl,
@@ -190,6 +194,19 @@ export class Conversation {
190
194
  /** @internal */ contextWindowManager: ContextWindowManager;
191
195
  /** @internal */ contextCompactedMessageCount = 0;
192
196
  /** @internal */ contextCompactedAt: number | null = null;
197
+ /**
198
+ * Tracks consecutive compaction failures (summary LLM call threw). In-memory
199
+ * only — resets to 0 on process restart, which is the intended "one free
200
+ * retry after restart" behavior. Reset to 0 on any successful compaction.
201
+ */
202
+ /** @internal */ consecutiveCompactionFailures = 0;
203
+ /**
204
+ * When the circuit breaker is open, this timestamp (ms since epoch) marks
205
+ * when auto-compaction is allowed to resume. Set to `Date.now() + 1h` after
206
+ * 3 consecutive failures; cleared on a successful compaction. User-initiated
207
+ * compaction (`force: true`) bypasses the breaker regardless.
208
+ */
209
+ /** @internal */ compactionCircuitOpenUntil: number | null = null;
193
210
  /** @internal */ currentRequestId?: string;
194
211
  /** @internal */ hasNoClient = false;
195
212
  /** @internal */ isSubagent = false;
@@ -238,6 +255,7 @@ export class Conversation {
238
255
  languageCode?: string;
239
256
  };
240
257
  /** @internal */ surfaceActionRequestIds = new Set<string>();
258
+ /** @internal */ approvedViaPromptThisTurn = false;
241
259
  /** @internal */ pendingSurfaceActions = new Map<
242
260
  string,
243
261
  { surfaceType: SurfaceType }
@@ -265,6 +283,28 @@ export class Conversation {
265
283
  string,
266
284
  Record<string, unknown>
267
285
  >();
286
+ /**
287
+ * Pending standalone UI requests keyed by surfaceId.
288
+ * Daemon-driven surfaces that block the caller until user response or timeout.
289
+ * @internal
290
+ */
291
+ pendingStandaloneSurfaces = new Map<
292
+ string,
293
+ {
294
+ resolve: (result: InteractiveUiResult) => void;
295
+ timer: ReturnType<typeof setTimeout>;
296
+ surfaceType: SurfaceType;
297
+ }
298
+ >();
299
+ /**
300
+ * Short-lived tombstone set of recently-completed standalone surface IDs.
301
+ * Prevents late client actions from falling through to the LLM path.
302
+ * @internal
303
+ */
304
+ recentlyCompletedStandaloneSurfaces = new Map<
305
+ string,
306
+ ReturnType<typeof setTimeout>
307
+ >();
268
308
  /** @internal */ broadcastToAllClients?: (msg: ServerMessage) => void;
269
309
  /** @internal */ withSurface = createSurfaceMutex();
270
310
  /** @internal */ currentTurnSurfaces: Array<{
@@ -338,7 +378,6 @@ export class Conversation {
338
378
  sharedCesClient?: CesClient,
339
379
  speedOverride?: Speed,
340
380
  cacheTtl?: "5m" | "1h",
341
- modelIntent?: ModelIntent,
342
381
  modelOverride?: string,
343
382
  ) {
344
383
  this.conversationId = conversationId;
@@ -386,7 +425,10 @@ export class Conversation {
386
425
  );
387
426
  }
388
427
  });
389
- this.secretPrompter = new SecretPrompter(sendToClient);
428
+ this.secretPrompter = new SecretPrompter(
429
+ sendToClient,
430
+ broadcastToAllClients,
431
+ );
390
432
 
391
433
  // Register watch/call notifiers (reads ctx properties lazily)
392
434
  registerConversationNotifiers(conversationId, this);
@@ -424,7 +466,7 @@ export class Conversation {
424
466
  );
425
467
 
426
468
  const config = getConfig();
427
- this.streamThinking = config.thinking.streamThinking ?? false;
469
+ this.streamThinking = config.llm.default.thinking.streamThinking ?? false;
428
470
 
429
471
  // CES (Credential Execution Service) — use the shared server-level client.
430
472
  // The CES sidecar accepts exactly one bootstrap connection, so the
@@ -441,13 +483,10 @@ export class Conversation {
441
483
  const hasSystemPromptOverride = systemPrompt !== buildSystemPrompt();
442
484
  this.hasSystemPromptOverride = hasSystemPromptOverride;
443
485
 
444
- // If an explicit modelOverride is supplied, use it verbatim. Otherwise,
445
- // if modelIntent is set, resolve it against the active provider's
446
- // intent model mapping. The AgentLoop passes the resulting string
447
- // through to `providerConfig.model` on every turn.
448
- const resolvedModel: string | undefined =
449
- modelOverride ??
450
- (modelIntent ? resolveModelIntent(provider.name, modelIntent) : undefined);
486
+ // If an explicit modelOverride is supplied, use it verbatim. Otherwise
487
+ // leave the model unset and let `RetryProvider`'s call-site resolver pick
488
+ // it up from `llm.default` / `llm.callSites.<id>` on every turn.
489
+ const resolvedModel: string | undefined = modelOverride;
451
490
 
452
491
  const resolveSystemPromptCallback = (
453
492
  _history: import("../providers/types.js").Message[],
@@ -477,16 +516,17 @@ export class Conversation {
477
516
  };
478
517
 
479
518
  const fastModeEnabled = isAssistantFeatureFlagEnabled("fast-mode", config);
480
- const resolvedSpeed = speedOverride ?? config.speed;
519
+ const resolvedSpeed = speedOverride ?? config.llm.default.speed;
520
+ const llmDefault = config.llm.default;
481
521
 
482
522
  this.agentLoop = new AgentLoop(
483
523
  provider,
484
524
  systemPrompt,
485
525
  {
486
526
  maxTokens,
487
- maxInputTokens: config.contextWindow.maxInputTokens,
488
- thinking: config.thinking,
489
- effort: config.effort,
527
+ maxInputTokens: llmDefault.contextWindow.maxInputTokens,
528
+ thinking: llmDefault.thinking,
529
+ effort: llmDefault.effort,
490
530
  ...(fastModeEnabled && resolvedSpeed === "fast"
491
531
  ? { speed: resolvedSpeed }
492
532
  : {}),
@@ -500,7 +540,7 @@ export class Conversation {
500
540
  this.contextWindowManager = new ContextWindowManager({
501
541
  provider,
502
542
  systemPrompt: () => resolveSystemPromptCallback([]).systemPrompt,
503
- config: config.contextWindow,
543
+ config: llmDefault.contextWindow,
504
544
  toolTokenBudget: this.agentLoop.getToolTokenBudget(),
505
545
  });
506
546
 
@@ -724,6 +764,35 @@ export class Conversation {
724
764
 
725
765
  dispose(): void {
726
766
  approvalOverrides.clearMode(this.conversationId);
767
+ // Cancel all pending standalone surfaces so callers get a clean
768
+ // cancellation instead of hanging forever. Emit dismiss notifications
769
+ // to the client so surfaces don't remain visually active if the client
770
+ // reconnects after dispose.
771
+ const emitDispose =
772
+ this.broadcastToAllClients ?? this.sendToClient.bind(this);
773
+ for (const [surfaceId, entry] of this.pendingStandaloneSurfaces) {
774
+ clearTimeout(entry.timer);
775
+ try {
776
+ emitDispose({
777
+ type: "ui_surface_dismiss",
778
+ conversationId: this.conversationId,
779
+ surfaceId,
780
+ });
781
+ } catch {
782
+ // Best-effort: the client may already be disconnected during dispose.
783
+ }
784
+ entry.resolve({
785
+ status: "cancelled",
786
+ surfaceId,
787
+ cancellationReason: "resolver_unavailable",
788
+ });
789
+ }
790
+ this.pendingStandaloneSurfaces.clear();
791
+ // Clear tombstone timers to prevent dangling references after dispose.
792
+ for (const timer of this.recentlyCompletedStandaloneSurfaces.values()) {
793
+ clearTimeout(timer);
794
+ }
795
+ this.recentlyCompletedStandaloneSurfaces.clear();
727
796
  this.hostBashProxy?.dispose();
728
797
  this.hostBrowserProxy?.dispose();
729
798
  this.hostCuProxy?.dispose();
@@ -762,6 +831,7 @@ export class Conversation {
762
831
  options?: { isInteractive?: boolean },
763
832
  displayContent?: string,
764
833
  transport?: ConversationTransportMetadata,
834
+ clientMessageId?: string,
765
835
  ): { queued: boolean; requestId: string; rejected?: boolean } {
766
836
  return enqueueMessageImpl(
767
837
  this,
@@ -775,6 +845,7 @@ export class Conversation {
775
845
  options,
776
846
  displayContent,
777
847
  transport,
848
+ clientMessageId,
778
849
  );
779
850
  }
780
851
 
@@ -927,7 +998,7 @@ export class Conversation {
927
998
  * confirmations in the same conversation that match the decision.
928
999
  *
929
1000
  * - allow_10m / allow_conversation → approve ALL pending in conversation
930
- * - always_allow / always_allow_high_risk → approve pattern-matching pending
1001
+ * - always_allow → approve pattern-matching pending
931
1002
  * - always_deny → deny pattern-matching pending
932
1003
  * - allow / deny (one-time) → no cascading
933
1004
  */
@@ -1021,14 +1092,9 @@ export class Conversation {
1021
1092
  }
1022
1093
 
1023
1094
  // Persistent allow: cascade if the pattern matches any allowlist candidate.
1024
- // "always_allow" must NOT cascade to high-risk pending confirmations
1025
- // only "always_allow_high_risk" has consent for those.
1026
- if (
1027
- (decision === "always_allow" || decision === "always_allow_high_risk") &&
1028
- selectedPattern &&
1029
- details
1030
- ) {
1031
- if (decision === "always_allow" && details.riskLevel === "high") {
1095
+ // "always_allow" must NOT cascade to high-risk pending confirmations.
1096
+ if (decision === "always_allow" && selectedPattern && details) {
1097
+ if (details.riskLevel === "high") {
1032
1098
  return null;
1033
1099
  }
1034
1100
  for (const option of details.allowlistOptions) {
@@ -1170,8 +1236,21 @@ export class Conversation {
1170
1236
  const result = await this.contextWindowManager.maybeCompact(
1171
1237
  this.messages,
1172
1238
  this.abortController?.signal ?? undefined,
1173
- { force: true, lastCompactedAt: this.contextCompactedAt ?? undefined },
1239
+ {
1240
+ force: true,
1241
+ lastCompactedAt: this.contextCompactedAt ?? undefined,
1242
+ conversationOriginChannel:
1243
+ getConversationOriginChannel(this.conversationId) ?? undefined,
1244
+ },
1174
1245
  );
1246
+ // Track circuit-breaker state for user-initiated `/compact` and other
1247
+ // forced paths so a successful forced compaction clears a stuck counter
1248
+ // and a run of forced failures still trips the breaker. `summaryFailed`
1249
+ // is `undefined` on early-return paths (no eligible messages, disabled,
1250
+ // etc.) — skip those so they don't silently reset the counter.
1251
+ if (result.summaryFailed !== undefined) {
1252
+ trackCompactionOutcome(this, result.summaryFailed, this.sendToClient);
1253
+ }
1175
1254
  if (result.compacted) {
1176
1255
  this.messages = result.messages;
1177
1256
  this.contextCompactedMessageCount += result.compactedPersistedMessages;
@@ -1194,6 +1273,14 @@ export class Conversation {
1194
1273
 
1195
1274
  setChannelCapabilities(caps: ChannelCapabilities | null): void {
1196
1275
  this.channelCapabilities = caps ?? undefined;
1276
+ this.secretPrompter.setChannelContext(
1277
+ caps
1278
+ ? {
1279
+ channel: caps.channel,
1280
+ supportsDynamicUi: caps.supportsDynamicUi,
1281
+ }
1282
+ : undefined,
1283
+ );
1197
1284
  }
1198
1285
 
1199
1286
  setTrustContext(ctx: TrustContext | null): void {
@@ -1333,6 +1420,7 @@ export class Conversation {
1333
1420
  isInteractive?: boolean;
1334
1421
  isUserMessage?: boolean;
1335
1422
  titleText?: string;
1423
+ callSite?: LLMCallSite;
1336
1424
  },
1337
1425
  ): Promise<void> {
1338
1426
  return runAgentLoopImpl(this, content, userMessageId, onEvent, options);
@@ -1349,7 +1437,7 @@ export class Conversation {
1349
1437
  requestId?: string,
1350
1438
  activeSurfaceId?: string,
1351
1439
  currentPage?: string,
1352
- options?: { isInteractive?: boolean },
1440
+ options?: { isInteractive?: boolean; callSite?: LLMCallSite },
1353
1441
  displayContent?: string,
1354
1442
  ): Promise<string> {
1355
1443
  return processMessageImpl(
@@ -0,0 +1,41 @@
1
+ /**
2
+ * External skill bootstrap.
3
+ *
4
+ * Loads first-party skills that expose **in-process tools** to the daemon.
5
+ * Importing this module triggers each skill's `register.ts` to run, which
6
+ * in turn calls `registerExternalTools()` on the assistant-side tool
7
+ * registry. The daemon's `initializeTools()` then picks the registered
8
+ * tools up and makes them available to the LLM.
9
+ *
10
+ * ## Why the cross-directory import exists
11
+ *
12
+ * `CLAUDE.md` and `skills/meet-join/AGENTS.md` establish a general rule
13
+ * that `assistant/` must not import from `skills/` via relative paths so
14
+ * that skills stay portable and extractable. For in-process tools this
15
+ * creates a chicken-and-egg problem: skills need their `register.ts` to
16
+ * execute before `initializeTools()` runs, but in a `bun --compile`
17
+ * binary only statically analyzed imports end up in the bundle, and
18
+ * dynamic imports with variable paths fail inside `/$bunfs/`.
19
+ *
20
+ * We resolve the tension by:
21
+ *
22
+ * 1. Keeping this file as the **one** place in `assistant/` that
23
+ * reaches into `skills/`. Every other import direction (skill ->
24
+ * assistant) remains legal and intentional.
25
+ * 2. Limiting entries to **first-party bundled skills** whose source
26
+ * is shipped in the Docker build context and statically compiled
27
+ * into the Bun binary. The repo-root `.dockerignore` is the
28
+ * allowlist that determines which skill files enter the build
29
+ * context; the assistant `Dockerfile` copies `skills/` generically.
30
+ * 3. Keeping the imports as **side-effect only** so the skill owns
31
+ * both the tool list and the feature-flag semantics — this file
32
+ * just wires module evaluation into the startup path.
33
+ *
34
+ * When a new bundled first-party skill wants to expose in-process tools
35
+ * to the LLM, add another side-effect import here and extend the
36
+ * repo-root `.dockerignore` allowlist with the skill's runtime files.
37
+ * Non-bundled skills (workspace-installed, third-party) never belong in
38
+ * this file.
39
+ */
40
+
41
+ import "../../../skills/meet-join/register.js";
@@ -1,5 +1,7 @@
1
- import { loadConfig } from "../config/loader.js";
1
+ import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
2
+ import { getConfiguredProvider } from "../providers/provider-send-message.js";
2
3
  import { getProvider } from "../providers/registry.js";
4
+ import type { Provider } from "../providers/types.js";
3
5
  import {
4
6
  buildGuardianActionGenerationPrompt,
5
7
  getGuardianActionFallbackMessage,
@@ -18,21 +20,20 @@ import type {
18
20
  /**
19
21
  * Create the daemon-owned guardian action copy generator that resolves
20
22
  * providers and calls `provider.sendMessage` to generate guardian action
21
- * copy text. Uses `latency-optimized` model intent since these are
22
- * time-sensitive voice responses.
23
+ * copy text. Uses the `guardianQuestionCopy` call site so model selection
24
+ * tracks the unified `llm.callSites` configuration.
23
25
  *
24
26
  * This keeps all provider awareness in the daemon lifecycle, away from
25
27
  * the runtime composer.
26
28
  */
27
29
  export function createGuardianActionCopyGenerator(): GuardianActionCopyGenerator {
28
30
  return async (context, options = {}) => {
29
- const config = loadConfig();
30
- let provider;
31
- try {
32
- provider = getProvider(config.services.inference.provider);
33
- } catch {
34
- return null;
35
- }
31
+ const baseProvider = await getConfiguredProvider("guardianQuestionCopy");
32
+ if (!baseProvider) return null;
33
+ // Wrap so the per-call `callSite` can route to a different provider
34
+ // transport when `llm.callSites.guardianQuestionCopy.provider` overrides
35
+ // the default. Without this, callSite only affects request metadata.
36
+ const provider = wrapWithCallSiteRouting(baseProvider);
36
37
 
37
38
  const fallbackText =
38
39
  options.fallbackText?.trim() || getGuardianActionFallbackMessage(context);
@@ -52,7 +53,7 @@ export function createGuardianActionCopyGenerator(): GuardianActionCopyGenerator
52
53
  {
53
54
  config: {
54
55
  max_tokens: options.maxTokens ?? GUARDIAN_ACTION_COPY_MAX_TOKENS,
55
- modelIntent: "latency-optimized",
56
+ callSite: "guardianQuestionCopy",
56
57
  },
57
58
  signal: AbortSignal.timeout(
58
59
  options.timeoutMs ?? GUARDIAN_ACTION_COPY_TIMEOUT_MS,
@@ -130,8 +131,11 @@ const VALID_FOLLOWUP_DISPOSITIONS: ReadonlySet<string> = new Set([
130
131
  */
131
132
  export function createGuardianFollowUpConversationGenerator(): GuardianFollowUpConversationGenerator {
132
133
  return async (context) => {
133
- const config = loadConfig();
134
- const provider = getProvider(config.services.inference.provider);
134
+ const baseProvider = await getConfiguredProvider("guardianQuestionCopy");
135
+ if (!baseProvider) {
136
+ throw new Error("No configured provider available for follow-up conversation");
137
+ }
138
+ const provider = wrapWithCallSiteRouting(baseProvider);
135
139
 
136
140
  const userPrompt = [
137
141
  `Original question from the voice call: "${context.questionText}"`,
@@ -146,7 +150,7 @@ export function createGuardianFollowUpConversationGenerator(): GuardianFollowUpC
146
150
  {
147
151
  config: {
148
152
  max_tokens: FOLLOWUP_CONVERSATION_MAX_TOKENS,
149
- modelIntent: "latency-optimized",
153
+ callSite: "guardianQuestionCopy",
150
154
  },
151
155
  signal: AbortSignal.timeout(FOLLOWUP_CONVERSATION_TIMEOUT_MS),
152
156
  },
@@ -188,3 +192,19 @@ export function createGuardianFollowUpConversationGenerator(): GuardianFollowUpC
188
192
  return result;
189
193
  };
190
194
  }
195
+
196
+ /**
197
+ * Wrap a base Provider so per-call `callSite` metadata can route the actual
198
+ * transport to a different provider when `llm.callSites.<id>.provider`
199
+ * differs from the default. Without this wrapper, only request metadata
200
+ * reflects the callSite — the HTTP transport stays bound to the default.
201
+ */
202
+ function wrapWithCallSiteRouting(base: Provider): Provider {
203
+ return new CallSiteRoutingProvider(base, (name) => {
204
+ try {
205
+ return getProvider(name);
206
+ } catch {
207
+ return undefined;
208
+ }
209
+ });
210
+ }
@@ -0,0 +1,86 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { PROVIDER_CATALOG } from "../../providers/model-catalog.js";
4
+ import { projectProviderForWire } from "./config-model.js";
5
+
6
+ /**
7
+ * Regression guard for the wire contract declared in
8
+ * `daemon/message-types/conversations.ts#ModelInfo.allProviders`. The
9
+ * daemon's `PROVIDER_CATALOG` carries richer metadata (capability flags,
10
+ * pricing, subtitle, setupMode, setupHint, envVar, credentialsGuide), but
11
+ * clients source that metadata from the bundled `LLMProviderRegistry`
12
+ * JSON, so only the legacy fields belong on the wire. The Swift generated
13
+ * DTO declares the same legacy-only shape and silently discards any
14
+ * extras — this test keeps the daemon honest about what it sends.
15
+ */
16
+ describe("projectProviderForWire", () => {
17
+ const LEGACY_WIRE_KEYS = new Set([
18
+ "id",
19
+ "displayName",
20
+ "models",
21
+ "defaultModel",
22
+ "apiKeyUrl",
23
+ "apiKeyPlaceholder",
24
+ ]);
25
+
26
+ test("drops rich catalog fields (subtitle, setupMode, envVar, credentialsGuide, setupHint)", () => {
27
+ for (const entry of PROVIDER_CATALOG) {
28
+ const wire = projectProviderForWire(entry);
29
+ const keys = Object.keys(wire);
30
+ for (const key of keys) {
31
+ expect(LEGACY_WIRE_KEYS.has(key)).toBe(true);
32
+ }
33
+ expect(keys).not.toContain("subtitle");
34
+ expect(keys).not.toContain("setupMode");
35
+ expect(keys).not.toContain("setupHint");
36
+ expect(keys).not.toContain("envVar");
37
+ expect(keys).not.toContain("credentialsGuide");
38
+ }
39
+ });
40
+
41
+ test("drops rich CatalogModel fields (capability flags, pricing, context windows)", () => {
42
+ for (const entry of PROVIDER_CATALOG) {
43
+ const wire = projectProviderForWire(entry);
44
+ for (const model of wire.models) {
45
+ expect(Object.keys(model).sort()).toEqual(["displayName", "id"]);
46
+ }
47
+ }
48
+ });
49
+
50
+ test("preserves legacy wire fields exactly", () => {
51
+ const anthropic = PROVIDER_CATALOG.find((p) => p.id === "anthropic");
52
+ expect(anthropic).toBeDefined();
53
+ const wire = projectProviderForWire(anthropic!);
54
+ expect(wire.id).toBe(anthropic!.id);
55
+ expect(wire.displayName).toBe(anthropic!.displayName);
56
+ expect(wire.defaultModel).toBe(anthropic!.defaultModel);
57
+ expect(wire.apiKeyUrl).toBe(anthropic!.apiKeyUrl);
58
+ expect(wire.apiKeyPlaceholder).toBe(anthropic!.apiKeyPlaceholder);
59
+ expect(wire.models.length).toBe(anthropic!.models.length);
60
+ });
61
+
62
+ test("omits apiKeyUrl/apiKeyPlaceholder when source entry has none (keyless providers)", () => {
63
+ const ollama = PROVIDER_CATALOG.find((p) => p.id === "ollama");
64
+ expect(ollama).toBeDefined();
65
+ // Sanity-check the fixture: ollama is the keyless provider.
66
+ expect(ollama!.apiKeyUrl).toBeUndefined();
67
+ expect(ollama!.apiKeyPlaceholder).toBeUndefined();
68
+
69
+ const wire = projectProviderForWire(ollama!);
70
+ expect("apiKeyUrl" in wire).toBe(false);
71
+ expect("apiKeyPlaceholder" in wire).toBe(false);
72
+ });
73
+
74
+ test("JSON round-trip exposes only the legacy wire keys", () => {
75
+ for (const entry of PROVIDER_CATALOG) {
76
+ const wire = projectProviderForWire(entry);
77
+ const serialized = JSON.parse(JSON.stringify(wire)) as Record<
78
+ string,
79
+ unknown
80
+ >;
81
+ for (const key of Object.keys(serialized)) {
82
+ expect(LEGACY_WIRE_KEYS.has(key)).toBe(true);
83
+ }
84
+ }
85
+ });
86
+ });
@@ -3,7 +3,10 @@ import {
3
3
  loadRawConfig,
4
4
  saveRawConfig,
5
5
  } from "../../config/loader.js";
6
- import { setServiceField } from "../../config/raw-config-utils.js";
6
+ import {
7
+ setLlmDefaultField,
8
+ setServiceField,
9
+ } from "../../config/raw-config-utils.js";
7
10
  import { VALID_INFERENCE_PROVIDERS } from "../../config/schemas/services.js";
8
11
  import type { ProviderCatalogEntry } from "../../providers/model-catalog.js";
9
12
  import {
@@ -37,25 +40,64 @@ export const MODEL_TO_PROVIDER: Record<string, string> = Object.fromEntries(
37
40
  // Shared business logic (transport-agnostic)
38
41
  // ---------------------------------------------------------------------------
39
42
 
43
+ /**
44
+ * Wire-contract shape for a provider entry in `ModelInfo.allProviders`.
45
+ * Mirrors the legacy fields declared in `message-types/conversations.ts` —
46
+ * rich provider metadata (capability flags, pricing, subtitle, setupMode,
47
+ * setupHint, envVar, credentialsGuide) is sourced by clients from the
48
+ * bundled `LLMProviderRegistry` JSON, so there is no reason to double-send
49
+ * it over the wire.
50
+ */
51
+ export interface WireProviderEntry {
52
+ id: string;
53
+ displayName: string;
54
+ models: Array<{ id: string; displayName: string }>;
55
+ defaultModel: string;
56
+ apiKeyUrl?: string;
57
+ apiKeyPlaceholder?: string;
58
+ }
59
+
40
60
  export interface ModelInfo {
41
61
  model: string;
42
62
  provider: string;
43
63
  configuredProviders?: string[];
44
64
  availableModels?: Array<{ id: string; displayName: string }>;
45
- allProviders?: ProviderCatalogEntry[];
65
+ allProviders?: WireProviderEntry[];
66
+ }
67
+
68
+ /**
69
+ * Project a rich `ProviderCatalogEntry` to the legacy wire-contract fields.
70
+ * Keeping the wire payload honest avoids contract drift with
71
+ * `message-types/conversations.ts` and the generated Swift DTO.
72
+ */
73
+ export function projectProviderForWire(
74
+ entry: ProviderCatalogEntry,
75
+ ): WireProviderEntry {
76
+ return {
77
+ id: entry.id,
78
+ displayName: entry.displayName,
79
+ models: entry.models.map((m) => ({ id: m.id, displayName: m.displayName })),
80
+ defaultModel: entry.defaultModel,
81
+ ...(entry.apiKeyUrl !== undefined && { apiKeyUrl: entry.apiKeyUrl }),
82
+ ...(entry.apiKeyPlaceholder !== undefined && {
83
+ apiKeyPlaceholder: entry.apiKeyPlaceholder,
84
+ }),
85
+ };
46
86
  }
47
87
 
48
88
  /** Return current model configuration. */
49
89
  export async function getModelInfo(): Promise<ModelInfo> {
50
90
  const config = getConfig();
51
- const provider = config.services.inference.provider;
91
+ const provider = config.llm.default.provider;
52
92
 
53
93
  return {
54
- model: config.services.inference.model,
94
+ model: config.llm.default.model,
55
95
  provider,
56
96
  configuredProviders: await getConfiguredProviders(),
57
- availableModels: PROVIDER_CATALOG.find((p) => p.id === provider)?.models,
58
- allProviders: PROVIDER_CATALOG,
97
+ availableModels: PROVIDER_CATALOG.find(
98
+ (p) => p.id === provider,
99
+ )?.models?.map((m) => ({ id: m.id, displayName: m.displayName })),
100
+ allProviders: PROVIDER_CATALOG.map(projectProviderForWire),
59
101
  };
60
102
  }
61
103
 
@@ -102,12 +144,12 @@ export async function setModel(
102
144
  const resolvedProvider =
103
145
  explicitProvider ??
104
146
  MODEL_TO_PROVIDER[modelId] ??
105
- current.services.inference.provider;
147
+ current.llm.default.provider;
106
148
 
107
149
  // Auto-reset model when provider changes and current modelId doesn't
108
150
  // belong to the new provider's catalog.
109
151
  if (
110
- resolvedProvider !== current.services.inference.provider &&
152
+ resolvedProvider !== current.llm.default.provider &&
111
153
  !isModelInCatalog(resolvedProvider, modelId)
112
154
  ) {
113
155
  modelId = getProviderDefaultModel(resolvedProvider);
@@ -115,8 +157,8 @@ export async function setModel(
115
157
 
116
158
  // No-op guard: skip expensive reinitialization when nothing changed
117
159
  if (
118
- modelId === current.services.inference.model &&
119
- resolvedProvider === current.services.inference.provider
160
+ modelId === current.llm.default.model &&
161
+ resolvedProvider === current.llm.default.provider
120
162
  ) {
121
163
  return await getModelInfo();
122
164
  }
@@ -129,8 +171,8 @@ export async function setModel(
129
171
 
130
172
  // Use raw config to avoid persisting env-var API keys to disk
131
173
  const raw = loadRawConfig();
132
- setServiceField(raw, "inference", "model", modelId);
133
- setServiceField(raw, "inference", "provider", resolvedProvider);
174
+ setLlmDefaultField(raw, "model", modelId);
175
+ setLlmDefaultField(raw, "provider", resolvedProvider);
134
176
 
135
177
  // Suppress the file watcher callback — setModel already does
136
178
  // the full reload sequence; a redundant watcher-triggered reload
@@ -148,12 +148,19 @@ export function handleConfirmationResponse(
148
148
  // Route by requestId to the conversation that originated the prompt, not by
149
149
  // the current conversation binding which may have changed since the
150
150
  // request was issued (e.g. after a conversation switch).
151
+ // Normalize legacy decision: older clients may still send
152
+ // "always_allow_high_risk" via WebSocket for high-risk prompts.
153
+ const decision =
154
+ msg.decision === ("always_allow_high_risk" as typeof msg.decision)
155
+ ? "always_allow"
156
+ : msg.decision;
157
+
151
158
  for (const [conversationId, conversation] of ctx.conversations) {
152
159
  if (conversation.hasPendingConfirmation(msg.requestId)) {
153
160
  ctx.touchConversation(conversationId);
154
161
  conversation.handleConfirmationResponse(
155
162
  msg.requestId,
156
- msg.decision,
163
+ decision,
157
164
  msg.selectedPattern,
158
165
  msg.selectedScope,
159
166
  undefined,
@@ -435,7 +442,7 @@ export function handleUsageRequest(
435
442
  totalInputTokens: conversation.totalInputTokens,
436
443
  totalOutputTokens: conversation.totalOutputTokens,
437
444
  estimatedCost: conversation.totalEstimatedCost,
438
- model: config.services.inference.model,
445
+ model: config.llm.default.model,
439
446
  });
440
447
  }
441
448