@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
@@ -32,6 +32,7 @@ mock.module("../config/loader.js", () => ({
32
32
  }));
33
33
 
34
34
  import { buildCliProgram } from "../cli/program.js";
35
+ import type { RiskClassification } from "../permissions/checker.js";
35
36
  import { classifyRisk } from "../permissions/checker.js";
36
37
  import { RiskLevel } from "../permissions/types.js";
37
38
 
@@ -39,17 +40,17 @@ import { RiskLevel } from "../permissions/types.js";
39
40
  * Assert that a command classifies as Low risk, with a descriptive failure
40
41
  * message that guides developers toward the correct fix.
41
42
  */
42
- function expectLowRisk(command: string, actual: RiskLevel): void {
43
- if (actual !== RiskLevel.Low) {
43
+ function expectLowRisk(command: string, actual: RiskClassification): void {
44
+ if (actual.level !== RiskLevel.Low) {
44
45
  throw new Error(
45
- `"${command}" classified as ${actual} instead of Low. ` +
46
+ `"${command}" classified as ${actual.level} instead of Low. ` +
46
47
  `assistant CLI commands must be Low risk by default — the assistant ` +
47
48
  `uses its own CLI during normal operation. If you need risk ` +
48
49
  `escalation for specific subcommands, add them to the elevated ` +
49
50
  `risk tests in this guard test with justification.`,
50
51
  );
51
52
  }
52
- expect(actual).toBe(RiskLevel.Low);
53
+ expect(actual.level).toBe(RiskLevel.Low);
53
54
  }
54
55
 
55
56
  // Dynamically extract subcommand names from the CLI program definition.
@@ -84,11 +85,7 @@ describe("CLI command risk guard: assistant commands", () => {
84
85
  });
85
86
 
86
87
  test("assistant with flags classifies as Low risk", async () => {
87
- const flagCommands = [
88
- "assistant --version",
89
- "assistant --help",
90
- "assistant doctor --verbose",
91
- ];
88
+ const flagCommands = ["assistant --version", "assistant --help"];
92
89
 
93
90
  for (const command of flagCommands) {
94
91
  const risk = await classifyRisk("bash", { command });
@@ -105,56 +102,56 @@ describe("CLI command risk guard: elevated assistant subcommands", () => {
105
102
  const risk = await classifyRisk("bash", {
106
103
  command: "assistant oauth token",
107
104
  });
108
- expect(risk).toBe(RiskLevel.High);
105
+ expect(risk.level).toBe(RiskLevel.High);
109
106
  });
110
107
 
111
108
  test("assistant oauth mode --set is High risk (changes auth mode)", async () => {
112
109
  const risk = await classifyRisk("bash", {
113
110
  command: "assistant oauth mode --set managed",
114
111
  });
115
- expect(risk).toBe(RiskLevel.High);
112
+ expect(risk.level).toBe(RiskLevel.High);
116
113
  });
117
114
 
118
115
  test("assistant oauth mode --set=value is High risk (equals syntax)", async () => {
119
116
  const risk = await classifyRisk("bash", {
120
117
  command: "assistant oauth mode google --set=managed",
121
118
  });
122
- expect(risk).toBe(RiskLevel.High);
119
+ expect(risk.level).toBe(RiskLevel.High);
123
120
  });
124
121
 
125
122
  test("assistant oauth mode without --set is Low risk (read-only)", async () => {
126
123
  const risk = await classifyRisk("bash", {
127
124
  command: "assistant oauth mode",
128
125
  });
129
- expect(risk).toBe(RiskLevel.Low);
126
+ expect(risk.level).toBe(RiskLevel.Low);
130
127
  });
131
128
 
132
129
  test("assistant credentials reveal is High risk (exposes secrets)", async () => {
133
130
  const risk = await classifyRisk("bash", {
134
131
  command: "assistant credentials reveal",
135
132
  });
136
- expect(risk).toBe(RiskLevel.High);
133
+ expect(risk.level).toBe(RiskLevel.High);
137
134
  });
138
135
 
139
136
  test("assistant oauth request is Medium risk (initiates OAuth flow)", async () => {
140
137
  const risk = await classifyRisk("bash", {
141
138
  command: "assistant oauth request",
142
139
  });
143
- expect(risk).toBe(RiskLevel.Medium);
140
+ expect(risk.level).toBe(RiskLevel.Medium);
144
141
  });
145
142
 
146
143
  test("assistant oauth connect is Medium risk (modifies OAuth connections)", async () => {
147
144
  const risk = await classifyRisk("bash", {
148
145
  command: "assistant oauth connect",
149
146
  });
150
- expect(risk).toBe(RiskLevel.Medium);
147
+ expect(risk.level).toBe(RiskLevel.Medium);
151
148
  });
152
149
 
153
150
  test("assistant oauth disconnect is Medium risk (removes OAuth connections)", async () => {
154
151
  const risk = await classifyRisk("bash", {
155
152
  command: "assistant oauth disconnect",
156
153
  });
157
- expect(risk).toBe(RiskLevel.Medium);
154
+ expect(risk.level).toBe(RiskLevel.Medium);
158
155
  });
159
156
 
160
157
  test("--help on non-elevated subcommands remains Low risk", async () => {
@@ -199,12 +196,12 @@ describe("CLI command risk guard: elevated assistant subcommands", () => {
199
196
  // THEN --help does not bypass the elevated risk level
200
197
  for (const command of highRiskWithHelp) {
201
198
  const risk = await classifyRisk("bash", { command });
202
- expect(risk).toBe(RiskLevel.High);
199
+ expect(risk.level).toBe(RiskLevel.High);
203
200
  }
204
201
 
205
202
  for (const command of mediumRiskWithHelp) {
206
203
  const risk = await classifyRisk("bash", { command });
207
- expect(risk).toBe(RiskLevel.Medium);
204
+ expect(risk.level).toBe(RiskLevel.Medium);
208
205
  }
209
206
  });
210
207
 
@@ -212,14 +209,14 @@ describe("CLI command risk guard: elevated assistant subcommands", () => {
212
209
  const risk = await classifyRisk("bash", {
213
210
  command: "assistant credentials reveal 123 --service --help",
214
211
  });
215
- expect(risk).toBe(RiskLevel.High);
212
+ expect(risk.level).toBe(RiskLevel.High);
216
213
  });
217
214
 
218
215
  test("-h used as option value does not downgrade oauth mode --set risk", async () => {
219
216
  const risk = await classifyRisk("bash", {
220
217
  command: "assistant oauth mode --set -h",
221
218
  });
222
- expect(risk).toBe(RiskLevel.High);
219
+ expect(risk.level).toBe(RiskLevel.High);
223
220
  });
224
221
 
225
222
  test("non-sensitive oauth subcommands remain Low risk", async () => {
@@ -252,28 +249,28 @@ describe("CLI command risk guard: elevated assistant subcommands", () => {
252
249
  const risk = await classifyRisk("bash", {
253
250
  command: "assistant credentials set",
254
251
  });
255
- expect(risk).toBe(RiskLevel.High);
252
+ expect(risk.level).toBe(RiskLevel.High);
256
253
  });
257
254
 
258
255
  test("assistant credentials delete is High risk (removes stored credentials)", async () => {
259
256
  const risk = await classifyRisk("bash", {
260
257
  command: "assistant credentials delete",
261
258
  });
262
- expect(risk).toBe(RiskLevel.High);
259
+ expect(risk.level).toBe(RiskLevel.High);
263
260
  });
264
261
 
265
262
  test("assistant keys set is High risk (modifies API keys)", async () => {
266
263
  const risk = await classifyRisk("bash", {
267
264
  command: "assistant keys set anthropic sk-ant-xxx",
268
265
  });
269
- expect(risk).toBe(RiskLevel.High);
266
+ expect(risk.level).toBe(RiskLevel.High);
270
267
  });
271
268
 
272
269
  test("assistant keys delete is High risk (removes API keys)", async () => {
273
270
  const risk = await classifyRisk("bash", {
274
271
  command: "assistant keys delete openai",
275
272
  });
276
- expect(risk).toBe(RiskLevel.High);
273
+ expect(risk.level).toBe(RiskLevel.High);
277
274
  });
278
275
 
279
276
  test("non-sensitive keys subcommands remain Low risk", async () => {
@@ -289,14 +286,14 @@ describe("CLI command risk guard: elevated assistant subcommands", () => {
289
286
  const risk = await classifyRisk("bash", {
290
287
  command: "assistant trust remove abc123",
291
288
  });
292
- expect(risk).toBe(RiskLevel.High);
289
+ expect(risk.level).toBe(RiskLevel.High);
293
290
  });
294
291
 
295
292
  test("assistant trust clear is High risk (clears all trust rules)", async () => {
296
293
  const risk = await classifyRisk("bash", {
297
294
  command: "assistant trust clear",
298
295
  });
299
- expect(risk).toBe(RiskLevel.High);
296
+ expect(risk.level).toBe(RiskLevel.High);
300
297
  });
301
298
 
302
299
  test("non-sensitive trust subcommands remain Low risk", async () => {
@@ -314,35 +311,35 @@ describe("CLI command risk guard: wrapper program propagation", () => {
314
311
  const risk = await classifyRisk("bash", {
315
312
  command: "env assistant oauth token",
316
313
  });
317
- expect(risk).toBe(RiskLevel.High);
314
+ expect(risk.level).toBe(RiskLevel.High);
318
315
  });
319
316
 
320
317
  test("nice assistant credentials reveal is High risk", async () => {
321
318
  const risk = await classifyRisk("bash", {
322
319
  command: "nice assistant credentials reveal",
323
320
  });
324
- expect(risk).toBe(RiskLevel.High);
321
+ expect(risk.level).toBe(RiskLevel.High);
325
322
  });
326
323
 
327
324
  test("timeout 30 assistant oauth request is Medium risk", async () => {
328
325
  const risk = await classifyRisk("bash", {
329
326
  command: "timeout 30 assistant oauth request",
330
327
  });
331
- expect(risk).toBe(RiskLevel.Medium);
328
+ expect(risk.level).toBe(RiskLevel.Medium);
332
329
  });
333
330
 
334
331
  test("timeout 30 assistant oauth token is High risk", async () => {
335
332
  const risk = await classifyRisk("bash", {
336
333
  command: "timeout 30 assistant oauth token",
337
334
  });
338
- expect(risk).toBe(RiskLevel.High);
335
+ expect(risk.level).toBe(RiskLevel.High);
339
336
  });
340
337
 
341
338
  test("timeout 30 git push is Medium risk", async () => {
342
339
  const risk = await classifyRisk("bash", {
343
340
  command: "timeout 30 git push",
344
341
  });
345
- expect(risk).toBe(RiskLevel.Medium);
342
+ expect(risk.level).toBe(RiskLevel.Medium);
346
343
  });
347
344
 
348
345
  test("timeout 30 git status is Low risk", async () => {
@@ -361,7 +358,7 @@ describe("CLI command risk guard: wrapper program propagation", () => {
361
358
 
362
359
  test("env git push is Medium risk (not Low)", async () => {
363
360
  const risk = await classifyRisk("bash", { command: "env git push" });
364
- expect(risk).toBe(RiskLevel.Medium);
361
+ expect(risk.level).toBe(RiskLevel.Medium);
365
362
  });
366
363
 
367
364
  test("env git status is Low risk", async () => {
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Circuit-breaker tests for the compaction path.
3
+ *
4
+ * These exercise the tiny helpers (`isCompactionCircuitOpen`,
5
+ * `trackCompactionOutcome`) that `conversation-agent-loop.ts` uses at every
6
+ * `maybeCompact()` call site. Covering the helpers — rather than wiring up a
7
+ * full `Conversation` — keeps the test fast and isolates the breaker logic
8
+ * from the rest of the loop, which is where bugs actually hide.
9
+ *
10
+ * Acceptance criteria:
11
+ * (a) counter increments on `summaryFailed`
12
+ * (b) circuit opens after exactly 3 failures
13
+ * (c) successful compaction resets counter and circuit
14
+ * (d) open circuit skips auto-compaction but admits `force: true`
15
+ * (e) circuit re-opens after cooldown expiry when 3 more failures accumulate
16
+ * (f) call sites guard `undefined summaryFailed` so early returns do not
17
+ * reset the counter
18
+ * (g) forceCompact-style tracking: resets counter on success, increments on
19
+ * failure, preserves state on early returns
20
+ */
21
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
22
+
23
+ import {
24
+ isCompactionCircuitOpen,
25
+ trackCompactionOutcome,
26
+ } from "../daemon/conversation-agent-loop.js";
27
+ import type { ServerMessage } from "../daemon/message-protocol.js";
28
+
29
+ interface BreakerState {
30
+ consecutiveCompactionFailures: number;
31
+ compactionCircuitOpenUntil: number | null;
32
+ }
33
+
34
+ function makeState(): BreakerState {
35
+ return {
36
+ consecutiveCompactionFailures: 0,
37
+ compactionCircuitOpenUntil: null,
38
+ };
39
+ }
40
+
41
+ function collectEvents(): {
42
+ events: ServerMessage[];
43
+ onEvent: (msg: ServerMessage) => void;
44
+ } {
45
+ const events: ServerMessage[] = [];
46
+ return { events, onEvent: (msg) => events.push(msg) };
47
+ }
48
+
49
+ describe("compaction circuit breaker", () => {
50
+ let originalDateNow: () => number;
51
+
52
+ beforeEach(() => {
53
+ originalDateNow = Date.now;
54
+ });
55
+
56
+ afterEach(() => {
57
+ Date.now = originalDateNow;
58
+ });
59
+
60
+ test("(a) counter increments on each summaryFailed outcome", () => {
61
+ const state = makeState();
62
+ const { onEvent, events } = collectEvents();
63
+
64
+ trackCompactionOutcome(state, true, onEvent);
65
+ expect(state.consecutiveCompactionFailures).toBe(1);
66
+ expect(state.compactionCircuitOpenUntil).toBeNull();
67
+ expect(events).toHaveLength(0);
68
+
69
+ trackCompactionOutcome(state, true, onEvent);
70
+ expect(state.consecutiveCompactionFailures).toBe(2);
71
+ expect(state.compactionCircuitOpenUntil).toBeNull();
72
+ expect(events).toHaveLength(0);
73
+ });
74
+
75
+ test("(b) circuit opens after exactly 3 consecutive failures", () => {
76
+ const fixedNow = 1_700_000_000_000;
77
+ Date.now = () => fixedNow;
78
+
79
+ const state = makeState();
80
+ const { onEvent, events } = collectEvents();
81
+
82
+ trackCompactionOutcome(state, true, onEvent);
83
+ trackCompactionOutcome(state, true, onEvent);
84
+ // Two failures — circuit still closed.
85
+ expect(state.compactionCircuitOpenUntil).toBeNull();
86
+ expect(events).toHaveLength(0);
87
+
88
+ trackCompactionOutcome(state, true, onEvent);
89
+ // Third failure — circuit trips and fires the event exactly once.
90
+ expect(state.consecutiveCompactionFailures).toBe(3);
91
+ expect(state.compactionCircuitOpenUntil).toBe(fixedNow + 60 * 60 * 1000);
92
+ expect(events).toHaveLength(1);
93
+ expect(events[0]).toEqual({
94
+ type: "compaction_circuit_open",
95
+ reason: "3_consecutive_failures",
96
+ openUntil: fixedNow + 60 * 60 * 1000,
97
+ });
98
+
99
+ // Further failures do not re-fire the event while the circuit is open.
100
+ trackCompactionOutcome(state, true, onEvent);
101
+ expect(state.consecutiveCompactionFailures).toBe(4);
102
+ expect(events).toHaveLength(1);
103
+ });
104
+
105
+ test("(c) successful compaction resets counter and clears circuit", () => {
106
+ const fixedNow = 1_700_000_000_000;
107
+ Date.now = () => fixedNow;
108
+
109
+ const state = makeState();
110
+ const { onEvent } = collectEvents();
111
+
112
+ // Trip the breaker.
113
+ trackCompactionOutcome(state, true, onEvent);
114
+ trackCompactionOutcome(state, true, onEvent);
115
+ trackCompactionOutcome(state, true, onEvent);
116
+ expect(state.compactionCircuitOpenUntil).not.toBeNull();
117
+
118
+ // Success resets state.
119
+ trackCompactionOutcome(state, false, onEvent);
120
+ expect(state.consecutiveCompactionFailures).toBe(0);
121
+ expect(state.compactionCircuitOpenUntil).toBeNull();
122
+
123
+ // `summaryFailed` undefined (never attempted the LLM call) currently
124
+ // takes the "not failed" branch, which is why callers must guard the
125
+ // helper with `summaryFailed !== undefined` — otherwise an early-return
126
+ // `maybeCompact()` would silently reset the counter. The regression test
127
+ // below documents that invariant from the caller's perspective.
128
+ trackCompactionOutcome(state, undefined, onEvent);
129
+ expect(state.consecutiveCompactionFailures).toBe(0);
130
+ expect(state.compactionCircuitOpenUntil).toBeNull();
131
+ });
132
+
133
+ test("(d) isCompactionCircuitOpen reflects state and expiry", () => {
134
+ const fixedNow = 1_700_000_000_000;
135
+ Date.now = () => fixedNow;
136
+
137
+ const state = makeState();
138
+ expect(isCompactionCircuitOpen(state)).toBe(false);
139
+
140
+ // Trip the breaker — now open.
141
+ const { onEvent } = collectEvents();
142
+ trackCompactionOutcome(state, true, onEvent);
143
+ trackCompactionOutcome(state, true, onEvent);
144
+ trackCompactionOutcome(state, true, onEvent);
145
+ expect(isCompactionCircuitOpen(state)).toBe(true);
146
+
147
+ // After cooldown expires the helper reports closed again, even without an
148
+ // explicit reset — the open-until timestamp is the only source of truth
149
+ // for the gate.
150
+ Date.now = () => fixedNow + 60 * 60 * 1000 + 1;
151
+ expect(isCompactionCircuitOpen(state)).toBe(false);
152
+ });
153
+
154
+ test("(d) open circuit skips auto-compaction but admits force:true", () => {
155
+ // Simulate the decision the agent-loop site makes with a counter that
156
+ // only increments when compaction actually runs.
157
+ const fixedNow = 1_700_000_000_000;
158
+ Date.now = () => fixedNow;
159
+
160
+ const state = makeState();
161
+ const { onEvent } = collectEvents();
162
+
163
+ let compactionCalls = 0;
164
+ const runCompactionIfAllowed = (opts: { force?: boolean }) => {
165
+ // Mirror conversation-agent-loop.ts site 1:
166
+ // auto paths gate on !isCompactionCircuitOpen(ctx);
167
+ // force paths bypass the gate.
168
+ if (!opts.force && isCompactionCircuitOpen(state)) {
169
+ return { ran: false };
170
+ }
171
+ compactionCalls += 1;
172
+ return { ran: true };
173
+ };
174
+
175
+ // Trip the breaker.
176
+ trackCompactionOutcome(state, true, onEvent);
177
+ trackCompactionOutcome(state, true, onEvent);
178
+ trackCompactionOutcome(state, true, onEvent);
179
+ expect(isCompactionCircuitOpen(state)).toBe(true);
180
+
181
+ // Auto-path is skipped while the circuit is open.
182
+ const autoAttempt = runCompactionIfAllowed({});
183
+ expect(autoAttempt.ran).toBe(false);
184
+ expect(compactionCalls).toBe(0);
185
+
186
+ // Force-path always runs, even with the breaker open.
187
+ const forceAttempt = runCompactionIfAllowed({ force: true });
188
+ expect(forceAttempt.ran).toBe(true);
189
+ expect(compactionCalls).toBe(1);
190
+
191
+ // After a forced compaction succeeds, the counter resets and the circuit
192
+ // closes, unblocking future auto attempts.
193
+ trackCompactionOutcome(state, false, onEvent);
194
+ expect(isCompactionCircuitOpen(state)).toBe(false);
195
+ expect(state.consecutiveCompactionFailures).toBe(0);
196
+
197
+ const autoRetry = runCompactionIfAllowed({});
198
+ expect(autoRetry.ran).toBe(true);
199
+ expect(compactionCalls).toBe(2);
200
+ });
201
+
202
+ test("(e) circuit re-opens after cooldown expiry when 3 more failures accumulate", () => {
203
+ // Regression: before the fix, `trackCompactionOutcome` required
204
+ // `compactionCircuitOpenUntil === null` to open the circuit. Once a
205
+ // cooldown expired, `isCompactionCircuitOpen()` correctly reported
206
+ // "closed" but the stale past-timestamp stayed on the state, so the
207
+ // next 3-strike window could never trip a new cooldown. The fix
208
+ // treats any expired timestamp the same as null.
209
+ const t0 = 1_700_000_000_000;
210
+ Date.now = () => t0;
211
+
212
+ const state = makeState();
213
+ const { onEvent, events } = collectEvents();
214
+
215
+ // Trip the breaker the first time.
216
+ trackCompactionOutcome(state, true, onEvent);
217
+ trackCompactionOutcome(state, true, onEvent);
218
+ trackCompactionOutcome(state, true, onEvent);
219
+ expect(state.compactionCircuitOpenUntil).toBe(t0 + 60 * 60 * 1000);
220
+ expect(events).toHaveLength(1);
221
+
222
+ // Advance past the cooldown window. Manually reset the counter — in
223
+ // production this happens when a subsequent `maybeCompact()` call
224
+ // succeeds (`summaryFailed: false`) after the cooldown elapses, but
225
+ // the bug manifests even when the counter is reset: the stale
226
+ // `compactionCircuitOpenUntil` is what breaks re-opening.
227
+ const t1 = t0 + 60 * 60 * 1000 + 1;
228
+ Date.now = () => t1;
229
+ expect(isCompactionCircuitOpen(state)).toBe(false);
230
+ state.consecutiveCompactionFailures = 0;
231
+ // `compactionCircuitOpenUntil` is deliberately left as the old
232
+ // timestamp to reproduce the bug condition — in practice the null
233
+ // reset only happens on `summaryFailed: false`.
234
+ expect(state.compactionCircuitOpenUntil).toBe(t0 + 60 * 60 * 1000);
235
+
236
+ // Three more failures must trip a fresh cooldown even though the
237
+ // old timestamp is still set.
238
+ trackCompactionOutcome(state, true, onEvent);
239
+ trackCompactionOutcome(state, true, onEvent);
240
+ trackCompactionOutcome(state, true, onEvent);
241
+ expect(state.consecutiveCompactionFailures).toBe(3);
242
+ expect(state.compactionCircuitOpenUntil).toBe(t1 + 60 * 60 * 1000);
243
+ expect(events).toHaveLength(2);
244
+ expect(events[1]).toEqual({
245
+ type: "compaction_circuit_open",
246
+ reason: "3_consecutive_failures",
247
+ openUntil: t1 + 60 * 60 * 1000,
248
+ });
249
+ });
250
+
251
+ test("(f) call sites guard undefined summaryFailed so early returns don't reset the counter", () => {
252
+ // Regression: `maybeCompact()` returns `summaryFailed: undefined` on
253
+ // early-return paths (no eligible messages, below threshold, cooldown
254
+ // active, truncation-only). Before the fix, the agent loop called
255
+ // `trackCompactionOutcome(ctx, compacted.summaryFailed, onEvent)`
256
+ // unconditionally — `undefined` took the else branch and silently
257
+ // reset the 3-strike counter. Callers must now guard with
258
+ // `summaryFailed !== undefined` at every call site.
259
+ const state = makeState();
260
+ const { onEvent } = collectEvents();
261
+
262
+ // Accumulate two failures, close to tripping the breaker.
263
+ trackCompactionOutcome(state, true, onEvent);
264
+ trackCompactionOutcome(state, true, onEvent);
265
+ expect(state.consecutiveCompactionFailures).toBe(2);
266
+
267
+ // Simulate an early-return result from maybeCompact() (e.g. below
268
+ // threshold) — callers must skip the tracking call entirely.
269
+ const earlyReturn = {
270
+ compacted: false,
271
+ summaryFailed: undefined as boolean | undefined,
272
+ };
273
+ if (earlyReturn.summaryFailed !== undefined) {
274
+ trackCompactionOutcome(state, earlyReturn.summaryFailed, onEvent);
275
+ }
276
+ // Counter preserved — the early return did not reset progress toward
277
+ // tripping the breaker.
278
+ expect(state.consecutiveCompactionFailures).toBe(2);
279
+
280
+ // A third real failure then trips the breaker as expected.
281
+ trackCompactionOutcome(state, true, onEvent);
282
+ expect(state.consecutiveCompactionFailures).toBe(3);
283
+ expect(state.compactionCircuitOpenUntil).not.toBeNull();
284
+ });
285
+
286
+ test("(g) forceCompact-style tracking resets counter on success, increments on failure", () => {
287
+ // Regression: `Conversation.forceCompact()` previously didn't track
288
+ // circuit-breaker outcomes. A successful user `/compact` wouldn't clear
289
+ // an accumulating counter and a failed forced compaction wouldn't
290
+ // contribute to tripping the breaker. The fix calls
291
+ // `trackCompactionOutcome(this, result.summaryFailed, this.sendToClient)`
292
+ // after `maybeCompact` — guarded by `summaryFailed !== undefined` so
293
+ // early-return paths don't reset the counter.
294
+ const state = makeState();
295
+ const { onEvent } = collectEvents();
296
+
297
+ // Simulate forceCompact: call maybeCompact with force:true, then
298
+ // track the outcome the same way forceCompact now does.
299
+ const trackForceCompact = (result: {
300
+ summaryFailed?: boolean;
301
+ compacted: boolean;
302
+ }): void => {
303
+ if (result.summaryFailed !== undefined) {
304
+ trackCompactionOutcome(state, result.summaryFailed, onEvent);
305
+ }
306
+ };
307
+
308
+ // Two failures via the auto path …
309
+ trackCompactionOutcome(state, true, onEvent);
310
+ trackCompactionOutcome(state, true, onEvent);
311
+ expect(state.consecutiveCompactionFailures).toBe(2);
312
+
313
+ // … then the user hits /compact and the forced call succeeds. This
314
+ // must clear the stuck counter so the conversation isn't one
315
+ // auto-failure away from a cooldown.
316
+ trackForceCompact({ summaryFailed: false, compacted: true });
317
+ expect(state.consecutiveCompactionFailures).toBe(0);
318
+ expect(state.compactionCircuitOpenUntil).toBeNull();
319
+
320
+ // Conversely, three forced failures must trip the breaker too — a
321
+ // run of broken summaries is a provider-health signal regardless of
322
+ // whether the caller bypassed the breaker.
323
+ trackForceCompact({ summaryFailed: true, compacted: true });
324
+ trackForceCompact({ summaryFailed: true, compacted: true });
325
+ trackForceCompact({ summaryFailed: true, compacted: true });
326
+ expect(state.consecutiveCompactionFailures).toBe(3);
327
+ expect(state.compactionCircuitOpenUntil).not.toBeNull();
328
+
329
+ // An early-return forceCompact (e.g. no eligible messages) must not
330
+ // reset the counter — the breaker should stay open.
331
+ const wasOpenUntil = state.compactionCircuitOpenUntil;
332
+ trackForceCompact({ summaryFailed: undefined, compacted: false });
333
+ expect(state.consecutiveCompactionFailures).toBe(3);
334
+ expect(state.compactionCircuitOpenUntil).toBe(wasOpenUntil);
335
+ });
336
+ });
@@ -71,7 +71,7 @@ function makeLongMessages(turns: number): Message[] {
71
71
 
72
72
  function makeConfig() {
73
73
  return {
74
- ...DEFAULT_CONFIG.contextWindow,
74
+ ...DEFAULT_CONFIG.llm.default.contextWindow,
75
75
  maxInputTokens: 6000,
76
76
  targetBudgetRatio: 0.58,
77
77
  compactThreshold: 0.6,
@@ -10,30 +10,27 @@ describe("AnalysisConfigSchema", () => {
10
10
  const parsed = AnalysisConfigSchema.parse({});
11
11
  expect(parsed.batchSize).toBe(30);
12
12
  expect(parsed.idleTimeoutMs).toBe(600_000);
13
- expect(parsed.modelIntent).toBeUndefined();
14
- expect(parsed.modelOverride).toBeUndefined();
15
13
  });
16
14
 
17
- test("custom values round-trip", () => {
15
+ test("custom batch/idle values round-trip", () => {
18
16
  const input = {
19
17
  batchSize: 50,
20
18
  idleTimeoutMs: 120_000,
21
- modelIntent: "quality-optimized" as const,
22
- modelOverride: "anthropic/claude-opus-4-6",
23
19
  };
24
20
  const parsed = AnalysisConfigSchema.parse(input);
25
21
  expect(parsed).toEqual(input);
26
22
  });
27
23
 
28
- test("accepts each valid modelIntent value", () => {
29
- for (const intent of [
30
- "latency-optimized",
31
- "quality-optimized",
32
- "vision-optimized",
33
- ] as const) {
34
- const parsed = AnalysisConfigSchema.parse({ modelIntent: intent });
35
- expect(parsed.modelIntent).toBe(intent);
36
- }
24
+ test("legacy modelIntent/modelOverride are stripped after PR 19 cleanup", () => {
25
+ // Both fields moved to llm.callSites.analyzeConversation in PR 4 and
26
+ // were removed from the schema in PR 19. Zod silently strips unknown
27
+ // keys; migration 039 erases them from disk.
28
+ const parsed = AnalysisConfigSchema.parse({
29
+ modelIntent: "quality-optimized",
30
+ modelOverride: "anthropic/claude-opus-4-6",
31
+ });
32
+ expect((parsed as Record<string, unknown>).modelIntent).toBeUndefined();
33
+ expect((parsed as Record<string, unknown>).modelOverride).toBeUndefined();
37
34
  });
38
35
 
39
36
  test("rejects batchSize: 0 (must be positive)", () => {
@@ -60,18 +57,6 @@ describe("AnalysisConfigSchema", () => {
60
57
  const result = AnalysisConfigSchema.safeParse({ idleTimeoutMs: -1000 });
61
58
  expect(result.success).toBe(false);
62
59
  });
63
-
64
- test("rejects invalid modelIntent value", () => {
65
- const result = AnalysisConfigSchema.safeParse({
66
- modelIntent: "bogus-intent",
67
- });
68
- expect(result.success).toBe(false);
69
- });
70
-
71
- test("rejects non-string modelOverride", () => {
72
- const result = AnalysisConfigSchema.safeParse({ modelOverride: 42 });
73
- expect(result.success).toBe(false);
74
- });
75
60
  });
76
61
 
77
62
  describe("AssistantConfigSchema — analysis integration", () => {
@@ -88,13 +73,11 @@ describe("AssistantConfigSchema — analysis integration", () => {
88
73
  analysis: {
89
74
  batchSize: 15,
90
75
  idleTimeoutMs: 300_000,
91
- modelIntent: "latency-optimized",
92
76
  },
93
77
  });
94
78
  expect(parsed.analysis).toEqual({
95
79
  batchSize: 15,
96
80
  idleTimeoutMs: 300_000,
97
- modelIntent: "latency-optimized",
98
81
  });
99
82
  });
100
83
  });