@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
@@ -60,7 +60,7 @@ export function buildMemoryRollup(scopeId: string): string {
60
60
  and(
61
61
  sql`${memoryGraphNodes.fidelity} != 'gone'`,
62
62
  eq(memoryGraphNodes.scopeId, scopeId),
63
- )
63
+ ),
64
64
  )
65
65
  .orderBy(desc(memoryGraphNodes.significance))
66
66
  .limit(60)
@@ -111,19 +111,21 @@ function buildNewItemsDiff(scopeId: string): string {
111
111
  WHERE fidelity != 'gone' AND scope_id = ? AND created > ?
112
112
  ORDER BY created DESC LIMIT 20`,
113
113
  scopeId,
114
- lastGenAt
114
+ lastGenAt,
115
115
  );
116
116
 
117
117
  if (newItems.length === 0) return "";
118
118
 
119
119
  return (
120
120
  "## New since last generation\n" +
121
- newItems.map((i) => {
122
- const nl = i.content.indexOf("\n");
123
- const subject = nl >= 0 ? i.content.slice(0, nl) : i.content;
124
- const statement = nl >= 0 ? i.content.slice(nl + 1) : i.content;
125
- return `- (${i.kind}) ${subject}: ${statement}`;
126
- }).join("\n")
121
+ newItems
122
+ .map((i) => {
123
+ const nl = i.content.indexOf("\n");
124
+ const subject = nl >= 0 ? i.content.slice(0, nl) : i.content;
125
+ const statement = nl >= 0 ? i.content.slice(nl + 1) : i.content;
126
+ return `- (${i.kind}) ${subject}: ${statement}`;
127
+ })
128
+ .join("\n")
127
129
  );
128
130
  }
129
131
 
@@ -162,7 +164,8 @@ export const CONVERSATION_STARTER_CATEGORIES = [
162
164
  "integration",
163
165
  ] as const;
164
166
 
165
- export type ConversationStarterCategory = typeof CONVERSATION_STARTER_CATEGORIES[number];
167
+ export type ConversationStarterCategory =
168
+ (typeof CONVERSATION_STARTER_CATEGORIES)[number];
166
169
 
167
170
  interface GeneratedStarter {
168
171
  label: string;
@@ -171,7 +174,7 @@ interface GeneratedStarter {
171
174
  }
172
175
 
173
176
  async function generateStarters(scopeId: string): Promise<GeneratedStarter[]> {
174
- const provider = await getConfiguredProvider();
177
+ const provider = await getConfiguredProvider("conversationStarters");
175
178
  if (!provider) {
176
179
  log.info("No configured provider for conversation starters generation");
177
180
  return [];
@@ -288,7 +291,7 @@ Bad → Good (incomplete phrase → complete):
288
291
  const response = await provider.sendMessage(
289
292
  [
290
293
  userMessage(
291
- "Generate personalized conversation starters based on my context."
294
+ "Generate personalized conversation starters based on my context.",
292
295
  ),
293
296
  ],
294
297
  [
@@ -330,7 +333,7 @@ Bad → Good (incomplete phrase → complete):
330
333
  systemPrompt,
331
334
  {
332
335
  config: {
333
- modelIntent: "quality-optimized",
336
+ callSite: "conversationStarters" as const,
334
337
  max_tokens: 2048,
335
338
  tool_choice: {
336
339
  type: "tool" as const,
@@ -338,14 +341,14 @@ Bad → Good (incomplete phrase → complete):
338
341
  },
339
342
  },
340
343
  signal,
341
- }
344
+ },
342
345
  );
343
346
  cleanup();
344
347
 
345
348
  const toolBlock = extractToolUse(response);
346
349
  if (!toolBlock) {
347
350
  log.warn(
348
- "No tool_use block in conversation starters generation response"
351
+ "No tool_use block in conversation starters generation response",
349
352
  );
350
353
  return [];
351
354
  }
@@ -363,7 +366,7 @@ Bad → Good (incomplete phrase → complete):
363
366
  s.label.length > 0 &&
364
367
  s.label.length <= 40 &&
365
368
  typeof s.prompt === "string" &&
366
- s.prompt.length > 0
369
+ s.prompt.length > 0,
367
370
  )
368
371
  .slice(0, 4)
369
372
  .map((s) => ({
@@ -372,7 +375,7 @@ Bad → Good (incomplete phrase → complete):
372
375
  category:
373
376
  typeof s.category === "string" &&
374
377
  (CONVERSATION_STARTER_CATEGORIES as readonly string[]).includes(
375
- s.category
378
+ s.category,
376
379
  )
377
380
  ? s.category
378
381
  : "productivity",
@@ -386,7 +389,7 @@ Bad → Good (incomplete phrase → complete):
386
389
  // ── Job handler ───────────────────────────────────────────────────
387
390
 
388
391
  export async function generateConversationStartersJob(
389
- job: MemoryJob
392
+ job: MemoryJob,
390
393
  ): Promise<void> {
391
394
  const scopeId = asString(job.payload.scopeId) ?? "default";
392
395
 
@@ -419,7 +422,7 @@ export async function generateConversationStartersJob(
419
422
  and(
420
423
  sql`${memoryGraphNodes.fidelity} != 'gone'`,
421
424
  eq(memoryGraphNodes.scopeId, scopeId),
422
- )
425
+ ),
423
426
  )
424
427
  .groupBy(memoryGraphNodes.type)
425
428
  .all();
@@ -453,7 +456,7 @@ export async function generateConversationStartersJob(
453
456
  // Count active items for checkpoint
454
457
  const countRow = rawGet<{ c: number }>(
455
458
  `SELECT COUNT(*) AS c FROM memory_graph_nodes WHERE fidelity != 'gone' AND scope_id = ?`,
456
- scopeId
459
+ scopeId,
457
460
  );
458
461
  const totalActive = countRow?.c ?? 0;
459
462
 
@@ -474,6 +477,6 @@ export async function generateConversationStartersJob(
474
477
 
475
478
  log.info(
476
479
  { scopeId, batch: nextBatch, count: starters.length },
477
- "Generated conversation starters"
480
+ "Generated conversation starters",
478
481
  );
479
482
  }
@@ -161,7 +161,7 @@ async function summarizeWithLLM(
161
161
  return buildFallbackSummary(existingSummary, newContent, label);
162
162
  }
163
163
 
164
- const provider = await getConfiguredProvider();
164
+ const provider = await getConfiguredProvider("conversationSummarization");
165
165
  if (!provider) {
166
166
  log.debug(
167
167
  { label },
@@ -189,7 +189,7 @@ async function summarizeWithLLM(
189
189
  systemPrompt,
190
190
  {
191
191
  config: {
192
- modelIntent: summarizationConfig.modelIntent,
192
+ callSite: "conversationSummarization" as const,
193
193
  max_tokens: SUMMARY_MAX_TOKENS,
194
194
  },
195
195
  signal,
@@ -147,7 +147,13 @@ export function truncate(text: string, max: number): string {
147
147
 
148
148
  export async function embedAndUpsert(
149
149
  config: AssistantConfig,
150
- targetType: "segment" | "item" | "summary" | "media" | "graph_node",
150
+ targetType:
151
+ | "segment"
152
+ | "item"
153
+ | "summary"
154
+ | "media"
155
+ | "graph_node"
156
+ | "pkb_file",
151
157
  targetId: string,
152
158
  input: EmbeddingInput,
153
159
  extraPayload?: Record<string, unknown>,
@@ -0,0 +1,168 @@
1
+ import { beforeAll, beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ mock.module("../../util/logger.js", () => ({
4
+ getLogger: () =>
5
+ new Proxy({} as Record<string, unknown>, {
6
+ get: () => () => {},
7
+ }),
8
+ }));
9
+
10
+ // Track calls to indexPkbFile so we can assert the handler forwards payload
11
+ // fields correctly.
12
+ const indexPkbFileCalls: Array<{
13
+ pkbRoot: string;
14
+ absPath: string;
15
+ memoryScopeId: string;
16
+ }> = [];
17
+
18
+ mock.module("../pkb/pkb-index.js", () => ({
19
+ indexPkbFile: async (
20
+ pkbRoot: string,
21
+ absPath: string,
22
+ memoryScopeId: string,
23
+ ) => {
24
+ indexPkbFileCalls.push({ pkbRoot, absPath, memoryScopeId });
25
+ },
26
+ }));
27
+
28
+ mock.module("../../config/loader.js", () => ({
29
+ loadConfig: () => ({}),
30
+ getConfig: () => ({}),
31
+ invalidateConfigCache: () => {},
32
+ }));
33
+
34
+ import { DEFAULT_CONFIG } from "../../config/defaults.js";
35
+ import type { AssistantConfig } from "../../config/types.js";
36
+ import { getDb, initializeDb } from "../db.js";
37
+ import {
38
+ claimMemoryJobs,
39
+ type MemoryJob,
40
+ type MemoryJobType,
41
+ } from "../jobs-store.js";
42
+ import { memoryJobs } from "../schema.js";
43
+ import { embedPkbFileJob, enqueuePkbIndexJob } from "./embed-pkb-file.js";
44
+
45
+ const TEST_CONFIG: AssistantConfig = DEFAULT_CONFIG;
46
+
47
+ function makeJob(payload: Record<string, unknown>): MemoryJob {
48
+ return {
49
+ id: "job-1",
50
+ type: "embed_pkb_file",
51
+ payload,
52
+ status: "running",
53
+ attempts: 0,
54
+ deferrals: 0,
55
+ runAfter: 0,
56
+ lastError: null,
57
+ startedAt: Date.now(),
58
+ createdAt: Date.now(),
59
+ updatedAt: Date.now(),
60
+ };
61
+ }
62
+
63
+ describe("embedPkbFileJob", () => {
64
+ beforeAll(() => {
65
+ initializeDb();
66
+ });
67
+
68
+ beforeEach(() => {
69
+ indexPkbFileCalls.length = 0;
70
+ const db = getDb();
71
+ db.delete(memoryJobs).run();
72
+ });
73
+
74
+ test("calls indexPkbFile with payload fields", async () => {
75
+ await embedPkbFileJob(
76
+ makeJob({
77
+ pkbRoot: "/pkb/root",
78
+ absPath: "/pkb/root/note.md",
79
+ memoryScopeId: "scope-123",
80
+ }),
81
+ TEST_CONFIG,
82
+ );
83
+
84
+ expect(indexPkbFileCalls).toHaveLength(1);
85
+ expect(indexPkbFileCalls[0]).toEqual({
86
+ pkbRoot: "/pkb/root",
87
+ absPath: "/pkb/root/note.md",
88
+ memoryScopeId: "scope-123",
89
+ });
90
+ });
91
+
92
+ test("skips when pkbRoot is missing", async () => {
93
+ await embedPkbFileJob(
94
+ makeJob({ absPath: "/pkb/root/note.md", memoryScopeId: "scope-123" }),
95
+ TEST_CONFIG,
96
+ );
97
+ expect(indexPkbFileCalls).toHaveLength(0);
98
+ });
99
+
100
+ test("skips when absPath is missing", async () => {
101
+ await embedPkbFileJob(
102
+ makeJob({ pkbRoot: "/pkb/root", memoryScopeId: "scope-123" }),
103
+ TEST_CONFIG,
104
+ );
105
+ expect(indexPkbFileCalls).toHaveLength(0);
106
+ });
107
+
108
+ test("skips when memoryScopeId is missing", async () => {
109
+ await embedPkbFileJob(
110
+ makeJob({ pkbRoot: "/pkb/root", absPath: "/pkb/root/note.md" }),
111
+ TEST_CONFIG,
112
+ );
113
+ expect(indexPkbFileCalls).toHaveLength(0);
114
+ });
115
+ });
116
+
117
+ describe("enqueuePkbIndexJob", () => {
118
+ beforeAll(() => {
119
+ initializeDb();
120
+ });
121
+
122
+ beforeEach(() => {
123
+ indexPkbFileCalls.length = 0;
124
+ const db = getDb();
125
+ db.delete(memoryJobs).run();
126
+ });
127
+
128
+ test("enqueues a pending embed_pkb_file job with payload", () => {
129
+ const id = enqueuePkbIndexJob({
130
+ pkbRoot: "/pkb/root",
131
+ absPath: "/pkb/root/note.md",
132
+ memoryScopeId: "scope-abc",
133
+ });
134
+ expect(id).toBeTruthy();
135
+
136
+ const claimed = claimMemoryJobs(10);
137
+ expect(claimed).toHaveLength(1);
138
+ const [job] = claimed;
139
+ const expectedType: MemoryJobType = "embed_pkb_file";
140
+ expect(job.type).toBe(expectedType);
141
+ expect(job.payload).toEqual({
142
+ pkbRoot: "/pkb/root",
143
+ absPath: "/pkb/root/note.md",
144
+ memoryScopeId: "scope-abc",
145
+ });
146
+ });
147
+
148
+ test("round-trip: enqueued job dispatched to handler invokes indexPkbFile", async () => {
149
+ enqueuePkbIndexJob({
150
+ pkbRoot: "/pkb/root",
151
+ absPath: "/pkb/root/note.md",
152
+ memoryScopeId: "scope-rt",
153
+ });
154
+
155
+ const claimed = claimMemoryJobs(10);
156
+ expect(claimed).toHaveLength(1);
157
+ const [job] = claimed;
158
+ expect(job.type).toBe("embed_pkb_file");
159
+
160
+ await embedPkbFileJob(job, TEST_CONFIG);
161
+ expect(indexPkbFileCalls).toHaveLength(1);
162
+ expect(indexPkbFileCalls[0]).toEqual({
163
+ pkbRoot: "/pkb/root",
164
+ absPath: "/pkb/root/note.md",
165
+ memoryScopeId: "scope-rt",
166
+ });
167
+ });
168
+ });
@@ -0,0 +1,54 @@
1
+ import type { AssistantConfig } from "../../config/types.js";
2
+ import { asString } from "../job-utils.js";
3
+ import { enqueueMemoryJob, type MemoryJob } from "../jobs-store.js";
4
+ import { indexPkbFile } from "../pkb/pkb-index.js";
5
+
6
+ /**
7
+ * Input shape for the `embed_pkb_file` background job.
8
+ */
9
+ export interface EmbedPkbFileJobInput {
10
+ pkbRoot: string;
11
+ absPath: string;
12
+ memoryScopeId: string;
13
+ }
14
+
15
+ /**
16
+ * Job handler: read a PKB markdown file, chunk it, and upsert each chunk to
17
+ * Qdrant via the shared embedding pipeline. Thin wrapper around
18
+ * {@link indexPkbFile} so write hooks and startup reconciliation can
19
+ * fire-and-forget into the async job queue.
20
+ */
21
+ export async function embedPkbFileJob(
22
+ job: MemoryJob,
23
+ _config: AssistantConfig,
24
+ ): Promise<void> {
25
+ const pkbRoot = asString(job.payload.pkbRoot);
26
+ const absPath = asString(job.payload.absPath);
27
+ const memoryScopeId = asString(job.payload.memoryScopeId);
28
+ if (!pkbRoot || !absPath || !memoryScopeId) return;
29
+
30
+ try {
31
+ await indexPkbFile(pkbRoot, absPath, memoryScopeId);
32
+ } catch (error) {
33
+ if (
34
+ error !== null &&
35
+ typeof error === "object" &&
36
+ "code" in error &&
37
+ (error as { code?: unknown }).code === "ENOENT"
38
+ ) {
39
+ return;
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Enqueue an `embed_pkb_file` job (async, fire-and-forget).
47
+ */
48
+ export function enqueuePkbIndexJob(input: EmbedPkbFileJobInput): string {
49
+ return enqueueMemoryJob("embed_pkb_file", {
50
+ pkbRoot: input.pkbRoot,
51
+ absPath: input.absPath,
52
+ memoryScopeId: input.memoryScopeId,
53
+ });
54
+ }
@@ -1,4 +1,4 @@
1
- import { and, asc, eq, inArray, lte, notInArray, sql } from "drizzle-orm";
1
+ import { and, asc, eq, inArray, lte, notInArray, or, sql } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import { getLogger } from "../util/logger.js";
@@ -27,6 +27,7 @@ export type MemoryJobType =
27
27
  | "embed_attachment"
28
28
  | "generate_conversation_starters"
29
29
  | "embed_graph_node"
30
+ | "embed_pkb_file"
30
31
  | "graph_extract"
31
32
  | "graph_decay"
32
33
  | "graph_consolidate"
@@ -41,6 +42,7 @@ const EMBED_JOB_TYPES: MemoryJobType[] = [
41
42
  "embed_media",
42
43
  "embed_attachment",
43
44
  "embed_graph_node",
45
+ "embed_pkb_file",
44
46
  "graph_trigger_embed",
45
47
  ];
46
48
 
@@ -165,6 +167,10 @@ export function upsertAutoAnalysisJob(
165
167
  : never,
166
168
  ): void {
167
169
  const db = dbOverride ?? getDb();
170
+ // Match rows with the same triggerGroup OR legacy rows without triggerGroup
171
+ // (from older builds that used upsertDebouncedJob before triggerGroup was
172
+ // introduced). Without the IS NULL fallback, the next enqueue would insert
173
+ // a duplicate pending row for the same conversation.
168
174
  const existing = db
169
175
  .select()
170
176
  .from(memoryJobs)
@@ -173,18 +179,53 @@ export function upsertAutoAnalysisJob(
173
179
  eq(memoryJobs.type, "conversation_analyze"),
174
180
  eq(memoryJobs.status, "pending"),
175
181
  sql`json_extract(${memoryJobs.payload}, '$.conversationId') = ${payload.conversationId}`,
176
- sql`json_extract(${memoryJobs.payload}, '$.triggerGroup') = ${payload.triggerGroup}`,
182
+ or(
183
+ sql`json_extract(${memoryJobs.payload}, '$.triggerGroup') = ${payload.triggerGroup}`,
184
+ sql`json_extract(${memoryJobs.payload}, '$.triggerGroup') IS NULL`,
185
+ ),
177
186
  ),
178
187
  )
179
188
  .get();
180
189
  if (existing) {
190
+ // Merge triggerGroup into legacy rows so subsequent lookups use the new key.
191
+ const existingPayload = JSON.parse(existing.payload) as Record<
192
+ string,
193
+ unknown
194
+ >;
195
+ const needsPayloadUpdate = !existingPayload.triggerGroup;
181
196
  db.update(memoryJobs)
182
- .set({ runAfter, updatedAt: Date.now() })
197
+ .set({
198
+ runAfter,
199
+ updatedAt: Date.now(),
200
+ ...(needsPayloadUpdate
201
+ ? {
202
+ payload: JSON.stringify({ ...existingPayload, ...payload }),
203
+ }
204
+ : {}),
205
+ })
183
206
  .where(eq(memoryJobs.id, existing.id))
184
207
  .run();
185
208
  } else {
186
209
  enqueueMemoryJob("conversation_analyze", payload, runAfter, dbOverride);
187
210
  }
211
+
212
+ // When an immediate trigger fires (batch/compaction), cancel any pending
213
+ // debounced row for the same conversation — the immediate analysis covers
214
+ // those messages, making the debounced pass redundant. Without this, both
215
+ // rows fire independently and double the LLM cost per batch crossing.
216
+ if (payload.triggerGroup === "immediate") {
217
+ db.update(memoryJobs)
218
+ .set({ status: "completed", updatedAt: Date.now() })
219
+ .where(
220
+ and(
221
+ eq(memoryJobs.type, "conversation_analyze"),
222
+ eq(memoryJobs.status, "pending"),
223
+ sql`json_extract(${memoryJobs.payload}, '$.conversationId') = ${payload.conversationId}`,
224
+ sql`json_extract(${memoryJobs.payload}, '$.triggerGroup') = 'debounced'`,
225
+ ),
226
+ )
227
+ .run();
228
+ }
188
229
  }
189
230
 
190
231
  /**
@@ -44,6 +44,7 @@ import {
44
44
  RETRY_MAX_ATTEMPTS,
45
45
  retryDelayForAttempt,
46
46
  } from "./job-utils.js";
47
+ import { embedPkbFileJob } from "./jobs/embed-pkb-file.js";
47
48
  import {
48
49
  claimMemoryJobs,
49
50
  completeMemoryJob,
@@ -420,6 +421,9 @@ async function processJob(
420
421
  case "embed_graph_node":
421
422
  await embedGraphNodeJob(job, config);
422
423
  return;
424
+ case "embed_pkb_file":
425
+ await embedPkbFileJob(job, config);
426
+ return;
423
427
  case "graph_trigger_embed":
424
428
  await embedGraphTriggerJob(job, config);
425
429
  return;
@@ -196,7 +196,7 @@ export function migrateBackfillUsageCacheAccounting(database: DrizzleDb): void {
196
196
  const requestLogsByConversation = buildRequestLogMap(requestLogRows);
197
197
  const requestOffsets = new Map<string, number>();
198
198
  const previousUsageEventCreatedAt = new Map<string, number>();
199
- const pricingOverrides = getConfig().pricingOverrides;
199
+ const pricingOverrides = getConfig().llm.pricingOverrides;
200
200
 
201
201
  let scannedAnthropicRows = 0;
202
202
  let updatedRows = 0;
@@ -63,8 +63,8 @@ export function isAutoIncrementedUserFile(
63
63
  * Multiple contact rows may represent the same principal (one per channel:
64
64
  * desktop, phone, Slack, etc.). When a new row was created for a second
65
65
  * channel, `generateUserFileSlug(displayName)` auto-incremented to avoid a
66
- * filename collision (e.g. `sidd.md` → `sidd-2.md`), even though no
67
- * `sidd-2.md` file ever existed on disk. The persona resolver then silently
66
+ * filename collision (e.g. `alice.md` → `alice-2.md`), even though no
67
+ * `alice-2.md` file ever existed on disk. The persona resolver then silently
68
68
  * fell back to `users/default.md` for that channel's messages — and the same
69
69
  * slug is used for the journal directory, so the user lost per-principal
70
70
  * continuity on every non-primary channel.
@@ -0,0 +1,82 @@
1
+ import { isPlaceholderSentinelText } from "../../providers/anthropic/client.js";
2
+ import type { DrizzleDb } from "../db-connection.js";
3
+ import { getSqliteFrom } from "../db-connection.js";
4
+ import { withCrashRecovery } from "./validate-migration-state.js";
5
+
6
+ /**
7
+ * Strip Anthropic provider placeholder sentinel text blocks from persisted
8
+ * assistant messages.
9
+ *
10
+ * PLACEHOLDER_EMPTY_TURN and PLACEHOLDER_BLOCKS_OMITTED are injected into
11
+ * outbound Anthropic request bodies to preserve role alternation when an
12
+ * assistant turn would otherwise be empty. They are never supposed to be
13
+ * persisted, but a leak path caused them to be stored in the messages table
14
+ * where they render in chat bubbles as bold "PLACEHOLDER[...]" (markdown
15
+ * interprets the double-underscore surround as bold).
16
+ *
17
+ * This migration walks every assistant message, parses its content blocks,
18
+ * and drops text blocks whose text matches either sentinel (with or without
19
+ * the null-byte prefix, to cover rows that round-tripped through tools that
20
+ * stripped null bytes). If stripping leaves the message empty, stores [].
21
+ *
22
+ * Idempotent — safe to re-run.
23
+ */
24
+ export function migrateStripPlaceholderSentinelsFromMessages(
25
+ database: DrizzleDb,
26
+ ): void {
27
+ withCrashRecovery(
28
+ database,
29
+ "migration_strip_placeholder_sentinels_from_messages_v1",
30
+ () => {
31
+ const raw = getSqliteFrom(database);
32
+
33
+ const BATCH_SIZE = 100;
34
+ let lastRowid = 0;
35
+
36
+ for (;;) {
37
+ const rows = raw
38
+ .query(
39
+ `SELECT rowid, id, content FROM messages
40
+ WHERE role = 'assistant'
41
+ AND content LIKE '%__PLACEHOLDER__%'
42
+ AND rowid > ?
43
+ ORDER BY rowid
44
+ LIMIT ?`,
45
+ )
46
+ .all(lastRowid, BATCH_SIZE) as Array<{
47
+ rowid: number;
48
+ id: string;
49
+ content: string;
50
+ }>;
51
+
52
+ if (rows.length === 0) break;
53
+
54
+ for (const row of rows) {
55
+ lastRowid = row.rowid;
56
+
57
+ let blocks: Array<Record<string, unknown>>;
58
+ try {
59
+ const parsed = JSON.parse(row.content);
60
+ if (!Array.isArray(parsed)) continue;
61
+ blocks = parsed;
62
+ } catch {
63
+ continue;
64
+ }
65
+
66
+ const stripped = blocks.filter((b) => {
67
+ if (typeof b !== "object" || b === null) return false;
68
+ if (b.type !== "text") return true;
69
+ const text = typeof b.text === "string" ? b.text : "";
70
+ return !isPlaceholderSentinelText(text);
71
+ });
72
+
73
+ if (stripped.length === blocks.length) continue;
74
+
75
+ raw
76
+ .query(`UPDATE messages SET content = ? WHERE id = ?`)
77
+ .run(JSON.stringify(stripped), row.id);
78
+ }
79
+ }
80
+ },
81
+ );
82
+ }
@@ -166,6 +166,7 @@ export {
166
166
  migrateNormalizeUserFileByPrincipal,
167
167
  } from "./220-normalize-user-file-by-principal.js";
168
168
  export { migrateConversationsArchivedAt } from "./221-conversations-archived-at.js";
169
+ export { migrateStripPlaceholderSentinelsFromMessages } from "./222-strip-placeholder-sentinels-from-messages.js";
169
170
  export {
170
171
  MIGRATION_REGISTRY,
171
172
  type MigrationRegistryEntry,