@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
@@ -81,9 +81,11 @@ function writeConfig(obj: unknown): void {
81
81
  describe("AssistantConfigSchema", () => {
82
82
  test("parses empty object with full defaults", () => {
83
83
  const result = AssistantConfigSchema.parse({});
84
- expect(result.services.inference.provider).toBe("anthropic");
85
- expect(result.services.inference.model).toBe("claude-opus-4-6");
84
+ // services.inference now carries only `mode`; provider/model live under
85
+ // llm.default.{provider,model} (see PR 19 of unify-llm-callsites).
86
86
  expect(result.services.inference.mode).toBe("your-own");
87
+ expect(result.llm.default.provider).toBe("anthropic");
88
+ expect(result.llm.default.model).toBe("claude-opus-4-7");
87
89
  expect(result.services["image-generation"].provider).toBe("gemini");
88
90
  expect(result.services["image-generation"].model).toBe(
89
91
  "gemini-3.1-flash-image-preview",
@@ -93,12 +95,12 @@ describe("AssistantConfigSchema", () => {
93
95
  "inference-provider-native",
94
96
  );
95
97
  expect(result.services["web-search"].mode).toBe("your-own");
96
- expect(result.maxTokens).toBe(64000);
97
- expect(result.thinking).toEqual({
98
+ expect(result.llm.default.maxTokens).toBe(64000);
99
+ expect(result.llm.default.thinking).toEqual({
98
100
  enabled: true,
99
101
  streamThinking: true,
100
102
  });
101
- expect(result.contextWindow).toEqual({
103
+ expect(result.llm.default.contextWindow).toEqual({
102
104
  enabled: true,
103
105
  maxInputTokens: 200000,
104
106
  targetBudgetRatio: 0.3,
@@ -134,11 +136,13 @@ describe("AssistantConfigSchema", () => {
134
136
 
135
137
  test("accepts valid complete config", () => {
136
138
  const input = {
137
- services: {
138
- inference: { provider: "openai", model: "gpt-4" },
139
+ llm: {
140
+ default: {
141
+ provider: "openai" as const,
142
+ model: "gpt-4",
143
+ maxTokens: 4096,
144
+ },
139
145
  },
140
- maxTokens: 4096,
141
- thinking: { enabled: true },
142
146
  timeouts: {
143
147
  shellDefaultTimeoutSec: 30,
144
148
  shellMaxTimeoutSec: 300,
@@ -154,13 +158,186 @@ describe("AssistantConfigSchema", () => {
154
158
  auditLog: { retentionDays: 30 },
155
159
  };
156
160
  const result = AssistantConfigSchema.parse(input);
157
- expect(result.services.inference.provider).toBe("openai");
158
- expect(result.services.inference.model).toBe("gpt-4");
159
- expect(result.maxTokens).toBe(4096);
160
- expect(result.thinking.enabled).toBe(true);
161
+ expect(result.llm.default.provider).toBe("openai");
162
+ expect(result.llm.default.model).toBe("gpt-4");
163
+ expect(result.llm.default.maxTokens).toBe(4096);
164
+ expect(result.llm.default.thinking.enabled).toBe(true);
161
165
  expect(result.secretDetection.action).toBe("block");
162
166
  });
163
167
 
168
+ test("applies llm defaults when llm key is omitted", () => {
169
+ const result = AssistantConfigSchema.parse({});
170
+ expect(result.llm).toBeDefined();
171
+ expect(result.llm.default).toEqual({
172
+ provider: "anthropic",
173
+ model: "claude-opus-4-7",
174
+ maxTokens: 64000,
175
+ effort: "max",
176
+ speed: "standard",
177
+ temperature: null,
178
+ thinking: { enabled: true, streamThinking: true },
179
+ contextWindow: {
180
+ enabled: true,
181
+ maxInputTokens: 200000,
182
+ targetBudgetRatio: 0.3,
183
+ compactThreshold: 0.8,
184
+ summaryBudgetRatio: 0.05,
185
+ overflowRecovery: {
186
+ enabled: true,
187
+ safetyMarginRatio: 0.05,
188
+ maxAttempts: 3,
189
+ interactiveLatestTurnCompression: "summarize",
190
+ nonInteractiveLatestTurnCompression: "truncate",
191
+ },
192
+ },
193
+ openrouter: { only: [] },
194
+ });
195
+ expect(result.llm.profiles).toEqual({});
196
+ expect(result.llm.callSites).toEqual({});
197
+ expect(result.llm.pricingOverrides).toEqual([]);
198
+ });
199
+
200
+ test("accepts an explicit llm block with profiles and call sites", () => {
201
+ const input = {
202
+ llm: {
203
+ default: {
204
+ provider: "anthropic" as const,
205
+ model: "claude-opus-4-7",
206
+ maxTokens: 32000,
207
+ effort: "high" as const,
208
+ speed: "fast" as const,
209
+ temperature: null,
210
+ thinking: { enabled: true, streamThinking: false },
211
+ contextWindow: {
212
+ enabled: true,
213
+ maxInputTokens: 200000,
214
+ targetBudgetRatio: 0.3,
215
+ compactThreshold: 0.8,
216
+ summaryBudgetRatio: 0.05,
217
+ overflowRecovery: {
218
+ enabled: true,
219
+ safetyMarginRatio: 0.05,
220
+ maxAttempts: 3,
221
+ interactiveLatestTurnCompression: "summarize" as const,
222
+ nonInteractiveLatestTurnCompression: "truncate" as const,
223
+ },
224
+ },
225
+ },
226
+ profiles: {
227
+ fast: { speed: "fast" as const, effort: "low" as const },
228
+ },
229
+ callSites: {
230
+ mainAgent: { profile: "fast" },
231
+ commitMessage: { maxTokens: 256 },
232
+ },
233
+ pricingOverrides: [],
234
+ },
235
+ };
236
+ const result = AssistantConfigSchema.parse(input);
237
+ expect(result.llm.default.model).toBe("claude-opus-4-7");
238
+ expect(result.llm.default.speed).toBe("fast");
239
+ expect(result.llm.profiles?.fast).toEqual({
240
+ speed: "fast",
241
+ effort: "low",
242
+ });
243
+ expect(result.llm.callSites?.mainAgent).toEqual({ profile: "fast" });
244
+ expect(result.llm.callSites?.commitMessage).toEqual({ maxTokens: 256 });
245
+ });
246
+
247
+ test("rejects an llm.callSites entry that references an undefined profile", () => {
248
+ const input = {
249
+ llm: {
250
+ default: {
251
+ provider: "anthropic" as const,
252
+ model: "claude-opus-4-6",
253
+ maxTokens: 64000,
254
+ effort: "max" as const,
255
+ speed: "standard" as const,
256
+ temperature: null,
257
+ thinking: { enabled: true, streamThinking: true },
258
+ contextWindow: {
259
+ enabled: true,
260
+ maxInputTokens: 200000,
261
+ targetBudgetRatio: 0.3,
262
+ compactThreshold: 0.8,
263
+ summaryBudgetRatio: 0.05,
264
+ overflowRecovery: {
265
+ enabled: true,
266
+ safetyMarginRatio: 0.05,
267
+ maxAttempts: 3,
268
+ interactiveLatestTurnCompression: "summarize" as const,
269
+ nonInteractiveLatestTurnCompression: "truncate" as const,
270
+ },
271
+ },
272
+ },
273
+ callSites: {
274
+ mainAgent: { profile: "missing-profile" },
275
+ },
276
+ },
277
+ };
278
+ expect(() => AssistantConfigSchema.parse(input)).toThrow(/missing-profile/);
279
+ });
280
+
281
+ test("legacy top-level inference keys are ignored after PR 19 cleanup", () => {
282
+ // The legacy keys (top-level maxTokens, effort, speed, thinking,
283
+ // contextWindow, services.inference.{provider,model}) were removed in PR
284
+ // 19. Configs that still carry them parse cleanly because Zod strips
285
+ // unknown fields, and migration 039 erases them from the on-disk file
286
+ // entirely.
287
+ const input = {
288
+ services: {
289
+ inference: { provider: "openai", model: "gpt-4" },
290
+ },
291
+ maxTokens: 8000,
292
+ effort: "medium",
293
+ speed: "fast",
294
+ thinking: { enabled: false, streamThinking: false },
295
+ };
296
+ const result = AssistantConfigSchema.parse(input);
297
+ expect((result as Record<string, unknown>).maxTokens).toBeUndefined();
298
+ expect((result as Record<string, unknown>).effort).toBeUndefined();
299
+ expect((result as Record<string, unknown>).speed).toBeUndefined();
300
+ expect((result as Record<string, unknown>).thinking).toBeUndefined();
301
+ expect(
302
+ (result.services.inference as Record<string, unknown>).provider,
303
+ ).toBeUndefined();
304
+ expect(
305
+ (result.services.inference as Record<string, unknown>).model,
306
+ ).toBeUndefined();
307
+ expect(result.llm.default.provider).toBe("anthropic");
308
+ expect(result.llm.default.model).toBe("claude-opus-4-7");
309
+ });
310
+
311
+ test("partial llm config (empty `llm: {}`) doesn't trigger full config reset", () => {
312
+ // Regression guard: previously LLMConfigBase had no schema-level defaults,
313
+ // so any `llm: {}` block would fail validation and the loader's recovery
314
+ // path would fall through to `cloneDefaultConfig()`, discarding unrelated
315
+ // valid settings (like a custom `llm.default.maxTokens`). With leaf-level
316
+ // defaults, `llm: {}` parses cleanly and the user's other settings are
317
+ // preserved.
318
+ const result = AssistantConfigSchema.parse({
319
+ llm: { default: { maxTokens: 32000 } },
320
+ });
321
+ expect(result.llm.default.maxTokens).toBe(32000);
322
+ expect(result.llm.default.provider).toBe("anthropic");
323
+ expect(result.llm.default.model).toBe("claude-opus-4-7");
324
+ });
325
+
326
+ test("llm.default with one missing field still parses (defaults applied)", () => {
327
+ // A user can override a single field of `llm.default` without specifying
328
+ // the rest — schema-level defaults fill in everything that wasn't set.
329
+ const result = AssistantConfigSchema.parse({
330
+ llm: { default: { model: "claude-haiku-4-5" } },
331
+ });
332
+ expect(result.llm.default.model).toBe("claude-haiku-4-5");
333
+ expect(result.llm.default.provider).toBe("anthropic");
334
+ expect(result.llm.default.maxTokens).toBe(64000);
335
+ expect(result.llm.default.thinking).toEqual({
336
+ enabled: true,
337
+ streamThinking: true,
338
+ });
339
+ });
340
+
164
341
  test("applies rollout defaults for dynamic budget", () => {
165
342
  const result = AssistantConfigSchema.parse({});
166
343
  expect(result.memory.retrieval.dynamicBudget).toEqual({
@@ -248,13 +425,15 @@ describe("AssistantConfigSchema", () => {
248
425
 
249
426
  test("rejects invalid provider", () => {
250
427
  const result = AssistantConfigSchema.safeParse({
251
- services: { inference: { provider: "invalid" } },
428
+ llm: { default: { provider: "invalid" } },
252
429
  });
253
430
  expect(result.success).toBe(false);
254
431
  });
255
432
 
256
- test("rejects negative maxTokens", () => {
257
- const result = AssistantConfigSchema.safeParse({ maxTokens: -100 });
433
+ test("rejects negative llm.default.maxTokens", () => {
434
+ const result = AssistantConfigSchema.safeParse({
435
+ llm: { default: { maxTokens: -100 } },
436
+ });
258
437
  expect(result.success).toBe(false);
259
438
  if (!result.success) {
260
439
  expect(
@@ -263,8 +442,10 @@ describe("AssistantConfigSchema", () => {
263
442
  }
264
443
  });
265
444
 
266
- test("rejects non-integer maxTokens", () => {
267
- const result = AssistantConfigSchema.safeParse({ maxTokens: 3.14 });
445
+ test("rejects non-integer llm.default.maxTokens", () => {
446
+ const result = AssistantConfigSchema.safeParse({
447
+ llm: { default: { maxTokens: 3.14 } },
448
+ });
268
449
  expect(result.success).toBe(false);
269
450
  if (!result.success) {
270
451
  expect(
@@ -273,9 +454,9 @@ describe("AssistantConfigSchema", () => {
273
454
  }
274
455
  });
275
456
 
276
- test("rejects string maxTokens", () => {
457
+ test("rejects string llm.default.maxTokens", () => {
277
458
  const result = AssistantConfigSchema.safeParse({
278
- maxTokens: "not-a-number",
459
+ llm: { default: { maxTokens: "not-a-number" } },
279
460
  });
280
461
  expect(result.success).toBe(false);
281
462
  if (!result.success) {
@@ -301,7 +482,7 @@ describe("AssistantConfigSchema", () => {
301
482
 
302
483
  test("rejects invalid thinking config", () => {
303
484
  const result = AssistantConfigSchema.safeParse({
304
- thinking: { enabled: "yes" },
485
+ llm: { default: { thinking: { enabled: "yes" } } },
305
486
  });
306
487
  expect(result.success).toBe(false);
307
488
  if (!result.success) {
@@ -311,16 +492,21 @@ describe("AssistantConfigSchema", () => {
311
492
 
312
493
  test("rejects contextWindow targetBudgetRatio >= compactThreshold", () => {
313
494
  const result = AssistantConfigSchema.safeParse({
314
- contextWindow: { targetBudgetRatio: 0.8, compactThreshold: 0.8 },
495
+ llm: {
496
+ default: {
497
+ contextWindow: { targetBudgetRatio: 0.8, compactThreshold: 0.8 },
498
+ },
499
+ },
315
500
  });
316
501
  expect(result.success).toBe(false);
317
502
  if (!result.success) {
318
503
  expect(
319
504
  result.error.issues.some(
320
505
  (issue) =>
321
- issue.path.join(".") === "contextWindow.targetBudgetRatio" &&
506
+ issue.path.join(".") ===
507
+ "llm.default.contextWindow.targetBudgetRatio" &&
322
508
  issue.message.includes(
323
- "must be less than contextWindow.compactThreshold",
509
+ "must be less than llm.default.contextWindow.compactThreshold",
324
510
  ),
325
511
  ),
326
512
  ).toBe(true);
@@ -330,7 +516,11 @@ describe("AssistantConfigSchema", () => {
330
516
  test("rejects overflowRecovery safetyMarginRatio out of (0,1) range", () => {
331
517
  for (const bad of [0, 1, -0.1, 1.5]) {
332
518
  const result = AssistantConfigSchema.safeParse({
333
- contextWindow: { overflowRecovery: { safetyMarginRatio: bad } },
519
+ llm: {
520
+ default: {
521
+ contextWindow: { overflowRecovery: { safetyMarginRatio: bad } },
522
+ },
523
+ },
334
524
  });
335
525
  expect(result.success).toBe(false);
336
526
  if (!result.success) {
@@ -345,8 +535,12 @@ describe("AssistantConfigSchema", () => {
345
535
 
346
536
  test("rejects invalid overflowRecovery interactiveLatestTurnCompression", () => {
347
537
  const result = AssistantConfigSchema.safeParse({
348
- contextWindow: {
349
- overflowRecovery: { interactiveLatestTurnCompression: "explode" },
538
+ llm: {
539
+ default: {
540
+ contextWindow: {
541
+ overflowRecovery: { interactiveLatestTurnCompression: "explode" },
542
+ },
543
+ },
350
544
  },
351
545
  });
352
546
  expect(result.success).toBe(false);
@@ -361,8 +555,12 @@ describe("AssistantConfigSchema", () => {
361
555
 
362
556
  test("rejects invalid overflowRecovery nonInteractiveLatestTurnCompression", () => {
363
557
  const result = AssistantConfigSchema.safeParse({
364
- contextWindow: {
365
- overflowRecovery: { nonInteractiveLatestTurnCompression: "nope" },
558
+ llm: {
559
+ default: {
560
+ contextWindow: {
561
+ overflowRecovery: { nonInteractiveLatestTurnCompression: "nope" },
562
+ },
563
+ },
366
564
  },
367
565
  });
368
566
  expect(result.success).toBe(false);
@@ -433,7 +631,7 @@ describe("AssistantConfigSchema", () => {
433
631
  "ollama",
434
632
  ] as const) {
435
633
  const result = AssistantConfigSchema.safeParse({
436
- services: { inference: { provider } },
634
+ llm: { default: { provider } },
437
635
  });
438
636
  expect(result.success).toBe(true);
439
637
  }
@@ -450,13 +648,19 @@ describe("AssistantConfigSchema", () => {
450
648
 
451
649
  test("provides helpful error messages", () => {
452
650
  const result = AssistantConfigSchema.safeParse({
453
- maxTokens: -1,
651
+ llm: { default: { maxTokens: -1 } },
454
652
  secretDetection: { action: "explode" },
455
653
  });
456
654
  expect(result.success).toBe(false);
457
655
  if (!result.success) {
458
656
  const messages = result.error.issues.map((i) => i.message);
459
- expect(messages.some((m) => m.includes("positive"))).toBe(true);
657
+ // The llm.default.maxTokens validation rejects -1 with a "Too small"
658
+ // / "expected number to be >0" message from Zod's default issue text.
659
+ expect(
660
+ messages.some(
661
+ (m) => m.includes("positive") || /expected number to be >0/i.test(m),
662
+ ),
663
+ ).toBe(true);
460
664
  expect(
461
665
  messages.some(
462
666
  (m) =>
@@ -471,6 +675,11 @@ describe("AssistantConfigSchema", () => {
471
675
  expect(result.permissions).toEqual({
472
676
  mode: "workspace",
473
677
  hostAccess: false,
678
+ autoApproveUpTo: {
679
+ conversation: "low",
680
+ background: "medium",
681
+ headless: "none",
682
+ },
474
683
  });
475
684
  });
476
685
 
@@ -507,6 +716,119 @@ describe("AssistantConfigSchema", () => {
507
716
  }
508
717
  });
509
718
 
719
+ test("defaults autoApproveUpTo to per-context object when not specified", () => {
720
+ const result = AssistantConfigSchema.parse({
721
+ permissions: { mode: "workspace" },
722
+ });
723
+ expect(result.permissions.autoApproveUpTo).toEqual({
724
+ conversation: "low",
725
+ background: "medium",
726
+ headless: "none",
727
+ });
728
+ });
729
+
730
+ test("accepts autoApproveUpTo none", () => {
731
+ const result = AssistantConfigSchema.parse({
732
+ permissions: { autoApproveUpTo: "none" },
733
+ });
734
+ expect(result.permissions.autoApproveUpTo).toBe("none");
735
+ });
736
+
737
+ test("accepts autoApproveUpTo low", () => {
738
+ const result = AssistantConfigSchema.parse({
739
+ permissions: { autoApproveUpTo: "low" },
740
+ });
741
+ expect(result.permissions.autoApproveUpTo).toBe("low");
742
+ });
743
+
744
+ test("accepts autoApproveUpTo medium", () => {
745
+ const result = AssistantConfigSchema.parse({
746
+ permissions: { autoApproveUpTo: "medium" },
747
+ });
748
+ expect(result.permissions.autoApproveUpTo).toBe("medium");
749
+ });
750
+
751
+ test("rejects autoApproveUpTo high", () => {
752
+ const result = AssistantConfigSchema.safeParse({
753
+ permissions: { autoApproveUpTo: "high" },
754
+ });
755
+ expect(result.success).toBe(false);
756
+ });
757
+
758
+ test("rejects invalid autoApproveUpTo string", () => {
759
+ const result = AssistantConfigSchema.safeParse({
760
+ permissions: { autoApproveUpTo: "everything" },
761
+ });
762
+ expect(result.success).toBe(false);
763
+ });
764
+
765
+ test("autoApproveUpTo round-trips through JSON serialization", () => {
766
+ const original = AssistantConfigSchema.parse({
767
+ permissions: { autoApproveUpTo: "medium" },
768
+ });
769
+ const json = JSON.stringify(original);
770
+ const parsed = AssistantConfigSchema.parse(JSON.parse(json));
771
+ expect(parsed.permissions.autoApproveUpTo).toBe("medium");
772
+ });
773
+
774
+ test("accepts autoApproveUpTo as per-context object", () => {
775
+ const result = AssistantConfigSchema.parse({
776
+ permissions: {
777
+ autoApproveUpTo: {
778
+ conversation: "low",
779
+ background: "medium",
780
+ headless: "none",
781
+ },
782
+ },
783
+ });
784
+ expect(result.permissions.autoApproveUpTo).toEqual({
785
+ conversation: "low",
786
+ background: "medium",
787
+ headless: "none",
788
+ });
789
+ });
790
+
791
+ test("per-context object applies defaults for omitted keys", () => {
792
+ const result = AssistantConfigSchema.parse({
793
+ permissions: {
794
+ autoApproveUpTo: {},
795
+ },
796
+ });
797
+ expect(result.permissions.autoApproveUpTo).toEqual({
798
+ conversation: "low",
799
+ background: "medium",
800
+ headless: "none",
801
+ });
802
+ });
803
+
804
+ test("per-context object rejects invalid enum values", () => {
805
+ const result = AssistantConfigSchema.safeParse({
806
+ permissions: {
807
+ autoApproveUpTo: { conversation: "high" },
808
+ },
809
+ });
810
+ expect(result.success).toBe(false);
811
+ });
812
+
813
+ test("per-context object round-trips through JSON serialization", () => {
814
+ const original = AssistantConfigSchema.parse({
815
+ permissions: {
816
+ autoApproveUpTo: {
817
+ conversation: "none",
818
+ background: "low",
819
+ headless: "medium",
820
+ },
821
+ },
822
+ });
823
+ const json = JSON.stringify(original);
824
+ const parsed = AssistantConfigSchema.parse(JSON.parse(json));
825
+ expect(parsed.permissions.autoApproveUpTo).toEqual({
826
+ conversation: "none",
827
+ background: "low",
828
+ headless: "medium",
829
+ });
830
+ });
831
+
510
832
  test("applies workspaceGit defaults including interactiveGitTimeoutMs", () => {
511
833
  const result = AssistantConfigSchema.parse({});
512
834
  expect(result.workspaceGit).toEqual({
@@ -520,11 +842,7 @@ describe("AssistantConfigSchema", () => {
520
842
  enrichmentMaxRetries: 2,
521
843
  commitMessageLLM: {
522
844
  enabled: false,
523
- useConfiguredProvider: true,
524
- providerFastModelOverrides: {},
525
845
  timeoutMs: 600,
526
- maxTokens: 120,
527
- temperature: 0.2,
528
846
  maxFilesInPrompt: 30,
529
847
  maxDiffBytes: 12000,
530
848
  minRemainingTurnBudgetMs: 1000,
@@ -578,11 +896,7 @@ describe("AssistantConfigSchema", () => {
578
896
  const result = AssistantConfigSchema.parse({});
579
897
  const llm = result.workspaceGit.commitMessageLLM;
580
898
  expect(llm.enabled).toBe(false);
581
- expect(llm.useConfiguredProvider).toBe(true);
582
- expect(llm.providerFastModelOverrides).toEqual({});
583
899
  expect(llm.timeoutMs).toBe(600);
584
- expect(llm.maxTokens).toBe(120);
585
- expect(llm.temperature).toBe(0.2);
586
900
  expect(llm.maxFilesInPrompt).toBe(30);
587
901
  expect(llm.maxDiffBytes).toBe(12000);
588
902
  expect(llm.minRemainingTurnBudgetMs).toBe(1000);
@@ -595,13 +909,6 @@ describe("AssistantConfigSchema", () => {
595
909
  expect(result.success).toBe(false);
596
910
  });
597
911
 
598
- test("rejects commitMessageLLM.temperature > 2", () => {
599
- const result = AssistantConfigSchema.safeParse({
600
- workspaceGit: { commitMessageLLM: { temperature: 2.5 } },
601
- });
602
- expect(result.success).toBe(false);
603
- });
604
-
605
912
  test("breaker settings have correct defaults", () => {
606
913
  const result = AssistantConfigSchema.parse({});
607
914
  const breaker = result.workspaceGit.commitMessageLLM.breaker;
@@ -616,14 +923,12 @@ describe("AssistantConfigSchema", () => {
616
923
  commitMessageLLM: {
617
924
  enabled: true,
618
925
  timeoutMs: 1000,
619
- temperature: 0.5,
620
926
  breaker: { openAfterFailures: 5 },
621
927
  },
622
928
  },
623
929
  });
624
930
  expect(result.workspaceGit.commitMessageLLM.enabled).toBe(true);
625
931
  expect(result.workspaceGit.commitMessageLLM.timeoutMs).toBe(1000);
626
- expect(result.workspaceGit.commitMessageLLM.temperature).toBe(0.5);
627
932
  expect(result.workspaceGit.commitMessageLLM.breaker.openAfterFailures).toBe(
628
933
  5,
629
934
  );
@@ -633,18 +938,18 @@ describe("AssistantConfigSchema", () => {
633
938
  );
634
939
  });
635
940
 
636
- test("rejects commitMessageLLM.temperature < 0", () => {
637
- const result = AssistantConfigSchema.safeParse({
638
- workspaceGit: { commitMessageLLM: { temperature: -0.1 } },
639
- });
640
- expect(result.success).toBe(false);
641
- });
642
-
643
- test("rejects non-integer commitMessageLLM.maxTokens", () => {
644
- const result = AssistantConfigSchema.safeParse({
645
- workspaceGit: { commitMessageLLM: { maxTokens: 3.5 } },
941
+ test("ignores legacy commitMessageLLM.{maxTokens,temperature} keys", () => {
942
+ // PR 19 removed maxTokens/temperature from the schema; Zod silently
943
+ // strips them on parse. Migration 039 erases them from disk so they
944
+ // don't accumulate over time.
945
+ const result = AssistantConfigSchema.parse({
946
+ workspaceGit: {
947
+ commitMessageLLM: { maxTokens: 200, temperature: 0.5 },
948
+ },
646
949
  });
647
- expect(result.success).toBe(false);
950
+ const cm = result.workspaceGit.commitMessageLLM as Record<string, unknown>;
951
+ expect(cm.maxTokens).toBeUndefined();
952
+ expect(cm.temperature).toBeUndefined();
648
953
  });
649
954
 
650
955
  // ── Calls config ────────────────────────────────────────────────────
@@ -803,16 +1108,13 @@ describe("AssistantConfigSchema", () => {
803
1108
  ).toBeUndefined();
804
1109
  });
805
1110
 
806
- test("accepts optional calls.model", () => {
1111
+ test("legacy calls.model key is stripped after PR 19 cleanup", () => {
1112
+ // calls.model moved to llm.callSites.callAgent.model in PR 4 and the
1113
+ // legacy field was removed in PR 19. Zod silently strips unknown keys.
807
1114
  const result = AssistantConfigSchema.parse({
808
1115
  calls: { model: "claude-haiku-4-5-20251001" },
809
1116
  });
810
- expect(result.calls.model).toBe("claude-haiku-4-5-20251001");
811
- });
812
-
813
- test("calls.model is undefined by default", () => {
814
- const result = AssistantConfigSchema.parse({});
815
- expect(result.calls.model).toBeUndefined();
1117
+ expect((result.calls as Record<string, unknown>).model).toBeUndefined();
816
1118
  });
817
1119
 
818
1120
  // ── Caller identity config ────────────────────────────────────────
@@ -1938,28 +2240,27 @@ describe("loadConfig with schema validation", () => {
1938
2240
  // intermittently trigger unhandled ENOENT in CI if the directory is removed.
1939
2241
  test("loads valid config", () => {
1940
2242
  writeConfig({
1941
- services: {
1942
- inference: { provider: "openai", model: "gpt-4" },
2243
+ llm: {
2244
+ default: { provider: "openai", model: "gpt-4", maxTokens: 4096 },
1943
2245
  },
1944
- maxTokens: 4096,
1945
2246
  });
1946
2247
  const config = loadConfig();
1947
- expect(config.services.inference.provider).toBe("openai");
1948
- expect(config.services.inference.model).toBe("gpt-4");
1949
- expect(config.maxTokens).toBe(4096);
2248
+ expect(config.llm.default.provider).toBe("openai");
2249
+ expect(config.llm.default.model).toBe("gpt-4");
2250
+ expect(config.llm.default.maxTokens).toBe(4096);
1950
2251
  });
1951
2252
 
1952
2253
  test("applies defaults for missing fields", () => {
1953
2254
  writeConfig({});
1954
2255
  const config = loadConfig();
1955
- expect(config.services.inference.provider).toBe("anthropic");
1956
- expect(config.services.inference.model).toBe("claude-opus-4-6");
1957
- expect(config.maxTokens).toBe(64000);
1958
- expect(config.thinking).toEqual({
2256
+ expect(config.llm.default.provider).toBe("anthropic");
2257
+ expect(config.llm.default.model).toBe("claude-opus-4-7");
2258
+ expect(config.llm.default.maxTokens).toBe(64000);
2259
+ expect(config.llm.default.thinking).toEqual({
1959
2260
  enabled: true,
1960
2261
  streamThinking: true,
1961
2262
  });
1962
- expect(config.contextWindow).toEqual({
2263
+ expect(config.llm.default.contextWindow).toEqual({
1963
2264
  enabled: true,
1964
2265
  maxInputTokens: 200000,
1965
2266
  targetBudgetRatio: 0.3,
@@ -1977,16 +2278,16 @@ describe("loadConfig with schema validation", () => {
1977
2278
 
1978
2279
  test("falls back to default for invalid provider", () => {
1979
2280
  writeConfig({
1980
- services: { inference: { provider: "invalid-provider" } },
2281
+ llm: { default: { provider: "invalid-provider" } },
1981
2282
  });
1982
2283
  const config = loadConfig();
1983
- expect(config.services.inference.provider).toBe("anthropic");
2284
+ expect(config.llm.default.provider).toBe("anthropic");
1984
2285
  });
1985
2286
 
1986
2287
  test("falls back to default for invalid maxTokens", () => {
1987
- writeConfig({ maxTokens: -100 });
2288
+ writeConfig({ llm: { default: { maxTokens: -100 } } });
1988
2289
  const config = loadConfig();
1989
- expect(config.maxTokens).toBe(64000);
2290
+ expect(config.llm.default.maxTokens).toBe(64000);
1990
2291
  });
1991
2292
 
1992
2293
  test("falls back to defaults for invalid nested values", () => {
@@ -2001,23 +2302,26 @@ describe("loadConfig with schema validation", () => {
2001
2302
 
2002
2303
  test("preserves valid fields when other fields are invalid", () => {
2003
2304
  writeConfig({
2004
- services: {
2005
- inference: { provider: "openai", model: "gpt-4" },
2305
+ llm: {
2306
+ default: {
2307
+ provider: "openai",
2308
+ model: "gpt-4",
2309
+ maxTokens: -1,
2310
+ thinking: { enabled: true },
2311
+ },
2006
2312
  },
2007
- maxTokens: -1,
2008
- thinking: { enabled: true },
2009
2313
  });
2010
2314
  const config = loadConfig();
2011
- expect(config.services.inference.provider).toBe("openai");
2012
- expect(config.services.inference.model).toBe("gpt-4");
2013
- expect(config.thinking.enabled).toBe(true);
2014
- expect(config.maxTokens).toBe(64000);
2315
+ expect(config.llm.default.provider).toBe("openai");
2316
+ expect(config.llm.default.model).toBe("gpt-4");
2317
+ expect(config.llm.default.thinking.enabled).toBe(true);
2318
+ expect(config.llm.default.maxTokens).toBe(64000);
2015
2319
  });
2016
2320
 
2017
2321
  test("handles no config file", () => {
2018
2322
  const config = loadConfig();
2019
- expect(config.services.inference.provider).toBe("anthropic");
2020
- expect(config.maxTokens).toBe(64000);
2323
+ expect(config.llm.default.provider).toBe("anthropic");
2324
+ expect(config.llm.default.maxTokens).toBe(64000);
2021
2325
  });
2022
2326
 
2023
2327
  test("partial nested objects get defaults for missing fields", () => {
@@ -2038,11 +2342,15 @@ describe("loadConfig with schema validation", () => {
2038
2342
 
2039
2343
  test("falls back for invalid contextWindow relationship", () => {
2040
2344
  writeConfig({
2041
- contextWindow: { targetBudgetRatio: 0.8, compactThreshold: 0.8 },
2345
+ llm: {
2346
+ default: {
2347
+ contextWindow: { targetBudgetRatio: 0.8, compactThreshold: 0.8 },
2348
+ },
2349
+ },
2042
2350
  });
2043
2351
  const config = loadConfig();
2044
- expect(config.contextWindow.targetBudgetRatio).toBe(0.3);
2045
- expect(config.contextWindow.compactThreshold).toBe(0.8);
2352
+ expect(config.llm.default.contextWindow.targetBudgetRatio).toBe(0.3);
2353
+ expect(config.llm.default.contextWindow.compactThreshold).toBe(0.8);
2046
2354
  });
2047
2355
 
2048
2356
  test("falls back for invalid rateLimit values", () => {
@@ -2065,6 +2373,11 @@ describe("loadConfig with schema validation", () => {
2065
2373
  expect(config.permissions).toEqual({
2066
2374
  mode: "workspace",
2067
2375
  hostAccess: false,
2376
+ autoApproveUpTo: {
2377
+ conversation: "low",
2378
+ background: "medium",
2379
+ headless: "none",
2380
+ },
2068
2381
  });
2069
2382
  });
2070
2383
 
@@ -2103,13 +2416,13 @@ describe("loadConfig with schema validation", () => {
2103
2416
  // Only activeHoursStart is set. The superRefine must emit the issue so
2104
2417
  // the loader's delete-and-retry can strip the set field; otherwise the
2105
2418
  // mismatch persists and the config falls back to full defaults (which
2106
- // would reset maxTokens below to 64000).
2419
+ // would reset llm.default.maxTokens below to 64000).
2107
2420
  writeConfig({
2108
- maxTokens: 4096,
2421
+ llm: { default: { maxTokens: 4096 } },
2109
2422
  filing: { activeHoursStart: 8 },
2110
2423
  });
2111
2424
  const config = loadConfig();
2112
- expect(config.maxTokens).toBe(4096);
2425
+ expect(config.llm.default.maxTokens).toBe(4096);
2113
2426
  expect(config.filing.activeHoursStart).toBeNull();
2114
2427
  expect(config.filing.activeHoursEnd).toBeNull();
2115
2428
  });
@@ -2117,13 +2430,13 @@ describe("loadConfig with schema validation", () => {
2117
2430
  test("recovers from partial heartbeat.activeHours without wiping unrelated fields", () => {
2118
2431
  // activeHoursStart is explicitly nulled while activeHoursEnd defaults to
2119
2432
  // 22 — a mismatch. Dual-emit strips both sides; both defaults restore
2120
- // (8, 22). maxTokens is unaffected.
2433
+ // (8, 22). llm.default.maxTokens is unaffected.
2121
2434
  writeConfig({
2122
- maxTokens: 4096,
2435
+ llm: { default: { maxTokens: 4096 } },
2123
2436
  heartbeat: { activeHoursStart: null },
2124
2437
  });
2125
2438
  const config = loadConfig();
2126
- expect(config.maxTokens).toBe(4096);
2439
+ expect(config.llm.default.maxTokens).toBe(4096);
2127
2440
  expect(config.heartbeat.activeHoursStart).toBe(8);
2128
2441
  expect(config.heartbeat.activeHoursEnd).toBe(22);
2129
2442
  });
@@ -2131,14 +2444,14 @@ describe("loadConfig with schema validation", () => {
2131
2444
  test("recovers from heartbeat.activeHours null-mismatch where explicit value equals opposite default", () => {
2132
2445
  // { start: null, end: 8 } — single-emit on the null side would strip
2133
2446
  // start, the default 8 would restore it, and the equal-hours check would
2134
- // fire, cascading to a full defaults reset that wipes maxTokens.
2447
+ // fire, cascading to a full defaults reset that wipes llm.default.maxTokens.
2135
2448
  // Dual-emit strips both sides in one pass.
2136
2449
  writeConfig({
2137
- maxTokens: 4096,
2450
+ llm: { default: { maxTokens: 4096 } },
2138
2451
  heartbeat: { activeHoursStart: null, activeHoursEnd: 8 },
2139
2452
  });
2140
2453
  const config = loadConfig();
2141
- expect(config.maxTokens).toBe(4096);
2454
+ expect(config.llm.default.maxTokens).toBe(4096);
2142
2455
  expect(config.heartbeat.activeHoursStart).toBe(8);
2143
2456
  expect(config.heartbeat.activeHoursEnd).toBe(22);
2144
2457
  });
@@ -2146,11 +2459,11 @@ describe("loadConfig with schema validation", () => {
2146
2459
  test("recovers from heartbeat.activeHours null-mismatch on the end side", () => {
2147
2460
  // { start: 22, end: null } — same cascade class as above, mirrored.
2148
2461
  writeConfig({
2149
- maxTokens: 4096,
2462
+ llm: { default: { maxTokens: 4096 } },
2150
2463
  heartbeat: { activeHoursStart: 22, activeHoursEnd: null },
2151
2464
  });
2152
2465
  const config = loadConfig();
2153
- expect(config.maxTokens).toBe(4096);
2466
+ expect(config.llm.default.maxTokens).toBe(4096);
2154
2467
  expect(config.heartbeat.activeHoursStart).toBe(8);
2155
2468
  expect(config.heartbeat.activeHoursEnd).toBe(22);
2156
2469
  });
@@ -2159,13 +2472,13 @@ describe("loadConfig with schema validation", () => {
2159
2472
  // { start: 22, end: 22 } — both equal to the default for end. Single-emit
2160
2473
  // on one path would strip one side, the default would recreate the
2161
2474
  // equal-hours mismatch, and the loader would fall back to full defaults,
2162
- // wiping maxTokens. Dual-emit strips both sides at once.
2475
+ // wiping llm.default.maxTokens. Dual-emit strips both sides at once.
2163
2476
  writeConfig({
2164
- maxTokens: 4096,
2477
+ llm: { default: { maxTokens: 4096 } },
2165
2478
  heartbeat: { activeHoursStart: 22, activeHoursEnd: 22 },
2166
2479
  });
2167
2480
  const config = loadConfig();
2168
- expect(config.maxTokens).toBe(4096);
2481
+ expect(config.llm.default.maxTokens).toBe(4096);
2169
2482
  expect(config.heartbeat.activeHoursStart).toBe(8);
2170
2483
  expect(config.heartbeat.activeHoursEnd).toBe(22);
2171
2484
  });
@@ -2174,14 +2487,14 @@ describe("loadConfig with schema validation", () => {
2174
2487
  // activeHoursStart === activeHoursEnd is invalid (empty window). Filing's
2175
2488
  // defaults are null/null, so single-emit on one path would strip one side
2176
2489
  // and the null default would recreate a mismatch — cascading to a full
2177
- // defaults reset that wipes maxTokens. Dual-emit strips both sides so
2178
- // both defaults restore to null.
2490
+ // defaults reset that wipes llm.default.maxTokens. Dual-emit strips both
2491
+ // sides so both defaults restore to null.
2179
2492
  writeConfig({
2180
- maxTokens: 1234,
2493
+ llm: { default: { maxTokens: 1234 } },
2181
2494
  filing: { activeHoursStart: 5, activeHoursEnd: 5 },
2182
2495
  });
2183
2496
  const config = loadConfig();
2184
- expect(config.maxTokens).toBe(1234);
2497
+ expect(config.llm.default.maxTokens).toBe(1234);
2185
2498
  expect(config.filing.activeHoursStart).toBeNull();
2186
2499
  expect(config.filing.activeHoursEnd).toBeNull();
2187
2500
  });
@@ -2201,7 +2514,7 @@ describe("loadConfig with schema validation", () => {
2201
2514
  expect(
2202
2515
  (config.calls.voice as Record<string, unknown>).ttsProvider,
2203
2516
  ).toBeUndefined();
2204
- expect(config.calls.model).toBeUndefined();
2517
+ expect((config.calls as Record<string, unknown>).model).toBeUndefined();
2205
2518
  expect(config.calls.callerIdentity).toEqual({
2206
2519
  allowPerCallOverride: true,
2207
2520
  });