@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,136 @@
1
+ /**
2
+ * Self-calibrating correction ratios for the token estimator.
3
+ *
4
+ * Every successful provider call returns ground-truth `usage.inputTokens`.
5
+ * By comparing that to the pre-send estimate, we can maintain a per-model
6
+ * EWMA correction ratio that multiplies future estimates — catching
7
+ * miscalibration proactively instead of waiting for provider overflow
8
+ * errors to reverse-engineer a token count from the error message.
9
+ *
10
+ * State is process-local; correction resets on restart. That is acceptable
11
+ * because the ratio converges quickly (EWMA alpha = 0.2, ~5 samples).
12
+ */
13
+
14
+ interface CalibrationState {
15
+ /** EWMA of (actual / estimated) — multiply estimates by this to correct. */
16
+ ratio: number;
17
+ /** Total samples recorded, for observability. */
18
+ sampleCount: number;
19
+ }
20
+
21
+ const CALIBRATIONS: Map<string, CalibrationState> = new Map();
22
+
23
+ /** Fast-adapting EWMA — converges to a steady state in ~5 consistent samples. */
24
+ const EWMA_ALPHA = 0.2;
25
+
26
+ /**
27
+ * Below this magnitude both numbers are noisy — a 500-token prompt with a
28
+ * 600-token usage is within normal overhead fluctuation and should not
29
+ * move the correction ratio.
30
+ */
31
+ const MIN_SAMPLE_MAGNITUDE = 500;
32
+
33
+ /**
34
+ * Outlier guard — discard samples where the ratio is more than 3x off in
35
+ * either direction. A ratio that extreme is almost always a bug (wrong
36
+ * estimate site, wrong provider, double-counting) rather than a genuine
37
+ * estimation error the calibrator should learn from.
38
+ */
39
+ const MIN_ACCEPTABLE_RATIO = 1 / 3;
40
+ const MAX_ACCEPTABLE_RATIO = 3;
41
+
42
+ function key(provider: string, model: string): string {
43
+ return `${provider}::${model}`;
44
+ }
45
+
46
+ /** Apply a single EWMA update at an exact (provider, model) key. */
47
+ function applyEwmaUpdate(provider: string, model: string, ratio: number): void {
48
+ const k = key(provider, model);
49
+ const prev = CALIBRATIONS.get(k);
50
+ const next: CalibrationState = prev
51
+ ? {
52
+ ratio: prev.ratio + EWMA_ALPHA * (ratio - prev.ratio),
53
+ sampleCount: prev.sampleCount + 1,
54
+ }
55
+ : { ratio, sampleCount: 1 };
56
+ CALIBRATIONS.set(k, next);
57
+ }
58
+
59
+ /**
60
+ * Fold a new (estimated, actual) observation into the EWMA ratio for this
61
+ * (provider, model). No-op when either number is too small to be reliable,
62
+ * or when the ratio is an outlier.
63
+ *
64
+ * When `model` is non-empty, the same observation is also folded into the
65
+ * per-provider aggregate key `(provider, "")` so callers that cannot resolve
66
+ * a specific model (early-init paths, provider-only estimate sites) still
67
+ * pick up a reasonable correction via {@link getCorrection}.
68
+ */
69
+ export function recordEstimate(
70
+ provider: string,
71
+ model: string,
72
+ estimated: number,
73
+ actual: number,
74
+ ): void {
75
+ if (estimated < MIN_SAMPLE_MAGNITUDE || actual < MIN_SAMPLE_MAGNITUDE) return;
76
+ const ratio = actual / estimated;
77
+ if (ratio < MIN_ACCEPTABLE_RATIO || ratio > MAX_ACCEPTABLE_RATIO) return;
78
+
79
+ applyEwmaUpdate(provider, model, ratio);
80
+
81
+ // Also fold into the per-provider aggregate so callers without a modelId
82
+ // fall back to a meaningful rolling correction instead of the 1.0 default.
83
+ // Skip when the caller already passed an empty model (avoids double-counting).
84
+ if (model.length > 0) {
85
+ applyEwmaUpdate(provider, "", ratio);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Correction factor to multiply a raw estimate by. Defaults to 1.0 for any
91
+ * unseen (provider, model) tuple, so first-call behavior is unchanged.
92
+ *
93
+ * When the model-specific key has no recorded samples, falls back to the
94
+ * per-provider aggregate `(provider, "")`. This covers model-alias
95
+ * mismatches where the configured model string (e.g. `claude-opus-4-6`)
96
+ * differs from the model the provider echoes back in its response
97
+ * (e.g. `claude-opus-4-6-20250514`).
98
+ */
99
+ export function getCorrection(provider: string, model: string): number {
100
+ const specific = CALIBRATIONS.get(key(provider, model));
101
+ if (specific) return specific.ratio;
102
+ if (model.length > 0) {
103
+ return CALIBRATIONS.get(key(provider, ""))?.ratio ?? 1.0;
104
+ }
105
+ return 1.0;
106
+ }
107
+
108
+ /** Test helper — clears all calibration state. */
109
+ export function resetCalibrations(): void {
110
+ CALIBRATIONS.clear();
111
+ }
112
+
113
+ /** Observability — list current calibrations for logging/debugging. */
114
+ export function getCalibrationSnapshot(): Array<{
115
+ provider: string;
116
+ model: string;
117
+ ratio: number;
118
+ samples: number;
119
+ }> {
120
+ const out: Array<{
121
+ provider: string;
122
+ model: string;
123
+ ratio: number;
124
+ samples: number;
125
+ }> = [];
126
+ for (const [k, state] of CALIBRATIONS) {
127
+ const [provider, model] = k.split("::", 2) as [string, string];
128
+ out.push({
129
+ provider,
130
+ model,
131
+ ratio: state.ratio,
132
+ samples: state.sampleCount,
133
+ });
134
+ }
135
+ return out;
136
+ }
@@ -0,0 +1,443 @@
1
+ import type {
2
+ ContentBlock,
3
+ Message,
4
+ ToolResultContent,
5
+ } from "../providers/types.js";
6
+ import { estimateTextTokens } from "./token-estimator.js";
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Constants
10
+ // ---------------------------------------------------------------------------
11
+
12
+ /** Default number of recent user-assistant exchanges to keep untouched. */
13
+ const DEFAULT_PROTECT_RECENT_TURNS = 4;
14
+
15
+ /** Default minimum reclaimable tokens required before we commit a pass. */
16
+ const DEFAULT_MIN_GAIN_TOKENS = 2_000;
17
+
18
+ /**
19
+ * Default list of tool names whose results are never wholesale-cleared.
20
+ * Matches opencode's `PRUNE_PROTECTED_TOOLS` and Claude Code's equivalent —
21
+ * protects subagent outputs and curated skill results, which are expensive
22
+ * to regenerate and usually load-bearing for the rest of the conversation.
23
+ *
24
+ * Note: ax-tree stripping still applies to protected tool results. Only the
25
+ * full-body replacement is skipped.
26
+ */
27
+ const DEFAULT_PROTECTED_TOOLS: readonly string[] = [
28
+ "Task",
29
+ "subagent",
30
+ "skill",
31
+ ];
32
+
33
+ /** Replacement body for cleared tool-result content. */
34
+ const CLEARED_TOOL_RESULT_TEXT = "[Old tool result content cleared]";
35
+
36
+ /** Replacement text for stubbed image blocks. */
37
+ const CLEARED_IMAGE_TEXT = "[image omitted]";
38
+
39
+ /** Replacement text for stubbed file blocks. */
40
+ const CLEARED_FILE_TEXT = "[file omitted]";
41
+
42
+ /**
43
+ * Regex that matches `<ax-tree>...</ax-tree>` blocks (non-greedy).
44
+ * Kept in sync with `AX_TREE_PATTERN` in `assistant/src/agent/loop.ts`; this
45
+ * module subsumes that function's responsibility for stale tool results.
46
+ */
47
+ const AX_TREE_PATTERN = /<ax-tree>[\s\S]*?<\/ax-tree>/g;
48
+
49
+ /** Placeholder inserted in place of a stripped ax-tree block. */
50
+ const AX_TREE_PLACEHOLDER = "<ax_tree_omitted />";
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Types
54
+ // ---------------------------------------------------------------------------
55
+
56
+ export interface MicrocompactOptions {
57
+ /** Preserve the last N user-assistant exchanges verbatim. Default 4. */
58
+ protectRecentTurns?: number;
59
+ /** Tool names whose results are never microcompacted (e.g. "Task", sub-agents). */
60
+ protectedTools?: string[];
61
+ /** Minimum reclaimable tokens required to bother — skip no-op passes. Default 2000. */
62
+ minGainTokens?: number;
63
+ }
64
+
65
+ export interface MicrocompactResult {
66
+ messages: Message[];
67
+ reclaimedTokens: number;
68
+ clearedToolResults: number;
69
+ /** Count of image + file blocks that were replaced with text stubs. */
70
+ clearedMedia: number;
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Public API
75
+ // ---------------------------------------------------------------------------
76
+
77
+ /**
78
+ * Deterministically compact stale content in the message history.
79
+ *
80
+ * Walks `messages` from newest to oldest. The most recent
81
+ * `protectRecentTurns` user-assistant exchanges are left untouched. In the
82
+ * older region:
83
+ *
84
+ * - Each `tool_result` whose owning tool is NOT in `protectedTools` has its
85
+ * `content` replaced with a short placeholder.
86
+ * - Every `image` / `file` block is replaced with a text stub.
87
+ * - `<ax-tree>...</ax-tree>` blocks inside any tool_result (including
88
+ * protected ones) are collapsed to a placeholder, subsuming the old
89
+ * `compactAxTreeHistory` in `assistant/src/agent/loop.ts`.
90
+ *
91
+ * The `tool_use` / `tool_result` block structure is preserved — we only
92
+ * mutate block bodies, never the block types or their pairing — so provider
93
+ * serialization remains valid after compaction.
94
+ *
95
+ * If the estimated savings (`reclaimedTokens`) is below `minGainTokens`, the
96
+ * original `messages` reference is returned unchanged. The pass is
97
+ * idempotent: re-invoking on a previously compacted history produces zero
98
+ * incremental reclaim.
99
+ */
100
+ export function microcompact(
101
+ messages: Message[],
102
+ options?: MicrocompactOptions,
103
+ ): MicrocompactResult {
104
+ const protectRecentTurns =
105
+ options?.protectRecentTurns ?? DEFAULT_PROTECT_RECENT_TURNS;
106
+ const minGainTokens = options?.minGainTokens ?? DEFAULT_MIN_GAIN_TOKENS;
107
+ const protectedToolSet = new Set(
108
+ options?.protectedTools ?? DEFAULT_PROTECTED_TOOLS,
109
+ );
110
+
111
+ if (messages.length === 0) {
112
+ return {
113
+ messages,
114
+ reclaimedTokens: 0,
115
+ clearedToolResults: 0,
116
+ clearedMedia: 0,
117
+ };
118
+ }
119
+
120
+ // Build a lookup of tool_use_id -> tool name by scanning every assistant
121
+ // message. Tool_use_ids are globally unique within a conversation so a
122
+ // single map is valid for the whole history.
123
+ const toolNameById = buildToolNameLookup(messages);
124
+
125
+ // Determine the index up to which messages are "protected" (left alone).
126
+ // Anything at index >= firstProtectedIdx is in the protected tail; the
127
+ // older region (indices < firstProtectedIdx) is where we clear.
128
+ const firstProtectedIdx = computeProtectedBoundary(
129
+ messages,
130
+ protectRecentTurns,
131
+ );
132
+
133
+ if (firstProtectedIdx <= 0) {
134
+ // Every message is protected — nothing to clear.
135
+ return {
136
+ messages,
137
+ reclaimedTokens: 0,
138
+ clearedToolResults: 0,
139
+ clearedMedia: 0,
140
+ };
141
+ }
142
+
143
+ let reclaimedTokens = 0;
144
+ let clearedToolResults = 0;
145
+ let clearedMedia = 0;
146
+ let anyChange = false;
147
+
148
+ const nextMessages: Message[] = messages.map((msg, idx) => {
149
+ if (idx >= firstProtectedIdx) return msg;
150
+
151
+ let changed = false;
152
+ const nextContent: ContentBlock[] = msg.content.map((block) => {
153
+ // guard:allow-tool-result-only — compaction here operates on locally-
154
+ // executed `tool_result` bodies (string `.content`, possible
155
+ // `.contentBlocks` media). `web_search_tool_result` has an opaque
156
+ // encrypted content shape and is never microcompacted; it's treated as
157
+ // a tool-response only in `isToolResultOnlyUserMessage` above.
158
+ if (block.type === "tool_result") {
159
+ const tr = block as ToolResultContent;
160
+ const toolName = toolNameById.get(tr.tool_use_id);
161
+ const isProtected = toolName != null && protectedToolSet.has(toolName);
162
+
163
+ const { replacement, tokensSaved, didChange, cleared } =
164
+ compactToolResult(tr, isProtected);
165
+ if (didChange) {
166
+ reclaimedTokens += tokensSaved;
167
+ if (cleared) clearedToolResults += 1;
168
+ changed = true;
169
+ return replacement;
170
+ }
171
+ return block;
172
+ }
173
+
174
+ if (block.type === "image") {
175
+ const saved = estimateImageReclaim(block);
176
+ // Only count a reclaim if stubbing actually shrinks the block.
177
+ // The stub is always valid, but avoid double-counting no-op cases.
178
+ reclaimedTokens += saved;
179
+ clearedMedia += 1;
180
+ changed = true;
181
+ return { type: "text", text: CLEARED_IMAGE_TEXT };
182
+ }
183
+
184
+ if (block.type === "file") {
185
+ const saved = estimateFileReclaim(block);
186
+ reclaimedTokens += saved;
187
+ clearedMedia += 1;
188
+ changed = true;
189
+ return { type: "text", text: CLEARED_FILE_TEXT };
190
+ }
191
+
192
+ return block;
193
+ });
194
+
195
+ if (!changed) return msg;
196
+ anyChange = true;
197
+ return { ...msg, content: nextContent };
198
+ });
199
+
200
+ if (!anyChange || reclaimedTokens < minGainTokens) {
201
+ return {
202
+ messages,
203
+ reclaimedTokens: 0,
204
+ clearedToolResults: 0,
205
+ clearedMedia: 0,
206
+ };
207
+ }
208
+
209
+ return {
210
+ messages: nextMessages,
211
+ reclaimedTokens,
212
+ clearedToolResults,
213
+ clearedMedia,
214
+ };
215
+ }
216
+
217
+ // ---------------------------------------------------------------------------
218
+ // Internals
219
+ // ---------------------------------------------------------------------------
220
+
221
+ function buildToolNameLookup(messages: Message[]): Map<string, string> {
222
+ const map = new Map<string, string>();
223
+ for (const msg of messages) {
224
+ if (msg.role !== "assistant") continue;
225
+ for (const block of msg.content) {
226
+ if (block.type === "tool_use") {
227
+ map.set(block.id, block.name);
228
+ }
229
+ }
230
+ }
231
+ return map;
232
+ }
233
+
234
+ /**
235
+ * Return the index of the first message that is inside the "protected tail".
236
+ *
237
+ * A user-assistant exchange begins at a user message that carries real user
238
+ * content (i.e. not a tool_result-only follow-up, which is how the provider
239
+ * encodes the tool response turn). We walk newest-to-oldest and, once we've
240
+ * seen `protectRecentTurns` such user-turn starts, return the index of the
241
+ * oldest such start. Everything at or after that index is protected.
242
+ *
243
+ * If the history has fewer than `protectRecentTurns` user turns, protect the
244
+ * entire history by returning 0.
245
+ */
246
+ function computeProtectedBoundary(
247
+ messages: Message[],
248
+ protectRecentTurns: number,
249
+ ): number {
250
+ if (protectRecentTurns <= 0) return messages.length;
251
+
252
+ let seen = 0;
253
+ for (let i = messages.length - 1; i >= 0; i--) {
254
+ const msg = messages[i];
255
+ if (msg.role !== "user") continue;
256
+ if (isToolResultOnlyUserMessage(msg)) continue;
257
+ seen += 1;
258
+ if (seen >= protectRecentTurns) {
259
+ return i;
260
+ }
261
+ }
262
+ // Fewer user turns than the protection budget — protect everything.
263
+ return 0;
264
+ }
265
+
266
+ /**
267
+ * A user message that contains only tool-response blocks (or system-injected
268
+ * metadata) represents the response side of a tool call rather than a fresh
269
+ * user turn.
270
+ *
271
+ * Qualifying blocks:
272
+ * - `tool_result` — locally-executed tool responses.
273
+ * - `web_search_tool_result` — server-side web-search responses. Same
274
+ * semantic as `tool_result` (paired with a prior `server_tool_use`), just
275
+ * a distinct discriminant. Missing this variant would cause these
276
+ * messages to masquerade as real user turns and eat `protectRecentTurns`
277
+ * budget on tool churn.
278
+ * - `text` blocks whose body is wholly inside `<system_notice>...</system_notice>`.
279
+ * Those are system-injected reminders/progress checks, not user-authored.
280
+ */
281
+ function isToolResultOnlyUserMessage(message: Message): boolean {
282
+ if (message.content.length === 0) return false;
283
+ return message.content.every(isToolResponseOrSystemNoticeBlock);
284
+ }
285
+
286
+ function isToolResponseOrSystemNoticeBlock(block: ContentBlock): boolean {
287
+ if (block.type === "tool_result" || block.type === "web_search_tool_result") {
288
+ return true;
289
+ }
290
+ if (block.type === "text") {
291
+ const text = block.text;
292
+ return (
293
+ text.startsWith("<system_notice>") && text.endsWith("</system_notice>")
294
+ );
295
+ }
296
+ return false;
297
+ }
298
+
299
+ /**
300
+ * Compact a single tool_result block in the stripped region.
301
+ *
302
+ * - If `isProtected` is true, we keep the body but strip `<ax-tree>` blocks
303
+ * and drop media (image/file) entries from `contentBlocks`, preserving
304
+ * any text entries so meaningful tool output isn't silently removed.
305
+ * - Otherwise we replace the body with a short placeholder and drop
306
+ * `contentBlocks` entirely.
307
+ *
308
+ * `tokensSaved` is the delta between the original and the replacement as
309
+ * measured by `estimateTextTokens`, floored at 0. `cleared` is true only when
310
+ * we fully replaced the body (i.e. counted against `clearedToolResults`).
311
+ */
312
+ function compactToolResult(
313
+ block: ToolResultContent,
314
+ isProtected: boolean,
315
+ ): {
316
+ replacement: ToolResultContent;
317
+ tokensSaved: number;
318
+ didChange: boolean;
319
+ cleared: boolean;
320
+ } {
321
+ const originalContent = block.content;
322
+ const originalContentTokens = estimateTextTokens(originalContent);
323
+
324
+ // Rich contentBlocks may include text (meaningful tool output) alongside
325
+ // media (images/files). For UNPROTECTED results we drop the entire array
326
+ // (the body is being wholesale-replaced). For PROTECTED results we keep
327
+ // text entries but strip media — images aren't the expensive part of a
328
+ // subagent result and are rarely load-bearing once the turn is stale, but
329
+ // text entries can carry real content we must not silently erase.
330
+ const originalContentBlocks = block.contentBlocks;
331
+ const hadContentBlocks =
332
+ originalContentBlocks != null && originalContentBlocks.length > 0;
333
+
334
+ let preservedContentBlocks: ContentBlock[] | undefined;
335
+ let droppedBlocksTokens = 0;
336
+ if (hadContentBlocks) {
337
+ if (isProtected) {
338
+ const kept: ContentBlock[] = [];
339
+ for (const cb of originalContentBlocks) {
340
+ if (cb.type === "text") {
341
+ kept.push(cb);
342
+ } else {
343
+ droppedBlocksTokens += estimateContentBlockTokenCost(cb);
344
+ }
345
+ }
346
+ preservedContentBlocks = kept;
347
+ } else {
348
+ for (const cb of originalContentBlocks) {
349
+ droppedBlocksTokens += estimateContentBlockTokenCost(cb);
350
+ }
351
+ preservedContentBlocks = undefined;
352
+ }
353
+ }
354
+
355
+ let newContent: string;
356
+ let cleared: boolean;
357
+ if (isProtected) {
358
+ // Strip ax-tree blocks but keep the rest of the text body.
359
+ newContent = originalContent.replace(AX_TREE_PATTERN, AX_TREE_PLACEHOLDER);
360
+ cleared = false;
361
+ } else {
362
+ newContent = CLEARED_TOOL_RESULT_TEXT;
363
+ cleared = true;
364
+ }
365
+
366
+ const newContentTokens = estimateTextTokens(newContent);
367
+ const bodyTokensSaved = originalContentTokens - newContentTokens;
368
+
369
+ const bodyChanged = newContent !== originalContent;
370
+ // A protected result with only text contentBlocks would be a no-op — nothing
371
+ // meaningful would be dropped. Only count contentBlocks as a "change" when
372
+ // we actually drop at least one entry.
373
+ const contentBlocksChanged = hadContentBlocks && droppedBlocksTokens > 0;
374
+ const didChange = bodyChanged || contentBlocksChanged;
375
+
376
+ if (!didChange) {
377
+ return {
378
+ replacement: block,
379
+ tokensSaved: 0,
380
+ didChange: false,
381
+ cleared: false,
382
+ };
383
+ }
384
+
385
+ const tokensSaved = Math.max(0, bodyTokensSaved + droppedBlocksTokens);
386
+
387
+ const replacement: ToolResultContent = {
388
+ type: "tool_result",
389
+ tool_use_id: block.tool_use_id,
390
+ content: newContent,
391
+ };
392
+ if (block.is_error != null) {
393
+ replacement.is_error = block.is_error;
394
+ }
395
+ if (preservedContentBlocks != null && preservedContentBlocks.length > 0) {
396
+ replacement.contentBlocks = preservedContentBlocks;
397
+ }
398
+
399
+ return {
400
+ replacement,
401
+ tokensSaved,
402
+ didChange,
403
+ cleared: cleared && bodyChanged,
404
+ };
405
+ }
406
+
407
+ function estimateImageReclaim(
408
+ block: Extract<ContentBlock, { type: "image" }>,
409
+ ): number {
410
+ // Base64 payloads are the expensive part of image blocks for our naive
411
+ // char/4 heuristic. The Anthropic-aware estimator in `token-estimator.ts`
412
+ // charges per-pixel — we deliberately use the simpler heuristic here so
413
+ // the reclaim number is a conservative lower bound on actual savings.
414
+ const payloadTokens = estimateTextTokens(block.source.data);
415
+ const stubTokens = estimateTextTokens(CLEARED_IMAGE_TEXT);
416
+ return Math.max(0, payloadTokens - stubTokens);
417
+ }
418
+
419
+ function estimateFileReclaim(
420
+ block: Extract<ContentBlock, { type: "file" }>,
421
+ ): number {
422
+ const payloadTokens =
423
+ estimateTextTokens(block.source.data) +
424
+ estimateTextTokens(block.extracted_text ?? "");
425
+ const stubTokens = estimateTextTokens(CLEARED_FILE_TEXT);
426
+ return Math.max(0, payloadTokens - stubTokens);
427
+ }
428
+
429
+ function estimateContentBlockTokenCost(block: ContentBlock): number {
430
+ switch (block.type) {
431
+ case "text":
432
+ return estimateTextTokens(block.text);
433
+ case "image":
434
+ return estimateTextTokens(block.source.data);
435
+ case "file":
436
+ return (
437
+ estimateTextTokens(block.source.data) +
438
+ estimateTextTokens(block.extracted_text ?? "")
439
+ );
440
+ default:
441
+ return 0;
442
+ }
443
+ }
@@ -0,0 +1,12 @@
1
+ You compress long assistant conversations into durable working memory.
2
+ Focus on actionable state, not prose.
3
+ Preserve concrete facts: goals, constraints, decisions, pending questions, file paths, commands, errors, and TODOs.
4
+ Remove repetition and stale details that were superseded.
5
+ Thread anchors: when a "Retained Thread References" section is present, each listed reply cites its parent via `→ Mxxxxxx`. If that parent appears in the Transcript, preserve its text verbatim (reactions may be aggregated as "N users reacted"). Omit when the section is absent.
6
+ Return concise markdown using these section headers exactly:
7
+ ## Goals
8
+ ## Constraints
9
+ ## Decisions
10
+ ## Open Conversations
11
+ ## Key Artifacts
12
+ ## Recent Progress
@@ -1,10 +1,27 @@
1
1
  import type {
2
2
  ContentBlock,
3
3
  Message,
4
+ Provider,
4
5
  ToolDefinition,
5
6
  } from "../providers/types.js";
7
+ import { getCorrection } from "./estimator-calibration.js";
6
8
  import { parseImageDimensions } from "./image-dimensions.js";
7
9
 
10
+ /**
11
+ * Canonical provider key used for calibration lookups and updates. Wrapper
12
+ * providers (e.g. OpenRouter routing `anthropic/*` traffic to the Messages
13
+ * API) set `tokenEstimationProvider` to the upstream provider name so the
14
+ * calibration key matches the one used when the provider actually produces
15
+ * the response. Falls back to `name` when the wrapper hint is unset.
16
+ *
17
+ * Every caller that records a sample or applies a correction must use this
18
+ * helper — otherwise wrapper-provider data is scattered across mismatched
19
+ * keys and the calibration becomes a no-op.
20
+ */
21
+ export function getCalibrationProviderKey(provider: Provider): string {
22
+ return provider.tokenEstimationProvider ?? provider.name;
23
+ }
24
+
8
25
  const CHARS_PER_TOKEN = 4;
9
26
  const MESSAGE_OVERHEAD_TOKENS = 4;
10
27
  const TEXT_BLOCK_OVERHEAD_TOKENS = 2;
@@ -103,7 +120,9 @@ function estimateAnthropicImageTokens(width: number, height: number): number {
103
120
  scaledHeight = Math.round(scaledHeight * mpScale);
104
121
  }
105
122
 
106
- return Math.ceil(scaledWidth * scaledHeight * ANTHROPIC_IMAGE_TOKENS_PER_PIXEL);
123
+ return Math.ceil(
124
+ scaledWidth * scaledHeight * ANTHROPIC_IMAGE_TOKENS_PER_PIXEL,
125
+ );
107
126
  }
108
127
 
109
128
  function estimateImageTokens(
@@ -139,13 +158,28 @@ export function estimateContentBlockTokens(
139
158
  estimateTextTokens(stableJson(block.input))
140
159
  );
141
160
  case "tool_result": {
161
+ // Mirror the Anthropic serializer in providers/anthropic/client.ts
162
+ // (toAnthropicBlockSafe): block.content is always sent as the first
163
+ // text part, and contentBlocks are appended — but only `image` and
164
+ // `text` sub-blocks survive, and `image` is filtered out when
165
+ // is_error is true. Counting every contentBlocks entry regardless
166
+ // of type overestimates the wire size and can trigger spurious
167
+ // compaction on conversations that carry e.g. thinking sub-blocks.
168
+ // OpenAI and Gemini forward error-result images normally, so the
169
+ // is_error image drop is Anthropic-specific.
170
+ const anthropicDropsErrorImage =
171
+ options?.providerName === "anthropic" && block.is_error === true;
142
172
  let tokens =
143
173
  TOOL_BLOCK_OVERHEAD_TOKENS +
144
174
  estimateTextTokens(block.tool_use_id) +
145
175
  estimateTextTokens(block.content);
146
176
  if (block.contentBlocks) {
147
177
  for (const cb of block.contentBlocks) {
148
- tokens += estimateContentBlockTokens(cb, options);
178
+ if (cb.type === "text") {
179
+ tokens += estimateContentBlockTokens(cb, options);
180
+ } else if (cb.type === "image" && !anthropicDropsErrorImage) {
181
+ tokens += estimateContentBlockTokens(cb, options);
182
+ }
149
183
  }
150
184
  }
151
185
  return tokens;
@@ -224,7 +258,13 @@ export function estimateToolsTokens(tools: ToolDefinition[]): number {
224
258
  return total;
225
259
  }
226
260
 
227
- export function estimatePromptTokens(
261
+ /**
262
+ * Raw (uncorrected) prompt-token estimate — exposed so the calibrator
263
+ * can record (raw, actual) pairs. Applying calibration to the estimate
264
+ * it uses for training would create a feedback loop that eventually
265
+ * drives the correction ratio back to 1.0 regardless of true bias.
266
+ */
267
+ export function estimatePromptTokensRaw(
228
268
  messages: Message[],
229
269
  systemPrompt?: string,
230
270
  options?: TokenEstimatorOptions,
@@ -236,6 +276,24 @@ export function estimatePromptTokens(
236
276
  return systemTokens + toolTokens + estimateMessagesTokens(messages, options);
237
277
  }
238
278
 
279
+ export function estimatePromptTokens(
280
+ messages: Message[],
281
+ systemPrompt?: string,
282
+ options?: TokenEstimatorOptions,
283
+ ): number {
284
+ const raw = estimatePromptTokensRaw(messages, systemPrompt, options);
285
+
286
+ // Apply the self-calibration correction. Default is 1.0 for any
287
+ // (provider, model) pair we haven't recorded a sample for, so first-call
288
+ // behavior is unchanged. As usage data accumulates, the correction ratio
289
+ // pulls estimates toward the provider's ground-truth token count. Lookup
290
+ // uses the per-provider aggregate key — `getCorrection` falls back to
291
+ // `(provider, "")` when a model-specific sample is not available.
292
+ const providerName = options?.providerName ?? "";
293
+ const correction = getCorrection(providerName, "");
294
+ return correction === 1.0 ? raw : Math.ceil(raw * correction);
295
+ }
296
+
239
297
  function stableJson(value: unknown): string {
240
298
  try {
241
299
  return JSON.stringify(value);