@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
@@ -0,0 +1,128 @@
1
+ import { z } from "zod";
2
+
3
+ import {
4
+ type LLMCallSite,
5
+ LLMConfigBase,
6
+ type LLMConfigFragment,
7
+ type LLMSchema,
8
+ } from "./schemas/llm.js";
9
+
10
+ /**
11
+ * Resolves a fully-specified `LLMConfigBase` for a given call site by layering
12
+ * the call-site override on top of an optional named profile on top of the
13
+ * required `llm.default`.
14
+ *
15
+ * Resolution order (highest precedence wins):
16
+ * 1. `llm.callSites[callSite]` fields (call-site override)
17
+ * 2. `llm.profiles[site.profile]` fields (named profile)
18
+ * 3. `llm.default` fields (required base)
19
+ *
20
+ * Nested objects (`thinking`, `contextWindow`, and
21
+ * `contextWindow.overflowRecovery`) are deep-merged so partial overrides at
22
+ * any nesting level merge into — rather than replace — the corresponding
23
+ * base value.
24
+ *
25
+ * Pure & synchronous: no I/O, no async work.
26
+ */
27
+ export function resolveCallSiteConfig(
28
+ callSite: LLMCallSite,
29
+ llm: z.infer<typeof LLMSchema>,
30
+ ): z.infer<typeof LLMConfigBase> {
31
+ const site = llm.callSites?.[callSite];
32
+
33
+ // No site-level entry: deep-merge `default` against an empty fragment so
34
+ // every code path goes through the same merge codepath.
35
+ if (site == null) {
36
+ return finalize(deepMerge(llm.default as Mergeable, {} as Mergeable));
37
+ }
38
+
39
+ let profileFragment: LLMConfigFragment | undefined;
40
+ if (site.profile != null) {
41
+ profileFragment = llm.profiles?.[site.profile];
42
+ if (profileFragment == null) {
43
+ // Defensive: `LLMSchema.superRefine` already rejects unknown profile
44
+ // references at config load, so this branch is unreachable for any
45
+ // config that survived schema validation. Throw a clear error in case
46
+ // a hand-crafted (un-parsed) config slips through.
47
+ throw new Error(
48
+ `LLM call site "${callSite}" references undefined profile "${site.profile}"`,
49
+ );
50
+ }
51
+ }
52
+
53
+ // Strip the `profile` discriminator before merging — it isn't a
54
+ // `LLMConfigBase` field.
55
+ const { profile: _profile, ...siteFragment } = site;
56
+
57
+ const merged = deepMerge(
58
+ llm.default as Mergeable,
59
+ (profileFragment ?? {}) as Mergeable,
60
+ siteFragment as Mergeable,
61
+ );
62
+
63
+ return finalize(merged);
64
+ }
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Internal helpers
68
+ // ---------------------------------------------------------------------------
69
+
70
+ type Mergeable = Record<string, unknown>;
71
+
72
+ /**
73
+ * Returns true for objects we should recurse into during deep merge. We
74
+ * deliberately exclude arrays so that array-valued fields (e.g.
75
+ * `pricingOverrides` siblings) get full replacement semantics.
76
+ */
77
+ function isPlainObject(value: unknown): value is Mergeable {
78
+ return (
79
+ typeof value === "object" &&
80
+ value !== null &&
81
+ !Array.isArray(value) &&
82
+ Object.getPrototypeOf(value) === Object.prototype
83
+ );
84
+ }
85
+
86
+ /**
87
+ * Deep-merges a sequence of fragments where each rightward source overrides
88
+ * the previous. For nested plain objects, recurse so partial overrides merge
89
+ * leaf-by-leaf rather than wholesale-replacing the nested object.
90
+ *
91
+ * `undefined` values in a source are skipped (treated as "no opinion"); this
92
+ * matches Zod fragment semantics where unset optional fields are absent.
93
+ *
94
+ * Plain-object values are always cloned (via recursion) rather than aliased,
95
+ * so the returned config is an isolated snapshot — mutating any nested object
96
+ * on the result cannot affect `llm.default`, named profiles, or other call
97
+ * sites' resolutions. Arrays and primitives are copied by reference; the
98
+ * resolver does not return arrays, and primitives are immutable.
99
+ */
100
+ function deepMerge(...sources: Mergeable[]): Mergeable {
101
+ const out: Mergeable = {};
102
+ for (const source of sources) {
103
+ for (const [key, value] of Object.entries(source)) {
104
+ if (value === undefined) continue;
105
+ const existing = out[key];
106
+ if (isPlainObject(value)) {
107
+ // Recurse for any plain-object source. Using `existing` as the base
108
+ // when it's also a plain object preserves leaf-by-leaf merge
109
+ // semantics; otherwise we recurse against an empty object so the
110
+ // result is a freshly-allocated clone rather than an alias.
111
+ const base = isPlainObject(existing) ? existing : ({} as Mergeable);
112
+ out[key] = deepMerge(base, value);
113
+ } else {
114
+ out[key] = value;
115
+ }
116
+ }
117
+ }
118
+ return out;
119
+ }
120
+
121
+ /**
122
+ * Cast helper that documents the intent: after merging `llm.default` (which
123
+ * is `LLMConfigBase`) with optional fragments, every required field is still
124
+ * present, so the result satisfies `LLMConfigBase`.
125
+ */
126
+ function finalize(merged: Mergeable): z.infer<typeof LLMConfigBase> {
127
+ return merged as unknown as z.infer<typeof LLMConfigBase>;
128
+ }
@@ -6,11 +6,14 @@ import {
6
6
  statSync,
7
7
  writeFileSync,
8
8
  } from "node:fs";
9
- import { dirname, join } from "node:path";
9
+ import { basename, dirname, join } from "node:path";
10
10
 
11
- import { ConfigError } from "../util/errors.js";
12
11
  import { getLogger } from "../util/logger.js";
13
- import { ensureDataDir, getWorkspaceConfigPath } from "../util/platform.js";
12
+ import {
13
+ ensureDataDir,
14
+ getWorkspaceConfigPath,
15
+ getWorkspaceDir,
16
+ } from "../util/platform.js";
14
17
  import { isAssistantFeatureFlagEnabled } from "./assistant-feature-flags.js";
15
18
  import { AssistantConfigSchema } from "./schema.js";
16
19
  import type { AssistantConfig } from "./types.js";
@@ -47,6 +50,116 @@ function cloneDefaultConfig(): AssistantConfig {
47
50
  return applyNestedDefaults({});
48
51
  }
49
52
 
53
+ /**
54
+ * Build a filesystem-safe ISO-8601 timestamp for use in quarantine filenames.
55
+ * Replaces `:` (invalid on Windows, confusing on macOS Finder) with `-` so the
56
+ * resulting string is safe on every supported platform.
57
+ */
58
+ function filesystemSafeTimestamp(date: Date = new Date()): string {
59
+ return date.toISOString().replace(/:/g, "-");
60
+ }
61
+
62
+ /**
63
+ * Rename a corrupt config file to a quarantine path so the bad content is
64
+ * preserved for debug while the daemon falls through to defaults. Logs at
65
+ * `error` level with a remediation hint. Best-effort: if the rename itself
66
+ * fails (missing permissions, readonly FS, etc.) we still fall through to
67
+ * defaults — startup must never block.
68
+ *
69
+ * The quarantine filename encodes a millisecond-precision timestamp and ends
70
+ * in `.json` so editors syntax-highlight the preserved content:
71
+ * `<path>.corrupt-<ISO-timestamp>.json`
72
+ *
73
+ * On a successful rename, also appends a bulletin to `<workspace>/UPDATES.md`
74
+ * so the background update-bulletin job surfaces the event to the user
75
+ * proactively on their next interaction (log-level errors alone are invisible
76
+ * to users).
77
+ */
78
+ function quarantineCorruptConfig(configPath: string, err: unknown): string {
79
+ const quarantinePath = `${configPath}.corrupt-${filesystemSafeTimestamp()}.json`;
80
+ try {
81
+ renameSync(configPath, quarantinePath);
82
+ log.error(
83
+ `config file at ${configPath} was corrupt (${String(err)}); ` +
84
+ `quarantined to ${quarantinePath} and loaded defaults. ` +
85
+ `Inspect the quarantined file to recover any hand-edited settings.`,
86
+ );
87
+ appendQuarantineBulletin(configPath, quarantinePath);
88
+ } catch (renameErr) {
89
+ log.error(
90
+ { renameErr },
91
+ `config file at ${configPath} was corrupt (${String(err)}) but could ` +
92
+ `not be renamed for quarantine; loaded defaults.`,
93
+ );
94
+ }
95
+ return quarantinePath;
96
+ }
97
+
98
+ /**
99
+ * Append a config-quarantine bulletin to `<workspace>/UPDATES.md`. On the
100
+ * next daemon boot the background update-bulletin job picks up UPDATES.md
101
+ * and processes it inside a background-only conversation (not the user's
102
+ * chat). The agent decides whether and when to surface the event — typical
103
+ * cases are the user asking why their settings changed or noticing missing
104
+ * API keys. The bulletin is agent-visible context, not a push notification.
105
+ *
106
+ * Idempotency: the appended block embeds a marker keyed on the quarantine
107
+ * filename's basename. If that marker is already present in UPDATES.md (a
108
+ * prior append succeeded but the process crashed before control returned, or
109
+ * the file was hand-edited), the function is a no-op. This mirrors the
110
+ * pattern release-notes workspace migrations use — see the "Release Update
111
+ * Hygiene" section in the root `AGENTS.md`.
112
+ *
113
+ * Best-effort: any write failure is logged at `warn` and swallowed. The
114
+ * quarantine path must never block startup, and the error log from
115
+ * `quarantineCorruptConfig` remains the authoritative record.
116
+ *
117
+ * Exported with an underscore-prefixed alias (`_appendQuarantineBulletin`) so
118
+ * tests can exercise the idempotent-skip branch directly with a deterministic
119
+ * quarantine basename. Non-test callers should never import the underscore
120
+ * alias — the wiring into `quarantineCorruptConfig` is the production entry
121
+ * point.
122
+ */
123
+ function appendQuarantineBulletin(
124
+ originalPath: string,
125
+ quarantinePath: string,
126
+ ): void {
127
+ try {
128
+ const updatesPath = join(getWorkspaceDir(), "UPDATES.md");
129
+ const quarantineBasename = basename(quarantinePath);
130
+ const marker = `<!-- config-quarantine:${quarantineBasename} -->`;
131
+
132
+ const existing = existsSync(updatesPath)
133
+ ? readFileSync(updatesPath, "utf-8")
134
+ : "";
135
+ if (existing.includes(marker)) return;
136
+
137
+ const timestamp = new Date().toISOString();
138
+ const block =
139
+ `## Config was reset to defaults\n\n` +
140
+ `Your \`config.json\` was unreadable at ${timestamp} and couldn't be parsed ` +
141
+ `as JSON. The assistant preserved the original file at \`${quarantinePath}\` ` +
142
+ `and loaded defaults so the app stays working.\n\n` +
143
+ `If you had custom settings (API keys, model choices, voice preferences), ` +
144
+ `they are still in the quarantined file — \`cat ${quarantinePath}\` to ` +
145
+ `recover them, then re-enter through Settings or the CLI.\n\n` +
146
+ `${marker}\n`;
147
+
148
+ const toWrite = existing.length === 0 ? block : `${existing}\n${block}`;
149
+ writeFileSync(updatesPath, toWrite, "utf-8");
150
+ log.info(
151
+ `Appended config-quarantine bulletin to ${updatesPath} for ${originalPath} ` +
152
+ `(quarantined as ${quarantineBasename}).`,
153
+ );
154
+ } catch (bulletinErr) {
155
+ log.warn(
156
+ { bulletinErr },
157
+ `Failed to append config-quarantine bulletin to UPDATES.md; ` +
158
+ `the quarantine event is still recorded in the assistant logs.`,
159
+ );
160
+ }
161
+ }
162
+
50
163
  /**
51
164
  * Validate a raw config object with Zod. Invalid fields are logged as warnings
52
165
  * and replaced with defaults (matching prior behavior of per-field fallback).
@@ -206,10 +319,53 @@ export function deepMergeMissing(
206
319
  return changed;
207
320
  }
208
321
 
322
+ /**
323
+ * Recursively strip `null` leaves from a plain-object value, returning a
324
+ * deep clone with all `null`-valued keys removed at every nesting level.
325
+ * Non-object inputs (scalars, arrays, `null` itself) are returned as-is.
326
+ *
327
+ * Used to sanitize `overrides` before assigning whole subtrees in
328
+ * `deepMergeOverwrite`, so deletion-sentinel semantics apply uniformly
329
+ * even when the corresponding `target` key does not yet exist.
330
+ */
331
+ function stripNullLeaves(value: unknown): unknown {
332
+ if (value == null || typeof value !== "object" || Array.isArray(value)) {
333
+ return value;
334
+ }
335
+ const out: Record<string, unknown> = {};
336
+ for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
337
+ if (v === null) continue;
338
+ out[k] = stripNullLeaves(v);
339
+ }
340
+ return out;
341
+ }
342
+
209
343
  /**
210
344
  * Deep-merge `overrides` into `target`, overwriting leaf values.
211
345
  * Recursively merges nested objects; scalars and arrays from `overrides`
212
346
  * replace corresponding values in `target`.
347
+ *
348
+ * JSON `null` semantics depend on what the target currently holds at
349
+ * that key:
350
+ *
351
+ * - **Target holds a non-null object** (not array): `null` deletes the
352
+ * key, removing the entire subtree. This supports "clear entry"
353
+ * semantics (e.g. the macOS SettingsStore clearing a call-site
354
+ * override via `{ callSites: { memoryRetrieval: null } }`).
355
+ *
356
+ * - **Target holds a scalar, null, or array**: `null` is assigned as the
357
+ * value, preserving nullable config fields like `activeHoursStart`
358
+ * and `llmRequestLogRetentionMs` where `null` is a valid schema
359
+ * value meaning "disabled / no limit".
360
+ *
361
+ * - **Key absent from target**: no-op. Assigning null to a missing key
362
+ * would create a spurious entry; callers that want to establish a
363
+ * null value should set the key to its default first.
364
+ *
365
+ * When an override assigns a whole object subtree to a key that does
366
+ * not yet exist on `target` (or whose existing value is a scalar/array),
367
+ * `stripNullLeaves` drops any `null` leaves inside that subtree before
368
+ * assignment so no invalid nulls get persisted for non-nullable fields.
213
369
  */
214
370
  export function deepMergeOverwrite(
215
371
  target: Record<string, unknown>,
@@ -217,8 +373,20 @@ export function deepMergeOverwrite(
217
373
  ): void {
218
374
  for (const key of Object.keys(overrides)) {
219
375
  const ov = overrides[key];
220
- if (
221
- ov != null &&
376
+ if (ov === null) {
377
+ if (!(key in target)) continue;
378
+ const existing = target[key];
379
+ if (
380
+ existing != null &&
381
+ typeof existing === "object" &&
382
+ !Array.isArray(existing)
383
+ ) {
384
+ delete target[key];
385
+ } else {
386
+ target[key] = null;
387
+ }
388
+ } else if (
389
+ ov !== undefined &&
222
390
  typeof ov === "object" &&
223
391
  !Array.isArray(ov) &&
224
392
  target[key] != null &&
@@ -230,7 +398,7 @@ export function deepMergeOverwrite(
230
398
  ov as Record<string, unknown>,
231
399
  );
232
400
  } else {
233
- target[key] = ov;
401
+ target[key] = stripNullLeaves(ov);
234
402
  }
235
403
  }
236
404
  }
@@ -363,9 +531,14 @@ export function loadConfig(): AssistantConfig {
363
531
  try {
364
532
  fileConfig = JSON.parse(readFileSync(configPath, "utf-8"));
365
533
  } catch (err) {
366
- throw new ConfigError(
367
- `Failed to parse config at ${configPath}: ${err}`,
368
- );
534
+ // The daemon must never block startup (assistant/CLAUDE.md). A config
535
+ // file that fails JSON.parse truncated during a mid-write crash, or
536
+ // hand-edited to invalid JSON — is quarantined so the content is
537
+ // preserved for debug, and startup proceeds with the same default-
538
+ // config path used when config.json does not exist.
539
+ quarantineCorruptConfig(configPath, err);
540
+ fileConfig = {};
541
+ configFileExisted = false;
369
542
  }
370
543
  } else {
371
544
  configFileExisted = false;
@@ -521,7 +694,11 @@ export function loadRawConfig(): Record<string, unknown> {
521
694
  try {
522
695
  raw = JSON.parse(readFileSync(configPath, "utf-8"));
523
696
  } catch (err) {
524
- throw new ConfigError(`Failed to parse config at ${configPath}: ${err}`);
697
+ // Mirror loadConfig(): quarantine the corrupt file and return an empty
698
+ // object rather than throwing. This prevents /v1/config from surfacing
699
+ // a 500 when the user's config.json is malformed.
700
+ quarantineCorruptConfig(configPath, err);
701
+ raw = {};
525
702
  }
526
703
  }
527
704
 
@@ -571,3 +748,10 @@ export function setNestedValue(
571
748
  }
572
749
  current[keys[keys.length - 1]] = value;
573
750
  }
751
+
752
+ /**
753
+ * Test-only alias for `appendQuarantineBulletin`. Exists so the crash-mid-
754
+ * append idempotency branch can be exercised with a deterministic quarantine
755
+ * basename without widening the runtime surface. Not for production use.
756
+ */
757
+ export const _appendQuarantineBulletin = appendQuarantineBulletin;
@@ -1,11 +1,39 @@
1
+ /**
2
+ * Safely set a nested field on a raw config object's `llm.default` map.
3
+ *
4
+ * Ensures the `llm` and `llm.default` objects exist before writing, so
5
+ * callers don't need to guard against undefined intermediate keys.
6
+ *
7
+ * Example: `setLlmDefaultField(raw, "model", "claude-sonnet-4-6")`
8
+ * produces `raw.llm.default.model = "claude-sonnet-4-6"`.
9
+ */
10
+ export function setLlmDefaultField(
11
+ raw: Record<string, unknown>,
12
+ field: string,
13
+ value: unknown,
14
+ ): void {
15
+ const llm: Record<string, unknown> =
16
+ raw.llm != null && typeof raw.llm === "object" && !Array.isArray(raw.llm)
17
+ ? (raw.llm as Record<string, unknown>)
18
+ : {};
19
+ const existing = llm.default;
20
+ const defaultBlock: Record<string, unknown> =
21
+ existing != null && typeof existing === "object" && !Array.isArray(existing)
22
+ ? (existing as Record<string, unknown>)
23
+ : {};
24
+ defaultBlock[field] = value;
25
+ llm.default = defaultBlock;
26
+ raw.llm = llm;
27
+ }
28
+
1
29
  /**
2
30
  * Safely set a nested field on a raw config object's `services` map.
3
31
  *
4
32
  * Ensures the `services` and service-level objects exist before writing,
5
33
  * so callers don't need to guard against undefined intermediate keys.
6
34
  *
7
- * Example: `setServiceField(raw, "inference", "model", "claude-sonnet-4-6")`
8
- * produces `raw.services.inference.model = "claude-sonnet-4-6"`.
35
+ * Example: `setServiceField(raw, "inference", "mode", "managed")`
36
+ * produces `raw.services.inference.mode = "managed"`.
9
37
  */
10
38
  export function setServiceField(
11
39
  raw: Record<string, unknown>,
@@ -7,6 +7,18 @@
7
7
  * - `ingress.enabled` → deleted
8
8
  * - `daemon` → deleted entirely
9
9
  * - `skills.load.extraDirs` → set to `[]`
10
+ * - `hostBrowser.cdpInspect.desktopAuto` → deleted **only when the source
11
+ * either relies on the schema default or explicitly sets
12
+ * `enabled: true`**. An explicit `enabled: false` is preserved so a
13
+ * platform→local teleport doesn't silently re-enable auto-attach
14
+ * against the user's opt-out.
15
+ *
16
+ * `logFile.dir` is intentionally *not* stripped: the logger's container
17
+ * fallback (`util/logger.ts#resolveLogDir`) already redirects to the
18
+ * default log dir with a warning when the configured path can't be
19
+ * created, and stripping `dir` would disable rotating file logging
20
+ * entirely because `lifecycle.ts` gates `initLogger` on a truthy
21
+ * `config.logFile.dir`.
10
22
  */
11
23
  export function sanitizeConfigForTransfer(configJson: string): string {
12
24
  let config: Record<string, unknown>;
@@ -43,5 +55,28 @@ export function sanitizeConfigForTransfer(configJson: string): string {
43
55
  }
44
56
  }
45
57
 
58
+ // Strip hostBrowser.cdpInspect.desktopAuto — the auto-attach-to-Chrome
59
+ // behavior is gated on a macOS-originated turn; preserving a
60
+ // source-host-derived `enabled: true` inside a Linux managed pod's
61
+ // config is misleading and brittle. Preserve an explicit
62
+ // `enabled: false` opt-out, though — the schema default is `true`,
63
+ // so unconditionally stripping this subobject would re-enable
64
+ // auto-attach after a platform→local teleport.
65
+ if (config.hostBrowser && typeof config.hostBrowser === "object") {
66
+ const hostBrowser = config.hostBrowser as Record<string, unknown>;
67
+ if (hostBrowser.cdpInspect && typeof hostBrowser.cdpInspect === "object") {
68
+ const cdpInspect = hostBrowser.cdpInspect as Record<string, unknown>;
69
+ const desktopAuto = cdpInspect.desktopAuto;
70
+ const isExplicitOptOut =
71
+ desktopAuto !== null &&
72
+ typeof desktopAuto === "object" &&
73
+ !Array.isArray(desktopAuto) &&
74
+ (desktopAuto as Record<string, unknown>).enabled === false;
75
+ if (!isExplicitOptOut) {
76
+ delete cdpInspect.desktopAuto;
77
+ }
78
+ }
79
+ }
80
+
46
81
  return JSON.stringify(config, null, 2) + "\n";
47
82
  }
@@ -62,17 +62,13 @@ export {
62
62
  export type {
63
63
  ContextOverflowRecoveryConfig,
64
64
  ContextWindowConfig,
65
- Effort,
66
65
  ModelPricingOverride,
67
- Speed,
68
66
  ThinkingConfig,
69
67
  } from "./schemas/inference.js";
70
68
  export {
71
69
  ContextOverflowRecoveryConfigSchema,
72
70
  ContextWindowConfigSchema,
73
- EffortSchema,
74
71
  ModelPricingOverrideSchema,
75
- SpeedSchema,
76
72
  ThinkingConfigSchema,
77
73
  } from "./schemas/inference.js";
78
74
  export type {
@@ -87,6 +83,14 @@ export {
87
83
  } from "./schemas/ingress.js";
88
84
  export type { JournalConfig } from "./schemas/journal.js";
89
85
  export { JournalConfigSchema } from "./schemas/journal.js";
86
+ export type {
87
+ LLMCallSite,
88
+ LLMCallSiteConfig,
89
+ LLMConfig,
90
+ LLMConfigBase,
91
+ LLMConfigFragment,
92
+ } from "./schemas/llm.js";
93
+ export { LLMCallSiteEnum, LLMSchema } from "./schemas/llm.js";
90
94
  export type { AuditLogConfig, LogFileConfig } from "./schemas/logging.js";
91
95
  export {
92
96
  AuditLogConfigSchema,
@@ -239,15 +243,9 @@ import {
239
243
  import { FilingConfigSchema } from "./schemas/filing.js";
240
244
  import { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
241
245
  import { HostBrowserConfigSchema } from "./schemas/host-browser.js";
242
- import {
243
- ContextWindowConfigSchema,
244
- EffortSchema,
245
- ModelPricingOverrideSchema,
246
- SpeedSchema,
247
- ThinkingConfigSchema,
248
- } from "./schemas/inference.js";
249
246
  import { IngressConfigSchema } from "./schemas/ingress.js";
250
247
  import { JournalConfigSchema } from "./schemas/journal.js";
248
+ import { LLMSchema } from "./schemas/llm.js";
251
249
  import {
252
250
  AuditLogConfigSchema,
253
251
  LogFileConfigSchema,
@@ -276,18 +274,6 @@ import { WorkspaceGitConfigSchema } from "./schemas/workspace-git.js";
276
274
  export const AssistantConfigSchema = z
277
275
  .object({
278
276
  services: ServicesSchema.default(ServicesSchema.parse({})),
279
- maxTokens: z
280
- .number({ error: "maxTokens must be a number" })
281
- .int("maxTokens must be an integer")
282
- .positive("maxTokens must be a positive integer")
283
- .default(64000)
284
- .describe("Maximum number of output tokens per LLM response"),
285
- effort: EffortSchema,
286
- speed: SpeedSchema,
287
- thinking: ThinkingConfigSchema.default(ThinkingConfigSchema.parse({})),
288
- contextWindow: ContextWindowConfigSchema.default(
289
- ContextWindowConfigSchema.parse({}),
290
- ),
291
277
  memory: MemoryConfigSchema.default(MemoryConfigSchema.parse({})),
292
278
  dataDir: z
293
279
  .string({ error: "dataDir must be a string" })
@@ -305,12 +291,16 @@ export const AssistantConfigSchema = z
305
291
  logFile: LogFileConfigSchema.default(
306
292
  LogFileConfigSchema.parse({ dir: getDataDir() + "/logs" }),
307
293
  ),
308
- pricingOverrides: z
309
- .array(ModelPricingOverrideSchema)
310
- .default([])
311
- .describe(
312
- "Custom pricing overrides for specific provider/model combinations",
313
- ),
294
+ // Unified LLM configuration block. The unique source of truth for
295
+ // provider/model/maxTokens/effort/speed/temperature/thinking/contextWindow
296
+ // and pricing overrides for every call site in the assistant.
297
+ //
298
+ // Default values live on each leaf inside `LLMSchema` (see
299
+ // `schemas/llm.ts`), so `LLMSchema.parse({})` returns a fully-populated
300
+ // object. This matches the pattern used by sibling schemas above and
301
+ // ensures the loader's leaf-deletion recovery path can repair a partially
302
+ // invalid `llm` block without falling back to `cloneDefaultConfig()`.
303
+ llm: LLMSchema.default(LLMSchema.parse({})),
314
304
  filing: FilingConfigSchema.default(FilingConfigSchema.parse({})),
315
305
  heartbeat: HeartbeatConfigSchema.default(HeartbeatConfigSchema.parse({})),
316
306
  updates: UpdatesConfigSchema.default(UpdatesConfigSchema.parse({})),
@@ -364,30 +354,29 @@ export const AssistantConfigSchema = z
364
354
  ),
365
355
  })
366
356
  .superRefine((config, ctx) => {
357
+ const llmContextWindow = config.llm?.default?.contextWindow;
367
358
  if (
368
- config.contextWindow?.targetBudgetRatio != null &&
369
- config.contextWindow?.compactThreshold != null &&
370
- config.contextWindow.targetBudgetRatio >=
371
- config.contextWindow.compactThreshold
359
+ llmContextWindow?.targetBudgetRatio != null &&
360
+ llmContextWindow?.compactThreshold != null &&
361
+ llmContextWindow.targetBudgetRatio >= llmContextWindow.compactThreshold
372
362
  ) {
373
363
  ctx.addIssue({
374
364
  code: z.ZodIssueCode.custom,
375
- path: ["contextWindow", "targetBudgetRatio"],
365
+ path: ["llm", "default", "contextWindow", "targetBudgetRatio"],
376
366
  message:
377
- "contextWindow.targetBudgetRatio must be less than contextWindow.compactThreshold",
367
+ "llm.default.contextWindow.targetBudgetRatio must be less than llm.default.contextWindow.compactThreshold",
378
368
  });
379
369
  }
380
370
  if (
381
- config.contextWindow?.targetBudgetRatio != null &&
382
- config.contextWindow?.summaryBudgetRatio != null &&
383
- config.contextWindow.targetBudgetRatio <=
384
- config.contextWindow.summaryBudgetRatio
371
+ llmContextWindow?.targetBudgetRatio != null &&
372
+ llmContextWindow?.summaryBudgetRatio != null &&
373
+ llmContextWindow.targetBudgetRatio <= llmContextWindow.summaryBudgetRatio
385
374
  ) {
386
375
  ctx.addIssue({
387
376
  code: z.ZodIssueCode.custom,
388
- path: ["contextWindow", "targetBudgetRatio"],
377
+ path: ["llm", "default", "contextWindow", "targetBudgetRatio"],
389
378
  message:
390
- "contextWindow.targetBudgetRatio must be greater than contextWindow.summaryBudgetRatio",
379
+ "llm.default.contextWindow.targetBudgetRatio must be greater than llm.default.contextWindow.summaryBudgetRatio",
391
380
  });
392
381
  }
393
382
  const segmentation = config.memory?.segmentation;
@@ -24,28 +24,9 @@ export const AnalysisConfigSchema = z
24
24
  .describe(
25
25
  "Milliseconds of idle time after the last message before the debounced analysis job fires",
26
26
  ),
27
-
28
- // Optional model intent for the analysis agent loop. When omitted,
29
- // the analysis agent uses the same model as the main agent.
30
- // Accepted values match the main agent's model-intent vocabulary.
31
- modelIntent: z
32
- .enum(["latency-optimized", "quality-optimized", "vision-optimized"], {
33
- error: "analysis.modelIntent must be a valid model intent",
34
- })
35
- .optional()
36
- .describe(
37
- "Model selection strategy for the analysis agent loop — falls back to the main agent's model when omitted",
38
- ),
39
-
40
- // Optional explicit model override (provider/model string). Takes
41
- // precedence over modelIntent when both are set.
42
- modelOverride: z
43
- .string({ error: "analysis.modelOverride must be a string" })
44
- .optional()
45
- .describe(
46
- "Explicit model override (provider/model string) for the analysis agent loop — takes precedence over modelIntent when both are set",
47
- ),
48
27
  })
49
- .describe("Controls the auto-analyze agent loop triggered by conversation activity");
28
+ .describe(
29
+ "Controls the auto-analyze agent loop triggered by conversation activity. Model selection lives under llm.callSites.analyzeConversation.",
30
+ );
50
31
 
51
32
  export type AnalysisConfig = z.infer<typeof AnalysisConfigSchema>;
@@ -222,10 +222,6 @@ export const CallsConfigSchema = z
222
222
  ),
223
223
  safety: CallsSafetyConfigSchema.default(CallsSafetyConfigSchema.parse({})),
224
224
  voice: CallsVoiceConfigSchema.default(CallsVoiceConfigSchema.parse({})),
225
- model: z
226
- .string({ error: "calls.model must be a string" })
227
- .optional()
228
- .describe("Override the default model for phone call conversations"),
229
225
  callerIdentity: CallerIdentityConfigSchema.default(
230
226
  CallerIdentityConfigSchema.parse({}),
231
227
  ),