@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
@@ -15,7 +15,11 @@ import {
15
15
  import type { ContentBlock, ImageContent } from "../../providers/types.js";
16
16
  import { getLogger } from "../../util/logger.js";
17
17
  import { embedWithRetry } from "../embed.js";
18
- import { selectedBackendSupportsMultimodal } from "../embedding-backend.js";
18
+ import {
19
+ generateSparseEmbedding,
20
+ selectedBackendSupportsMultimodal,
21
+ } from "../embedding-backend.js";
22
+ import type { QdrantSparseVector } from "../qdrant-client.js";
19
23
  import { searchGraphNodes } from "./graph-search.js";
20
24
  import type { InContextTracker } from "./injection.js";
21
25
  import {
@@ -28,7 +32,12 @@ import {
28
32
  weightsForContextLoad,
29
33
  } from "./scoring.js";
30
34
  import { sampleSerendipity } from "./serendipity.js";
31
- import { getEdgesForNode, getNodesByIds, queryNodes } from "./store.js";
35
+ import {
36
+ getEdgesForNode,
37
+ getNodesByIds,
38
+ queryCapabilityNodes,
39
+ queryNodes,
40
+ } from "./store.js";
32
41
  import { getActiveTriggersByType } from "./store.js";
33
42
  import {
34
43
  evaluateEventTriggers,
@@ -46,6 +55,13 @@ import { isCapabilityNode } from "./types.js";
46
55
 
47
56
  const log = getLogger("graph-retriever");
48
57
 
58
+ function extractCapabilityId(node: MemoryNode): string | null {
59
+ const match = node.content.match(
60
+ /^skill:(\S+)\n|^cli:(\S+)\n|^\s*The ".*?" skill \(([^)]+)\)|^\s*The "assistant (\S+)" CLI command/,
61
+ );
62
+ return match?.[1] ?? match?.[2] ?? match?.[3] ?? match?.[4] ?? null;
63
+ }
64
+
49
65
  // ---------------------------------------------------------------------------
50
66
  // LLM re-ranking + deduplication
51
67
  // ---------------------------------------------------------------------------
@@ -81,7 +97,7 @@ async function rerankAndDedup(
81
97
  if (candidates.length <= maxNodes) return candidates;
82
98
 
83
99
  try {
84
- const provider = await getConfiguredProvider();
100
+ const provider = await getConfiguredProvider("memoryRetrieval");
85
101
  if (!provider) return candidates.slice(0, maxNodes);
86
102
 
87
103
  // Numbered listing for the LLM: index + age + full content
@@ -111,7 +127,7 @@ Your job:
111
127
  3. Return the IDs in order of importance (most important first).`,
112
128
  {
113
129
  config: {
114
- modelIntent: "quality-optimized" as const,
130
+ callSite: "memoryRetrieval" as const,
115
131
  tool_choice: { type: "tool" as const, name: "select_memories" },
116
132
  thinking: { type: "disabled" },
117
133
  temperature: 0,
@@ -180,7 +196,7 @@ async function dedupForTurn(
180
196
  query: string,
181
197
  ): Promise<{ nodes: ScoredNode[]; llmApplied: boolean }> {
182
198
  try {
183
- const provider = await getConfiguredProvider();
199
+ const provider = await getConfiguredProvider("memoryRetrieval");
184
200
  if (!provider)
185
201
  return { nodes: candidates.slice(0, maxNodes), llmApplied: false };
186
202
 
@@ -202,7 +218,7 @@ async function dedupForTurn(
202
218
  `Dedupe + rerank the following numbered items. Pick the most relevant items to the query. Call the select_items tool.\n\nBe aggressive on dedup — when multiple items describe the same event, fact, or status, keep ONLY the richest version. But be generous on relevance — only cut items that are completely irrelevant to the query. If it's even tangentially related, keep it.`,
203
219
  {
204
220
  config: {
205
- modelIntent: "latency-optimized" as const,
221
+ callSite: "memoryRetrieval" as const,
206
222
  tool_choice: { type: "tool" as const, name: "select_items" },
207
223
  thinking: { type: "disabled" },
208
224
  temperature: 0,
@@ -273,7 +289,7 @@ async function dedupCrossCategory(
273
289
  maxNodes: number,
274
290
  ): Promise<ScoredNode[]> {
275
291
  try {
276
- const provider = await getConfiguredProvider();
292
+ const provider = await getConfiguredProvider("memoryRetrieval");
277
293
  if (!provider) return candidates.slice(0, maxNodes);
278
294
 
279
295
  const now = Date.now();
@@ -294,7 +310,7 @@ async function dedupCrossCategory(
294
310
  `Deduplicate the following numbered items. When multiple items describe the same event, fact, or status, keep ONLY the richest version. Keep ALL items that are not duplicates — do not filter by relevance or topic. Call the select_items tool with every item that survives dedup.`,
295
311
  {
296
312
  config: {
297
- modelIntent: "latency-optimized" as const,
313
+ callSite: "memoryRetrieval" as const,
298
314
  tool_choice: { type: "tool" as const, name: "select_items" },
299
315
  thinking: { type: "disabled" },
300
316
  temperature: 0,
@@ -347,6 +363,13 @@ export interface ContextLoadOpts {
347
363
  serendipitySlots?: number;
348
364
  /** Maximum nodes to return (default 40). */
349
365
  maxNodes?: number;
366
+ /**
367
+ * Optional dedicated user-message query text. When present and non-empty,
368
+ * `loadContextMemory` embeds this text independently of
369
+ * `recentSummaries` and uses the resulting vector to rank capability
370
+ * reserve slots. Leave `undefined` to use summary-only retrieval.
371
+ */
372
+ userQuery?: string;
350
373
  }
351
374
 
352
375
  export interface ContextLoadResult {
@@ -355,6 +378,37 @@ export interface ContextLoadResult {
355
378
  triggeredNodes: TriggeredResult[];
356
379
  latencyMs: number;
357
380
  metrics: RetrievalMetrics;
381
+ /**
382
+ * Dense query vector computed from `recentSummaries`. Surfaced so downstream
383
+ * callers (e.g. the PKB hint retriever) can reuse the same embedding for a
384
+ * second Qdrant query without paying for another embedding call. `undefined`
385
+ * when no summaries were provided or embedding failed (circuit breaker).
386
+ */
387
+ queryVector?: number[];
388
+ /**
389
+ * Optional sparse vector passed into `searchGraphNodes` alongside the dense
390
+ * query vector. Currently always `undefined` — reserved for future hybrid
391
+ * retrieval that produces a sparse vector at the call site.
392
+ */
393
+ sparseVector?: QdrantSparseVector;
394
+ /**
395
+ * Dense query vector computed from `opts.userQuery`. Surfaced so
396
+ * downstream callers (PKB hint search) can prefer it over the
397
+ * summary-based `queryVector` for user-intent-aligned retrieval.
398
+ * `undefined` when `userQuery` was not provided, was effectively empty,
399
+ * or the dedicated embed call was skipped/failed.
400
+ */
401
+ userQueryVector?: number[];
402
+ /**
403
+ * Sparse (TF-IDF) vector of `opts.userQuery`. Surfaced so PKB hint search
404
+ * can pair it with `userQueryVector` to run a hybrid dense+sparse query —
405
+ * RRF fusion captures lexical matches (exact filenames, proper nouns,
406
+ * uncommon tokens) that pure dense embeddings wash out. Computed locally
407
+ * (no embedding-service call), so it's cheap to produce whenever the user
408
+ * query is non-empty. `undefined` on the same conditions as
409
+ * `userQueryVector`.
410
+ */
411
+ userQuerySparseVector?: QdrantSparseVector;
358
412
  }
359
413
 
360
414
  /**
@@ -380,6 +434,7 @@ export async function loadContextMemory(
380
434
 
381
435
  // 1. Embed recent conversation summaries as retrieval queries
382
436
  let queryVector: number[] | null = null;
437
+ const sparseVector: QdrantSparseVector | undefined = undefined;
383
438
  let embeddingProvider: string | null = null;
384
439
  let embeddingModel: string | null = null;
385
440
  let contextQueryText: string | null = null;
@@ -400,15 +455,51 @@ export async function loadContextMemory(
400
455
  }
401
456
  }
402
457
 
458
+ // 1b. Dedicated user-query embedding. Always embed the user query
459
+ // independently when present. Summaries and the user query are
460
+ // disjoint signals, so both vectors carry unique retrieval value —
461
+ // especially in workloads with short summaries and a substantive
462
+ // user question.
463
+ let userQueryVector: number[] | null = null;
464
+ let userQuerySparseVector: QdrantSparseVector | undefined = undefined;
465
+ const userQueryCandidateIds = new Map<string, number>(); // nodeId → score
466
+ const trimmedUserQuery = opts.userQuery?.trim() ?? "";
467
+ const shouldEmbedUserQuery = trimmedUserQuery.length > 0;
468
+ if (shouldEmbedUserQuery) {
469
+ try {
470
+ const result = await embedWithRetry(opts.config, [trimmedUserQuery], {
471
+ signal: opts.signal,
472
+ });
473
+ userQueryVector = result.vectors[0] ?? null;
474
+ if (!embeddingProvider) {
475
+ embeddingProvider = result.provider;
476
+ embeddingModel = result.model;
477
+ }
478
+ } catch (err) {
479
+ log.warn({ err }, "Failed to embed userQuery for context load");
480
+ }
481
+ // Sparse embedding is a local TF-IDF computation — no network call, so
482
+ // compute it independently of the dense embed. Even if the dense call
483
+ // failed, a sparse vector is still useful for downstream consumers that
484
+ // can operate on it alone.
485
+ const sparse = generateSparseEmbedding(trimmedUserQuery);
486
+ if (sparse.indices.length > 0) {
487
+ userQuerySparseVector = sparse;
488
+ }
489
+ }
490
+
403
491
  // 2. Hybrid retrieval from Qdrant (dense search on graph_node points)
404
492
  const semanticCandidateIds = new Map<string, number>(); // nodeId → score
405
493
  let hybridSearchLatencyMs = 0;
406
494
  if (queryVector) {
407
495
  const searchStart = Date.now();
408
496
  try {
409
- const results = await searchGraphNodes(queryVector, maxNodes * 3, [
410
- opts.scopeId,
411
- ]);
497
+ const results = await searchGraphNodes(
498
+ queryVector,
499
+ maxNodes * 3,
500
+ [opts.scopeId],
501
+ sparseVector,
502
+ );
412
503
  for (const r of results) {
413
504
  semanticCandidateIds.set(r.nodeId, r.score);
414
505
  }
@@ -420,6 +511,30 @@ export async function loadContextMemory(
420
511
  }
421
512
  const pureSemanticHits = semanticCandidateIds.size;
422
513
 
514
+ // 2b. Run a parallel Qdrant search against the user-query vector and merge
515
+ // the results into the organic scoring pool via max-score union: a node
516
+ // hit by only the user-query vector still participates in downstream
517
+ // scoring, and a node hit by both vectors retains the higher score.
518
+ if (userQueryVector) {
519
+ try {
520
+ const results = await searchGraphNodes(
521
+ userQueryVector,
522
+ maxNodes * 3,
523
+ [opts.scopeId],
524
+ undefined,
525
+ );
526
+ for (const r of results) {
527
+ userQueryCandidateIds.set(r.nodeId, r.score);
528
+ const existing = semanticCandidateIds.get(r.nodeId);
529
+ if (existing === undefined || r.score > existing) {
530
+ semanticCandidateIds.set(r.nodeId, r.score);
531
+ }
532
+ }
533
+ } catch (err) {
534
+ log.warn({ err }, "Qdrant search failed for userQuery vector");
535
+ }
536
+ }
537
+
423
538
  // Also include top-significance nodes as a fallback
424
539
  const topSignificance = queryNodes({
425
540
  scopeId: opts.scopeId,
@@ -428,7 +543,7 @@ export async function loadContextMemory(
428
543
  });
429
544
  for (const node of topSignificance) {
430
545
  if (!semanticCandidateIds.has(node.id)) {
431
- semanticCandidateIds.set(node.id, 0); // no semantic score, ranked by significance
546
+ semanticCandidateIds.set(node.id, 0); // no score from either Qdrant query, ranked by significance only
432
547
  }
433
548
  }
434
549
 
@@ -550,47 +665,69 @@ export async function loadContextMemory(
550
665
  // Sort by score descending
551
666
  scored.sort((a, b) => b.score - a.score);
552
667
 
553
- // 5b. Reserve slots for skill/CLI capabilities. Queried directly from
554
- // SQLite — no Qdrant vectors needed — so capabilities surface even on
555
- // fresh assistants whose embedding jobs haven't completed yet.
668
+ // 5b. Reserve slots for skill/CLI capabilities.
669
+ //
670
+ // Source candidates from the hydrated semantic-search set (the same
671
+ // strategy `retrieveForTurn` uses) so ranking reflects query relevance.
672
+ // For cold-start cases (capability nodes exist in SQLite but their
673
+ // embeddings haven't landed in Qdrant yet), fall back to a narrow
674
+ // SQL pull that matches only capability-shaped content so organic
675
+ // procedurals can't crowd the pool.
556
676
  const capabilityReserve = ctxLoadCfg.capabilityReserve;
557
- const rawCapabilityNodes =
558
- capabilityReserve > 0
559
- ? queryNodes({
560
- scopeId: opts.scopeId,
561
- types: ["procedural"],
562
- fidelityNot: ["gone"],
563
- limit: capabilityReserve * 4,
564
- })
565
- : [];
677
+ const capabilityEntries: { node: MemoryNode; sim: number }[] = [];
678
+ if (capabilityReserve > 0) {
679
+ const uniqueCapabilityIds = new Set<string>();
680
+ let untaggedCount = 0;
681
+ for (const [nodeId, node] of nodeMap) {
682
+ if (node.fidelity === "gone") continue;
683
+ if (!isCapabilityNode(node)) continue;
684
+ const sim =
685
+ userQueryCandidateIds.get(nodeId) ??
686
+ semanticCandidateIds.get(nodeId) ??
687
+ 0;
688
+ capabilityEntries.push({ node, sim });
689
+ const capId = extractCapabilityId(node);
690
+ if (capId) uniqueCapabilityIds.add(capId);
691
+ else untaggedCount++;
692
+ }
693
+
694
+ // Gate the fallback on distinct capability IDs (plus any entries
695
+ // whose content didn't match a known ID pattern), not raw entry
696
+ // count — duplicate capability-ID seeding formats can otherwise push
697
+ // `capabilityEntries.length` past the threshold and then collapse
698
+ // below it during the dedup pass below.
699
+ const distinctCount = uniqueCapabilityIds.size + untaggedCount;
700
+ if (distinctCount < capabilityReserve) {
701
+ const alreadySeen = new Set(capabilityEntries.map((e) => e.node.id));
702
+ const fallback = queryCapabilityNodes(
703
+ opts.scopeId,
704
+ capabilityReserve * 4,
705
+ );
706
+ for (const node of fallback) {
707
+ if (alreadySeen.has(node.id)) continue;
708
+ const sim =
709
+ userQueryCandidateIds.get(node.id) ??
710
+ semanticCandidateIds.get(node.id) ??
711
+ 0;
712
+ capabilityEntries.push({ node, sim });
713
+ }
714
+ }
715
+ }
716
+
717
+ capabilityEntries.sort((a, b) => b.sim - a.sim);
566
718
 
567
719
  // Dedup: both seeding systems may create nodes for the same capability.
568
720
  // Extract capability ID from content and keep only the first node per ID.
569
721
  const seenCapabilityIds = new Set<string>();
570
- const capabilityNodes = rawCapabilityNodes
571
- .filter(isCapabilityNode)
572
- .filter((node) => {
573
- const match = node.content.match(
574
- /^skill:(\S+)\n|^cli:(\S+)\n|^\s*The ".*?" skill \(([^)]+)\)|^\s*The "assistant (\S+)" CLI command/,
575
- );
576
- const capId = match?.[1] ?? match?.[2] ?? match?.[3] ?? match?.[4];
577
- if (capId) {
578
- if (seenCapabilityIds.has(capId)) return false;
579
- seenCapabilityIds.add(capId);
580
- }
581
- return true;
582
- });
583
-
584
- // Rank by semantic similarity when a query vector exists
585
- let selectedCapabilities: MemoryNode[];
586
- if (queryVector && capabilityNodes.length > capabilityReserve) {
587
- selectedCapabilities = capabilityNodes
588
- .map((node) => ({ node, sim: semanticCandidateIds.get(node.id) ?? 0 }))
589
- .sort((a, b) => b.sim - a.sim)
590
- .slice(0, capabilityReserve)
591
- .map((e) => e.node);
592
- } else {
593
- selectedCapabilities = capabilityNodes.slice(0, capabilityReserve);
722
+ const selectedCapabilities: MemoryNode[] = [];
723
+ for (const { node } of capabilityEntries) {
724
+ if (selectedCapabilities.length >= capabilityReserve) break;
725
+ const capId = extractCapabilityId(node);
726
+ if (capId) {
727
+ if (seenCapabilityIds.has(capId)) continue;
728
+ seenCapabilityIds.add(capId);
729
+ }
730
+ selectedCapabilities.push(node);
594
731
  }
595
732
 
596
733
  const reservedCapabilities: ScoredNode[] = selectedCapabilities.map(
@@ -697,6 +834,10 @@ export async function loadContextMemory(
697
834
  queryContext: contextQueryText,
698
835
  topCandidates,
699
836
  },
837
+ queryVector: queryVector ?? undefined,
838
+ sparseVector,
839
+ userQueryVector: userQueryVector ?? undefined,
840
+ userQuerySparseVector,
700
841
  };
701
842
  }
702
843
 
@@ -726,6 +867,21 @@ export interface TurnRetrievalResult {
726
867
  triggeredNodes: TriggeredResult[];
727
868
  latencyMs: number;
728
869
  metrics: RetrievalMetrics;
870
+ /**
871
+ * Dense query vector computed from the last-exchange text (assistant +
872
+ * user message). Surfaced so downstream callers (e.g. the PKB hint
873
+ * retriever in `applyRuntimeInjections`) can reuse the same embedding
874
+ * for a second Qdrant query without paying for another embedding call.
875
+ * `undefined` when no text was embedded (image-only turn) or embedding
876
+ * failed (circuit breaker).
877
+ */
878
+ queryVector?: number[];
879
+ /**
880
+ * Optional sparse vector passed alongside `queryVector`. Currently always
881
+ * `undefined` — reserved for future hybrid retrieval that produces a
882
+ * sparse vector at the call site.
883
+ */
884
+ sparseVector?: QdrantSparseVector;
729
885
  }
730
886
 
731
887
  /**
@@ -766,6 +922,24 @@ export async function retrieveForTurn(
766
922
  .filter((m) => m.length > 0)
767
923
  .join("\n\n");
768
924
 
925
+ // Sparse (TF-IDF) vector of the user's last message only. Surfaced so PKB
926
+ // hint search can pair it with the per-turn dense vector, pulling in
927
+ // lexical matches (exact filenames, proper nouns, uncommon tokens) that
928
+ // pure dense embeddings wash out. Computed locally with no network call.
929
+ // The dense `queryVector` for per-turn is the combined assistant+user
930
+ // embedding (it drives graph search), so this pairing is slightly
931
+ // asymmetric — the sparse signal is user-only while the dense is mixed.
932
+ // That's acceptable for PKB's purpose: lexical matches are overwhelmingly
933
+ // driven by the user's own wording.
934
+ const trimmedUserLast = opts.userLastMessage.trim();
935
+ let perTurnSparseVector: QdrantSparseVector | undefined = undefined;
936
+ if (trimmedUserLast.length > 0) {
937
+ const sparse = generateSparseEmbedding(trimmedUserLast);
938
+ if (sparse.indices.length > 0) {
939
+ perTurnSparseVector = sparse;
940
+ }
941
+ }
942
+
769
943
  // Image-to-image search: embed incoming user images as queries
770
944
  // Runs before the text-empty early return so image-only turns are handled
771
945
  const imageBlocks = (opts.userLastMessageBlocks ?? []).filter(
@@ -828,6 +1002,8 @@ export async function retrieveForTurn(
828
1002
  embeddingModel,
829
1003
  queryContext: queryText || null,
830
1004
  },
1005
+ queryVector: undefined,
1006
+ sparseVector: perTurnSparseVector,
831
1007
  };
832
1008
  }
833
1009
 
@@ -900,6 +1076,8 @@ export async function retrieveForTurn(
900
1076
  embeddingModel,
901
1077
  queryContext: queryText || null,
902
1078
  },
1079
+ queryVector: undefined,
1080
+ sparseVector: perTurnSparseVector,
903
1081
  };
904
1082
  }
905
1083
  }
@@ -952,6 +1130,8 @@ export async function retrieveForTurn(
952
1130
  embeddingModel,
953
1131
  queryContext: queryText || null,
954
1132
  },
1133
+ queryVector: queryEmbeddings[0],
1134
+ sparseVector: perTurnSparseVector,
955
1135
  };
956
1136
  }
957
1137
 
@@ -1134,5 +1314,7 @@ export async function retrieveForTurn(
1134
1314
  queryContext: queryText || null,
1135
1315
  topCandidates,
1136
1316
  },
1317
+ queryVector: queryEmbeddings[0],
1318
+ sparseVector: perTurnSparseVector,
1137
1319
  };
1138
1320
  }
@@ -358,6 +358,47 @@ export function queryNodes(filters: NodeQueryFilters): MemoryNode[] {
358
358
  return query.all().map(rowToNode);
359
359
  }
360
360
 
361
+ /**
362
+ * Pull capability (skill / CLI) nodes directly from SQLite, ordered by
363
+ * significance DESC. Matches the content shapes produced by both the
364
+ * legacy (`skill:{id}\n`, `cli:{name}\n`) and current
365
+ * (`The "..." skill (id) is available.`, `The "assistant ..." CLI command`)
366
+ * seeding systems — keeping the SQL filter in sync with `isCapabilityNode`.
367
+ *
368
+ * Used as a cold-start fallback for context-load capability injection when
369
+ * no semantic-search candidates are capability nodes (e.g. fresh assistants
370
+ * whose embedding jobs haven't completed yet). The content-pattern filter
371
+ * prevents organic procedural memories from crowding out real capabilities.
372
+ */
373
+ export function queryCapabilityNodes(
374
+ scopeId: string,
375
+ limit: number,
376
+ ): MemoryNode[] {
377
+ const db = getDb();
378
+ const rows = db
379
+ .select()
380
+ .from(memoryGraphNodes)
381
+ .where(
382
+ and(
383
+ eq(memoryGraphNodes.scopeId, scopeId),
384
+ eq(memoryGraphNodes.type, "procedural"),
385
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
386
+ or(
387
+ sql`${memoryGraphNodes.content} LIKE 'skill:%'`,
388
+ sql`${memoryGraphNodes.content} LIKE 'cli:%'`,
389
+ and(
390
+ sql`${memoryGraphNodes.content} LIKE 'The "%'`,
391
+ sql`${memoryGraphNodes.content} LIKE '% is available.%'`,
392
+ ),
393
+ ),
394
+ ),
395
+ )
396
+ .orderBy(sql`${memoryGraphNodes.significance} DESC`)
397
+ .limit(limit)
398
+ .all();
399
+ return rows.map(rowToNode);
400
+ }
401
+
361
402
  /** Count all non-gone nodes in a scope. */
362
403
  export function countNodes(scopeId: string): number {
363
404
  const db = getDb();
@@ -14,6 +14,8 @@ import { getWorkspaceDir } from "../../util/platform.js";
14
14
  import { buildExcerpt, buildFtsMatchQuery } from "../conversation-queries.js";
15
15
  import { embedWithRetry } from "../embed.js";
16
16
  import { generateSparseEmbedding } from "../embedding-backend.js";
17
+ import { enqueuePkbIndexJob } from "../jobs/embed-pkb-file.js";
18
+ import { PKB_WORKSPACE_SCOPE } from "../pkb/types.js";
17
19
  import { searchGraphNodes } from "./graph-search.js";
18
20
  import { getNodesByIds } from "./store.js";
19
21
 
@@ -249,6 +251,7 @@ async function handleArchiveRecall(
249
251
 
250
252
  export interface RememberInput {
251
253
  content: string;
254
+ finish_turn?: boolean;
252
255
  }
253
256
 
254
257
  export interface RememberResult {
@@ -286,6 +289,7 @@ export function handleRemember(
286
289
  // Append to buffer.md
287
290
  const bufferPath = join(pkbDir, "buffer.md");
288
291
  appendFileSync(bufferPath, entry, "utf-8");
292
+ enqueuePkbReindex(pkbDir, bufferPath);
289
293
 
290
294
  // Append to daily archive
291
295
  const yyyy = now.getFullYear();
@@ -296,6 +300,29 @@ export function handleRemember(
296
300
  appendFileSync(archivePath, `# ${month} ${day}, ${yyyy}\n\n`, "utf-8");
297
301
  }
298
302
  appendFileSync(archivePath, entry, "utf-8");
303
+ enqueuePkbReindex(pkbDir, archivePath);
299
304
 
300
305
  return { success: true, message: "Saved to knowledge base." };
301
306
  }
307
+
308
+ /**
309
+ * Fire-and-forget enqueue of a PKB re-index job for a file we just wrote.
310
+ *
311
+ * Always indexes under {@link PKB_WORKSPACE_SCOPE}. See the comment on that
312
+ * constant for why PKB points are not per-conversation-scoped.
313
+ *
314
+ * Wrapped in try/catch so an enqueue failure (e.g. DB hiccup) cannot break
315
+ * the remember call — the write has already succeeded and the user's fact
316
+ * is safe on disk.
317
+ */
318
+ function enqueuePkbReindex(pkbRoot: string, absPath: string): void {
319
+ try {
320
+ enqueuePkbIndexJob({
321
+ pkbRoot,
322
+ absPath,
323
+ memoryScopeId: PKB_WORKSPACE_SCOPE,
324
+ });
325
+ } catch (err) {
326
+ log.warn({ err, absPath }, "Failed to enqueue PKB re-index job");
327
+ }
328
+ }
@@ -82,7 +82,7 @@ export const graphRecallDefinition: ToolDefinition = {
82
82
  export const graphRememberDefinition: ToolDefinition = {
83
83
  name: "remember",
84
84
  description:
85
- "Save a fact to your knowledge base. Call this AGGRESSIVELY — capture anything concrete about their life: preferences, locations, names, dates, habits, opinions, health details, plans, relationship facts, routines, commitments. Default to remembering; only skip obvious noise (small talk, hypotheticals, things they're just musing about). Don't judge importance — filing decides that later. Examples: 'Prefers UberEats over DoorDash', 'Lives in NYC, from Texas', 'Takes 45mg nicotine daily, tapering', 'Girlfriend Yen is in Texas', 'Watches vampire show Saturday nights', 'NYU Summit April 10-11'. Call this multiple times per conversation — it's cheap (one line appended to a file). Don't wait until the end. Don't batch. Every new fact, immediately. Remembering too much is infinitely better than forgetting something that mattered. CORRECTIONS are the highest priority — when the user corrects a fact you had wrong, `remember` the correction immediately. The wrong version is already propagated in your prior turns and memory graph; skipping a correction means future-you keeps operating on the old value. Never skip a correction even if you'd skip the equivalent fresh fact.",
85
+ "Save a fact to your knowledge base. Call this AGGRESSIVELY — capture anything concrete about their life: preferences, locations, names, dates, habits, opinions, health details, plans, relationship facts, routines, commitments. Default to remembering; only skip obvious noise (small talk, hypotheticals, things they're just musing about). Don't judge importance — filing decides that later. Examples: 'Prefers UberEats over DoorDash', 'Lives in NYC, from Texas', 'Takes daily medication, tapering dose', 'Partner Alex lives in Austin', 'Watches a weekly show on Saturday nights', 'Conference in May'. Call this multiple times per conversation — it's cheap (one line appended to a file). Don't wait until the end. Don't batch. Every new fact, immediately. Remembering too much is infinitely better than forgetting something that mattered. CORRECTIONS are the highest priority — when the user corrects a fact you had wrong, `remember` the correction immediately. The wrong version is already propagated in your prior turns and memory graph; skipping a correction means future-you keeps operating on the old value. Never skip a correction even if you'd skip the equivalent fresh fact.",
86
86
  input_schema: {
87
87
  type: "object",
88
88
  properties: {
@@ -91,6 +91,11 @@ export const graphRememberDefinition: ToolDefinition = {
91
91
  description:
92
92
  "The fact to remember. Write naturally — a preference, a detail, a commitment, a plan. No need to categorize.",
93
93
  },
94
+ finish_turn: {
95
+ type: "boolean",
96
+ description:
97
+ "Set to true ONLY on the final `remember` call when you have nothing else to say and want to hand control back to the user. When true, the assistant turn ends after this tool call and no further LLM call is made. Do NOT set true on intermediate `remember` calls. Default: false.",
98
+ },
94
99
  },
95
100
  required: ["content"],
96
101
  },
@@ -203,11 +203,11 @@ export async function indexMessageNow(
203
203
  );
204
204
 
205
205
  // ── Auto-analysis triggers ─────────────────────────────────────
206
- // Both triggers route through `upsertDebouncedJob` in the helper,
207
- // so a single pending row is shared. Order matters: the idle
208
- // upsert runs first (pushing `runAfter` into the future); the
209
- // batch trigger runs last so a threshold crossing pulls
210
- // `runAfter` back to "now" and overrides the idle debounce.
206
+ // Immediate triggers (batch, compaction) and debounced triggers
207
+ // (idle, lifecycle) write to separate rows keyed by triggerGroup
208
+ // via `upsertAutoAnalysisJob`. When an immediate trigger fires,
209
+ // it cancels any pending debounced row for the same conversation
210
+ // to avoid redundant analysis runs.
211
211
  enqueueAutoAnalysisIfEnabled({
212
212
  conversationId: input.conversationId,
213
213
  trigger: "idle",