@vellumai/assistant 0.6.4 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -0,0 +1,137 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { shouldCaptureAgentLoopError } from "../agent/loop.js";
4
+ import { ProviderError } from "../util/errors.js";
5
+
6
+ /**
7
+ * Regression coverage for JARVIS-446 and JARVIS-513.
8
+ *
9
+ * The agent loop reports uncaught turn-processing errors to Sentry, but two
10
+ * categories of errors are user-environment noise and should not page:
11
+ *
12
+ * - JARVIS-446: billing/auth/forbidden from the provider (402/401/403). The
13
+ * user-facing error path already surfaces a credits-exhausted message; a
14
+ * Sentry issue adds no engineering signal.
15
+ * - JARVIS-513: retry-exhausted transient network errors (ECONNRESET, Bun's
16
+ * "socket closed unexpectedly", etc.). The retry loop already did its job.
17
+ *
18
+ * `shouldCaptureAgentLoopError` gates the `Sentry.captureException` call.
19
+ */
20
+ describe("shouldCaptureAgentLoopError", () => {
21
+ describe("JARVIS-446 — billing/auth/forbidden ProviderError", () => {
22
+ test("skips capture for 402 (billing exhausted)", () => {
23
+ const err = new ProviderError(
24
+ "Anthropic API error (402): credit balance too low",
25
+ "anthropic",
26
+ 402,
27
+ );
28
+ expect(shouldCaptureAgentLoopError(err)).toBe(false);
29
+ });
30
+
31
+ test("skips capture for 401 (bad API key)", () => {
32
+ const err = new ProviderError(
33
+ "Anthropic API error (401): invalid x-api-key",
34
+ "anthropic",
35
+ 401,
36
+ );
37
+ expect(shouldCaptureAgentLoopError(err)).toBe(false);
38
+ });
39
+
40
+ test("skips capture for 403 (forbidden / plan-gated)", () => {
41
+ const err = new ProviderError(
42
+ "Anthropic API error (403): permission denied",
43
+ "anthropic",
44
+ 403,
45
+ );
46
+ expect(shouldCaptureAgentLoopError(err)).toBe(false);
47
+ });
48
+
49
+ test("still captures 500 (real server error)", () => {
50
+ const err = new ProviderError(
51
+ "Anthropic API error (500): internal server error",
52
+ "anthropic",
53
+ 500,
54
+ );
55
+ expect(shouldCaptureAgentLoopError(err)).toBe(true);
56
+ });
57
+
58
+ test("still captures 400 (bad request — engineering bug)", () => {
59
+ const err = new ProviderError(
60
+ "Anthropic API error (400): invalid tool definition",
61
+ "anthropic",
62
+ 400,
63
+ );
64
+ expect(shouldCaptureAgentLoopError(err)).toBe(true);
65
+ });
66
+
67
+ test("still captures ProviderError with no status (surprise error)", () => {
68
+ const err = new ProviderError(
69
+ "Anthropic API error: unexpected internal state",
70
+ "anthropic",
71
+ );
72
+ expect(shouldCaptureAgentLoopError(err)).toBe(true);
73
+ });
74
+ });
75
+
76
+ describe("JARVIS-513 — retry-exhausted transient network errors", () => {
77
+ test("skips capture when retriesExhausted is set on an ECONNRESET", () => {
78
+ const err = Object.assign(new Error("connection reset"), {
79
+ code: "ECONNRESET",
80
+ retriesExhausted: true,
81
+ });
82
+ expect(shouldCaptureAgentLoopError(err)).toBe(false);
83
+ });
84
+
85
+ test("skips capture for Bun 'socket closed unexpectedly' with retriesExhausted", () => {
86
+ const err = new Error("The socket connection was closed unexpectedly");
87
+ (err as Error & { retriesExhausted?: boolean }).retriesExhausted = true;
88
+ expect(shouldCaptureAgentLoopError(err)).toBe(false);
89
+ });
90
+
91
+ test("skips capture for wrapped ProviderError whose cause is a transient socket error", () => {
92
+ const cause = new Error("The socket connection was closed unexpectedly");
93
+ const err = new ProviderError(
94
+ "Anthropic request failed: The socket connection was closed unexpectedly",
95
+ "anthropic",
96
+ undefined,
97
+ { cause },
98
+ );
99
+ (err as Error & { retriesExhausted?: boolean }).retriesExhausted = true;
100
+ expect(shouldCaptureAgentLoopError(err)).toBe(false);
101
+ });
102
+
103
+ test("still captures ECONNRESET when retries were NOT exhausted", () => {
104
+ // If the first attempt threw with ECONNRESET and the retry loop somehow
105
+ // didn't run (e.g. a caller bypassed RetryProvider), we still want
106
+ // visibility — `retriesExhausted` wasn't set.
107
+ const err = Object.assign(new Error("connection reset"), {
108
+ code: "ECONNRESET",
109
+ });
110
+ expect(shouldCaptureAgentLoopError(err)).toBe(true);
111
+ });
112
+
113
+ test("still captures retriesExhausted marker on a non-network error", () => {
114
+ // The suppression is narrow: only retryable-network errors with the
115
+ // marker. A 500 with retriesExhausted still merits Sentry attention.
116
+ const err = new ProviderError(
117
+ "Anthropic API error (500): internal server error",
118
+ "anthropic",
119
+ 500,
120
+ );
121
+ (err as Error & { retriesExhausted?: boolean }).retriesExhausted = true;
122
+ expect(shouldCaptureAgentLoopError(err)).toBe(true);
123
+ });
124
+ });
125
+
126
+ describe("default behavior — everything else still pages", () => {
127
+ test("captures a plain surprise Error", () => {
128
+ expect(shouldCaptureAgentLoopError(new Error("boom"))).toBe(true);
129
+ });
130
+
131
+ test("captures a TypeError", () => {
132
+ expect(shouldCaptureAgentLoopError(new TypeError("x is not a fn"))).toBe(
133
+ true,
134
+ );
135
+ });
136
+ });
137
+ });
@@ -26,12 +26,14 @@ function createMockProvider(responses: ProviderResponse[]): {
26
26
  messages: Message[];
27
27
  tools?: ToolDefinition[];
28
28
  systemPrompt?: string;
29
+ options?: SendMessageOptions;
29
30
  }[];
30
31
  } {
31
32
  const calls: {
32
33
  messages: Message[];
33
34
  tools?: ToolDefinition[];
34
35
  systemPrompt?: string;
36
+ options?: SendMessageOptions;
35
37
  }[] = [];
36
38
  let callIndex = 0;
37
39
 
@@ -43,7 +45,7 @@ function createMockProvider(responses: ProviderResponse[]): {
43
45
  systemPrompt?: string,
44
46
  options?: SendMessageOptions,
45
47
  ): Promise<ProviderResponse> {
46
- calls.push({ messages: [...messages], tools, systemPrompt });
48
+ calls.push({ messages: [...messages], tools, systemPrompt, options });
47
49
  const response = responses[callIndex] ?? responses[responses.length - 1];
48
50
  callIndex++;
49
51
 
@@ -1769,6 +1771,85 @@ describe("AgentLoop", () => {
1769
1771
  expect(messageCompletes).toHaveLength(2);
1770
1772
  });
1771
1773
 
1774
+ // Regression: when the model emits [text, tool_use] in a single turn and then
1775
+ // returns an empty response after the tool result, the loop must NOT nudge —
1776
+ // the model already delivered its reply before the tool call, and nudging
1777
+ // would trick it into re-sending the same text verbatim.
1778
+ test("does not nudge empty response when prior turn had visible text", async () => {
1779
+ const textPlusToolUseResponse: ProviderResponse = {
1780
+ content: [
1781
+ { type: "text", text: "your move, husband." },
1782
+ {
1783
+ type: "tool_use",
1784
+ id: "t1",
1785
+ name: "read_file",
1786
+ input: { path: "/note.txt" },
1787
+ },
1788
+ ],
1789
+ model: "mock-model",
1790
+ usage: { inputTokens: 10, outputTokens: 5 },
1791
+ stopReason: "tool_use",
1792
+ };
1793
+ const emptyResponse: ProviderResponse = {
1794
+ content: [],
1795
+ model: "mock-model",
1796
+ usage: { inputTokens: 10, outputTokens: 0 },
1797
+ stopReason: "end_turn",
1798
+ };
1799
+
1800
+ const { provider, calls } = createMockProvider([
1801
+ textPlusToolUseResponse,
1802
+ emptyResponse,
1803
+ ]);
1804
+
1805
+ const toolExecutor = async () => ({
1806
+ content: "noted",
1807
+ isError: false,
1808
+ });
1809
+
1810
+ const loop = new AgentLoop(
1811
+ provider,
1812
+ "system",
1813
+ {},
1814
+ dummyTools,
1815
+ toolExecutor,
1816
+ );
1817
+ const events: AgentEvent[] = [];
1818
+ const history = await loop.run([userMessage], collectEvents(events));
1819
+
1820
+ // Provider called exactly 2 times: initial [text+tool_use], then empty.
1821
+ // No third (retry) call because the prior turn had visible text.
1822
+ expect(calls).toHaveLength(2);
1823
+
1824
+ // No nudge message should appear anywhere in history.
1825
+ const nudgeInHistory = history.some(
1826
+ (m) =>
1827
+ m.role === "user" &&
1828
+ m.content.some(
1829
+ (b) =>
1830
+ b.type === "text" &&
1831
+ "text" in b &&
1832
+ (b as { text: string }).text.includes(
1833
+ "previous response was empty",
1834
+ ),
1835
+ ),
1836
+ );
1837
+ expect(nudgeInHistory).toBe(false);
1838
+
1839
+ // The [text, tool_use] assistant message is preserved in history.
1840
+ const firstAssistant = history.find((m) => m.role === "assistant");
1841
+ expect(firstAssistant).toBeDefined();
1842
+ expect(firstAssistant!.content).toEqual([
1843
+ { type: "text", text: "your move, husband." },
1844
+ {
1845
+ type: "tool_use",
1846
+ id: "t1",
1847
+ name: "read_file",
1848
+ input: { path: "/note.txt" },
1849
+ },
1850
+ ]);
1851
+ });
1852
+
1772
1853
  test("gives up after max empty response retries", async () => {
1773
1854
  const emptyResponse: ProviderResponse = {
1774
1855
  content: [],
@@ -1831,4 +1912,34 @@ describe("AgentLoop", () => {
1831
1912
  expect(calls).toHaveLength(1);
1832
1913
  expect(history).toHaveLength(2); // user + empty assistant
1833
1914
  });
1915
+
1916
+ // PR 6: callSite threading from AgentLoop.run() into provider config.
1917
+ // Verifies the per-call config exposes `callSite` so RetryProvider can route
1918
+ // through `resolveCallSiteConfig` instead of the legacy `modelIntent` path.
1919
+ test("threads callSite from AgentLoop.run() into per-call provider config", async () => {
1920
+ const { provider, calls } = createMockProvider([textResponse("ok")]);
1921
+
1922
+ const loop = new AgentLoop(provider, "system");
1923
+ await loop.run(
1924
+ [userMessage],
1925
+ () => {},
1926
+ undefined, // signal
1927
+ undefined, // requestId
1928
+ undefined, // onCheckpoint
1929
+ "heartbeatAgent",
1930
+ );
1931
+
1932
+ expect(calls).toHaveLength(1);
1933
+ expect(calls[0].options?.config?.callSite).toBe("heartbeatAgent");
1934
+ });
1935
+
1936
+ test("omits callSite from provider config when not supplied", async () => {
1937
+ const { provider, calls } = createMockProvider([textResponse("ok")]);
1938
+
1939
+ const loop = new AgentLoop(provider, "system");
1940
+ await loop.run([userMessage], () => {});
1941
+
1942
+ expect(calls).toHaveLength(1);
1943
+ expect(calls[0].options?.config?.callSite).toBeUndefined();
1944
+ });
1834
1945
  });
@@ -0,0 +1,98 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import type { Message } from "../providers/types.js";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Mock Anthropic SDK — inject a throwing stream so we can assert on the
7
+ // message format produced by the client's error-mapping path (JARVIS-390).
8
+ // ---------------------------------------------------------------------------
9
+
10
+ class FakeAPIError extends Error {
11
+ status: number | undefined;
12
+ headers: Map<string, string> = new Map();
13
+ constructor(status: number | undefined, message: string) {
14
+ super(message);
15
+ this.status = status;
16
+ this.name = "APIError";
17
+ }
18
+ }
19
+
20
+ let nextThrown: FakeAPIError | null = null;
21
+
22
+ mock.module("@anthropic-ai/sdk", () => ({
23
+ default: class MockAnthropic {
24
+ static APIError = FakeAPIError;
25
+ constructor(_args: Record<string, unknown>) {}
26
+ #streamImpl = () => ({
27
+ on() {
28
+ return this;
29
+ },
30
+ async finalMessage() {
31
+ if (nextThrown) throw nextThrown;
32
+ return {
33
+ content: [],
34
+ model: "claude-sonnet-4-6",
35
+ usage: {
36
+ input_tokens: 0,
37
+ output_tokens: 0,
38
+ cache_creation_input_tokens: 0,
39
+ cache_read_input_tokens: 0,
40
+ },
41
+ stop_reason: "end_turn",
42
+ };
43
+ },
44
+ });
45
+ messages = { stream: () => this.#streamImpl() };
46
+ beta = { messages: { stream: () => this.#streamImpl() } };
47
+ },
48
+ }));
49
+
50
+ import { AnthropicProvider } from "../providers/anthropic/client.js";
51
+ import { ProviderError } from "../util/errors.js";
52
+
53
+ function userMsg(text: string): Message {
54
+ return { role: "user", content: [{ type: "text", text }] };
55
+ }
56
+
57
+ describe("AnthropicProvider — error message formatting (JARVIS-390)", () => {
58
+ beforeEach(() => {
59
+ nextThrown = null;
60
+ });
61
+
62
+ test("omits the `(status)` parenthetical when the SDK reports no HTTP status", async () => {
63
+ // Reproduces the abort/mid-stream path where `error.status` is undefined.
64
+ nextThrown = new FakeAPIError(undefined, "Request was aborted.");
65
+
66
+ const provider = new AnthropicProvider("sk-ant-test", "claude-sonnet-4-6");
67
+
68
+ try {
69
+ await provider.sendMessage([userMsg("hi")]);
70
+ throw new Error("expected sendMessage to throw");
71
+ } catch (err) {
72
+ expect(err).toBeInstanceOf(ProviderError);
73
+ const message = (err as Error).message;
74
+ expect(message).toBe("Anthropic API error: Request was aborted.");
75
+ // Belt-and-suspenders: the literal "(undefined)" must never appear.
76
+ expect(message).not.toContain("(undefined)");
77
+ }
78
+ });
79
+
80
+ test("includes the `(status)` parenthetical when the SDK reports an HTTP status", async () => {
81
+ nextThrown = new FakeAPIError(
82
+ 402,
83
+ "Billing issue: your credit balance is too low.",
84
+ );
85
+
86
+ const provider = new AnthropicProvider("sk-ant-test", "claude-sonnet-4-6");
87
+
88
+ try {
89
+ await provider.sendMessage([userMsg("hi")]);
90
+ throw new Error("expected sendMessage to throw");
91
+ } catch (err) {
92
+ expect(err).toBeInstanceOf(ProviderError);
93
+ const message = (err as Error).message;
94
+ expect(message).toContain("Anthropic API error (402):");
95
+ expect((err as ProviderError).statusCode).toBe(402);
96
+ }
97
+ });
98
+ });
@@ -10,6 +10,15 @@ let lastStreamParams: Record<string, unknown> | null = null;
10
10
  let _lastStreamOptions: Record<string, unknown> | null = null;
11
11
  let lastConstructorArgs: Record<string, unknown> | null = null;
12
12
 
13
+ type ScriptedStreamEvent =
14
+ | { kind: "text"; text: string }
15
+ | { kind: "blockStart"; blockType?: "text" }
16
+ | { kind: "blockStop" };
17
+
18
+ // When set, the mock fires these scripted stream events in order instead of
19
+ // the default single "Hello" text event. Tests reset this in beforeEach.
20
+ let scriptedStream: ScriptedStreamEvent[] | null = null;
21
+
13
22
  const fakeResponse = {
14
23
  content: [{ type: "text", text: "Hello" }],
15
24
  model: "claude-sonnet-4-6",
@@ -50,8 +59,25 @@ mock.module("@anthropic-ai/sdk", () => ({
50
59
  return this;
51
60
  },
52
61
  async finalMessage() {
53
- // Fire text events
54
- for (const cb of handlers["text"] ?? []) cb("Hello");
62
+ if (scriptedStream) {
63
+ for (const event of scriptedStream) {
64
+ if (event.kind === "text") {
65
+ for (const cb of handlers["text"] ?? []) cb(event.text);
66
+ } else if (event.kind === "blockStart") {
67
+ for (const cb of handlers["streamEvent"] ?? [])
68
+ cb({
69
+ type: "content_block_start",
70
+ content_block: { type: event.blockType ?? "text" },
71
+ });
72
+ } else if (event.kind === "blockStop") {
73
+ for (const cb of handlers["streamEvent"] ?? [])
74
+ cb({ type: "content_block_stop" });
75
+ }
76
+ }
77
+ } else {
78
+ // Default: a single "Hello" text event (preserves existing tests).
79
+ for (const cb of handlers["text"] ?? []) cb("Hello");
80
+ }
55
81
  return fakeResponse;
56
82
  },
57
83
  };
@@ -77,6 +103,7 @@ mock.module("@anthropic-ai/sdk", () => ({
77
103
  import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../prompts/system-prompt.js";
78
104
  import {
79
105
  AnthropicProvider,
106
+ isPlaceholderSentinelText,
80
107
  PLACEHOLDER_BLOCKS_OMITTED,
81
108
  PLACEHOLDER_EMPTY_TURN,
82
109
  } from "../providers/anthropic/client.js";
@@ -144,6 +171,7 @@ describe("AnthropicProvider — Cache-Control Characterization", () => {
144
171
  lastStreamParams = null;
145
172
  _lastStreamOptions = null;
146
173
  lastConstructorArgs = null;
174
+ scriptedStream = null;
147
175
  provider = new AnthropicProvider("sk-ant-test", "claude-sonnet-4-6");
148
176
  });
149
177
 
@@ -1254,6 +1282,147 @@ describe("AnthropicProvider — Cache-Control Characterization", () => {
1254
1282
  }
1255
1283
  });
1256
1284
 
1285
+ test("streams normal text through without delay when text is not a sentinel prefix", async () => {
1286
+ scriptedStream = [
1287
+ { kind: "blockStart" },
1288
+ { kind: "text", text: "Hello world" },
1289
+ { kind: "blockStop" },
1290
+ ];
1291
+ const emitted: string[] = [];
1292
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1293
+ onEvent: (event) => {
1294
+ if (event.type === "text_delta") emitted.push(event.text);
1295
+ },
1296
+ });
1297
+ expect(emitted).toEqual(["Hello world"]);
1298
+ });
1299
+
1300
+ test("suppresses placeholder sentinel streamed as a single chunk", async () => {
1301
+ // Model echoes a sentinel in one chunk; buffer should hold it and
1302
+ // drop it on content_block_stop since it matches exactly.
1303
+ scriptedStream = [
1304
+ { kind: "blockStart" },
1305
+ { kind: "text", text: PLACEHOLDER_EMPTY_TURN },
1306
+ { kind: "blockStop" },
1307
+ ];
1308
+ const emitted: string[] = [];
1309
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1310
+ onEvent: (event) => {
1311
+ if (event.type === "text_delta") emitted.push(event.text);
1312
+ },
1313
+ });
1314
+ expect(emitted).toEqual([]);
1315
+ });
1316
+
1317
+ test("suppresses bare-variant sentinel streamed as a single chunk", async () => {
1318
+ scriptedStream = [
1319
+ { kind: "blockStart" },
1320
+ { kind: "text", text: "__PLACEHOLDER__[empty assistant turn]" },
1321
+ { kind: "blockStop" },
1322
+ ];
1323
+ const emitted: string[] = [];
1324
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1325
+ onEvent: (event) => {
1326
+ if (event.type === "text_delta") emitted.push(event.text);
1327
+ },
1328
+ });
1329
+ expect(emitted).toEqual([]);
1330
+ });
1331
+
1332
+ test("suppresses placeholder sentinel streamed across multiple chunks", async () => {
1333
+ scriptedStream = [
1334
+ { kind: "blockStart" },
1335
+ { kind: "text", text: "\x00__PLACE" },
1336
+ { kind: "text", text: "HOLDER__[empty" },
1337
+ { kind: "text", text: " assistant turn]" },
1338
+ { kind: "blockStop" },
1339
+ ];
1340
+ const emitted: string[] = [];
1341
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1342
+ onEvent: (event) => {
1343
+ if (event.type === "text_delta") emitted.push(event.text);
1344
+ },
1345
+ });
1346
+ expect(emitted).toEqual([]);
1347
+ });
1348
+
1349
+ test("flushes buffered prefix when the continuation diverges from all sentinels", async () => {
1350
+ // "__PLACEHOLDER__" is a prefix of the sentinels, so it stays buffered.
1351
+ // Once the next chunk diverges (bracket instead of the expected opening),
1352
+ // the buffer must flush.
1353
+ scriptedStream = [
1354
+ { kind: "blockStart" },
1355
+ { kind: "text", text: "__PLACEHOLDER__" },
1356
+ { kind: "text", text: " is bold in markdown" },
1357
+ { kind: "blockStop" },
1358
+ ];
1359
+ const emitted: string[] = [];
1360
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1361
+ onEvent: (event) => {
1362
+ if (event.type === "text_delta") emitted.push(event.text);
1363
+ },
1364
+ });
1365
+ expect(emitted.join("")).toBe("__PLACEHOLDER__ is bold in markdown");
1366
+ });
1367
+
1368
+ test("flushes non-sentinel residual buffer at content_block_stop", async () => {
1369
+ // If the stream ends mid-prefix, the residual must be flushed (the
1370
+ // accumulated text isn't a complete sentinel, so it's real content).
1371
+ scriptedStream = [
1372
+ { kind: "blockStart" },
1373
+ { kind: "text", text: "__PLACEHOLDER__" },
1374
+ { kind: "blockStop" },
1375
+ ];
1376
+ const emitted: string[] = [];
1377
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1378
+ onEvent: (event) => {
1379
+ if (event.type === "text_delta") emitted.push(event.text);
1380
+ },
1381
+ });
1382
+ expect(emitted).toEqual(["__PLACEHOLDER__"]);
1383
+ });
1384
+
1385
+ test("resets buffer across content blocks so a sentinel in one block doesn't poison the next", async () => {
1386
+ scriptedStream = [
1387
+ { kind: "blockStart" },
1388
+ { kind: "text", text: PLACEHOLDER_EMPTY_TURN },
1389
+ { kind: "blockStop" },
1390
+ { kind: "blockStart" },
1391
+ { kind: "text", text: "Fresh block content" },
1392
+ { kind: "blockStop" },
1393
+ ];
1394
+ const emitted: string[] = [];
1395
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
1396
+ onEvent: (event) => {
1397
+ if (event.type === "text_delta") emitted.push(event.text);
1398
+ },
1399
+ });
1400
+ expect(emitted).toEqual(["Fresh block content"]);
1401
+ });
1402
+
1403
+ test("isPlaceholderSentinelText matches sentinel with and without the null-byte prefix", () => {
1404
+ // The runtime filter must be lenient enough to catch sentinel text that
1405
+ // lost its `\x00` prefix in transit (e.g. a model echoing it back from
1406
+ // input history without reproducing the control character). Migration 222
1407
+ // handles the same two variants.
1408
+ expect(isPlaceholderSentinelText(PLACEHOLDER_EMPTY_TURN)).toBe(true);
1409
+ expect(isPlaceholderSentinelText(PLACEHOLDER_BLOCKS_OMITTED)).toBe(true);
1410
+ expect(
1411
+ isPlaceholderSentinelText("__PLACEHOLDER__[empty assistant turn]"),
1412
+ ).toBe(true);
1413
+ expect(
1414
+ isPlaceholderSentinelText("__PLACEHOLDER__[internal blocks omitted]"),
1415
+ ).toBe(true);
1416
+ // Nearby strings must NOT match — guard against over-broad matching.
1417
+ expect(isPlaceholderSentinelText("")).toBe(false);
1418
+ expect(isPlaceholderSentinelText("__PLACEHOLDER__")).toBe(false);
1419
+ expect(
1420
+ isPlaceholderSentinelText(
1421
+ "prefix __PLACEHOLDER__[empty assistant turn]",
1422
+ ),
1423
+ ).toBe(false);
1424
+ });
1425
+
1257
1426
  // -----------------------------------------------------------------------
1258
1427
  // Workspace context injection + cache control
1259
1428
  // -----------------------------------------------------------------------
@@ -56,16 +56,34 @@ mock.module("../providers/registry.js", () => ({
56
56
 
57
57
  mock.module("../config/loader.js", () => ({
58
58
  getConfig: () => ({
59
- ui: {},
60
- provider: "mock-provider",
61
- maxTokens: 4096,
62
- thinking: false,
63
- contextWindow: {
64
- maxInputTokens: 100000,
65
- thresholdTokens: 80000,
66
- preserveRecentMessages: 6,
67
- summaryModel: "mock-model",
68
- maxSummaryTokens: 512,
59
+ ui: {},
60
+ llm: {
61
+ default: {
62
+ provider: "mock-provider",
63
+ model: "mock-model",
64
+ maxTokens: 4096,
65
+ effort: "max" as const,
66
+ speed: "standard" as const,
67
+ temperature: null,
68
+ thinking: { enabled: false, streamThinking: true },
69
+ contextWindow: {
70
+ enabled: true,
71
+ maxInputTokens: 100000,
72
+ targetBudgetRatio: 0.3,
73
+ compactThreshold: 0.8,
74
+ summaryBudgetRatio: 0.05,
75
+ overflowRecovery: {
76
+ enabled: true,
77
+ safetyMarginRatio: 0.05,
78
+ maxAttempts: 3,
79
+ interactiveLatestTurnCompression: "summarize",
80
+ nonInteractiveLatestTurnCompression: "truncate",
81
+ },
82
+ },
83
+ },
84
+ profiles: {},
85
+ callSites: {},
86
+ pricingOverrides: [],
69
87
  },
70
88
  rateLimit: { maxRequestsPerMinute: 0 },
71
89
  timeouts: { permissionTimeoutSec: 300 },
@@ -187,6 +205,9 @@ mock.module("../agent/loop.js", () => ({
187
205
  getToolTokenBudget() {
188
206
  return 0;
189
207
  }
208
+ getActiveModel() {
209
+ return undefined;
210
+ }
190
211
  async run(
191
212
  _messages: Message[],
192
213
  _onEvent: (event: AgentEvent) => void,