@vellumai/assistant 0.6.4 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -0,0 +1,169 @@
1
+ import path from "node:path";
2
+ import { describe, expect, test } from "bun:test";
3
+
4
+ import type { ContentBlock, Message } from "../providers/types.js";
5
+ import type { Conversation } from "./conversation.js";
6
+ import { getInContextPkbPaths } from "./pkb-context-tracker.js";
7
+
8
+ const WORKING_DIR = path.resolve("/tmp/test-pkb-root");
9
+ const PKB_ROOT = path.join(WORKING_DIR, "pkb");
10
+
11
+ // The helper only reads `conversation.messages`. Constructing a real
12
+ // `Conversation` instance would require a full daemon setup; casting a
13
+ // minimal object through `unknown` keeps the test isolated and pure while
14
+ // still exercising the public type.
15
+ function makeConversation(messages: Message[]): Conversation {
16
+ return { messages } as unknown as Conversation;
17
+ }
18
+
19
+ function fileReadToolUse(filePath: string): ContentBlock {
20
+ return {
21
+ type: "tool_use",
22
+ id: `toolu_${Math.random().toString(36).slice(2, 10)}`,
23
+ name: "file_read",
24
+ input: { path: filePath },
25
+ };
26
+ }
27
+
28
+ function assistantMessageWithBlocks(blocks: ContentBlock[]): Message {
29
+ return { role: "assistant", content: blocks };
30
+ }
31
+
32
+ describe("getInContextPkbPaths", () => {
33
+ test("auto-inject paths are always present (even with empty conversation)", () => {
34
+ const conversation = makeConversation([]);
35
+ const result = getInContextPkbPaths(
36
+ conversation,
37
+ ["notes/index.md", "journal/2026-04-18.md"],
38
+ PKB_ROOT,
39
+ WORKING_DIR,
40
+ );
41
+ expect(result).toEqual(
42
+ new Set([
43
+ path.join(PKB_ROOT, "notes/index.md"),
44
+ path.join(PKB_ROOT, "journal/2026-04-18.md"),
45
+ ]),
46
+ );
47
+ });
48
+
49
+ test("includes a file_read tool_use with a path inside pkbRoot", () => {
50
+ const insidePath = path.join(PKB_ROOT, "notes/thoughts.md");
51
+ const conversation = makeConversation([
52
+ assistantMessageWithBlocks([fileReadToolUse(insidePath)]),
53
+ ]);
54
+ const result = getInContextPkbPaths(conversation, [], PKB_ROOT, WORKING_DIR);
55
+ expect(result).toEqual(new Set([insidePath]));
56
+ });
57
+
58
+ test("excludes a file_read tool_use whose path is outside pkbRoot", () => {
59
+ const conversation = makeConversation([
60
+ assistantMessageWithBlocks([fileReadToolUse("/etc/hosts")]),
61
+ ]);
62
+ const result = getInContextPkbPaths(conversation, [], PKB_ROOT, WORKING_DIR);
63
+ expect(result).toEqual(new Set());
64
+ });
65
+
66
+ test("excludes a non-file_read tool_use with a PKB-like path", () => {
67
+ const insidePath = path.join(PKB_ROOT, "notes/thoughts.md");
68
+ const bogus: ContentBlock = {
69
+ type: "tool_use",
70
+ id: "toolu_bogus",
71
+ name: "file_write",
72
+ input: { path: insidePath },
73
+ };
74
+ const conversation = makeConversation([
75
+ assistantMessageWithBlocks([bogus]),
76
+ ]);
77
+ const result = getInContextPkbPaths(conversation, [], PKB_ROOT, WORKING_DIR);
78
+ expect(result).toEqual(new Set());
79
+ });
80
+
81
+ test("post-compaction context-summary user message returns only auto-inject paths", () => {
82
+ // After compaction, the structured tool_use blocks have been serialized
83
+ // away and the conversation is just a user-role text message containing
84
+ // the summary.
85
+ const summaryMessage: Message = {
86
+ role: "user",
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: "[Context summary] Previously you read notes/thoughts.md and journal/2026-04-18.md...",
91
+ },
92
+ ],
93
+ };
94
+ const conversation = makeConversation([summaryMessage]);
95
+ const autoInject = ["profile/identity.md"];
96
+ const result = getInContextPkbPaths(
97
+ conversation,
98
+ autoInject,
99
+ PKB_ROOT,
100
+ WORKING_DIR,
101
+ );
102
+ expect(result).toEqual(
103
+ new Set([path.join(PKB_ROOT, "profile/identity.md")]),
104
+ );
105
+ });
106
+
107
+ test("path-traversal attempt via ../../etc/passwd is excluded", () => {
108
+ const conversation = makeConversation([
109
+ assistantMessageWithBlocks([
110
+ fileReadToolUse("../../etc/passwd"),
111
+ fileReadToolUse("notes/../../../etc/shadow"),
112
+ ]),
113
+ ]);
114
+ const result = getInContextPkbPaths(conversation, [], PKB_ROOT, WORKING_DIR);
115
+ expect(result).toEqual(new Set());
116
+ });
117
+
118
+ test("relative file_read path outside pkbRoot is excluded", () => {
119
+ // These are resolved against `workingDir` (matching `file_read`'s own
120
+ // rule), land outside `pkbRoot`, and are correctly ignored.
121
+ const conversation = makeConversation([
122
+ assistantMessageWithBlocks([
123
+ fileReadToolUse("notes.md"),
124
+ fileReadToolUse("./deep/subdir/file.md"),
125
+ ]),
126
+ ]);
127
+ const result = getInContextPkbPaths(conversation, [], PKB_ROOT, WORKING_DIR);
128
+ expect(result).toEqual(new Set());
129
+ });
130
+
131
+ test("workspace-relative file_read path inside pkb/ is recognized", () => {
132
+ // The model emits workspace-relative paths like `pkb/threads.md`.
133
+ // The tracker resolves them against `workingDir` (matching `file_read`'s
134
+ // own rule) and verifies the result falls inside `pkbRoot`.
135
+ const conversation = makeConversation([
136
+ assistantMessageWithBlocks([fileReadToolUse("pkb/threads.md")]),
137
+ ]);
138
+ const result = getInContextPkbPaths(conversation, [], PKB_ROOT, WORKING_DIR);
139
+ expect(result).toEqual(new Set([path.join(PKB_ROOT, "threads.md")]));
140
+ });
141
+
142
+ test("resolves relative auto-inject paths against pkbRoot", () => {
143
+ const conversation = makeConversation([]);
144
+ const result = getInContextPkbPaths(
145
+ conversation,
146
+ ["./notes/relative.md"],
147
+ PKB_ROOT,
148
+ WORKING_DIR,
149
+ );
150
+ expect(result).toEqual(
151
+ new Set([path.join(PKB_ROOT, "notes/relative.md")]),
152
+ );
153
+ });
154
+
155
+ test("auto-inject and file_read paths union (no duplicates)", () => {
156
+ const insidePath = path.join(PKB_ROOT, "notes/shared.md");
157
+ const conversation = makeConversation([
158
+ assistantMessageWithBlocks([fileReadToolUse(insidePath)]),
159
+ ]);
160
+ const result = getInContextPkbPaths(
161
+ conversation,
162
+ ["notes/shared.md"],
163
+ PKB_ROOT,
164
+ WORKING_DIR,
165
+ );
166
+ expect(result.size).toBe(1);
167
+ expect(result.has(insidePath)).toBe(true);
168
+ });
169
+ });
@@ -0,0 +1,125 @@
1
+ /**
2
+ * pkb-context-tracker
3
+ *
4
+ * Pure helper that reports which PKB file paths are already "in context" for
5
+ * a given conversation. A path is considered in context if either:
6
+ *
7
+ * 1. It was explicitly auto-injected (caller supplies `autoInjectPaths`),
8
+ * typically via a system-reminder that embeds the file contents.
9
+ * 2. The conversation history contains a structured `file_read` tool_use
10
+ * block whose `input.path` — resolved the same way `file_read` itself
11
+ * resolves it (absolute as-is, relative against `workingDir`) — lands
12
+ * inside `pkbRoot`.
13
+ *
14
+ * Used by the PKB system reminder so we don't suggest files the model has
15
+ * already loaded.
16
+ *
17
+ * Post-compaction note: structured `tool_use` blocks get serialized into a
18
+ * plain-text summary and dropped from the live message array. After a
19
+ * compaction, this helper will naturally only see the `autoInjectPaths` —
20
+ * which is the desired semantics.
21
+ *
22
+ * No I/O, no globals, no side effects.
23
+ */
24
+
25
+ import path from "node:path";
26
+
27
+ import type { ContentBlock, Message } from "../providers/types.js";
28
+
29
+ /**
30
+ * Minimal shape this helper needs from a `Conversation`. Defining it as an
31
+ * interface (rather than importing the full `Conversation` class) keeps the
32
+ * helper pure and trivial to unit-test without constructing a real daemon
33
+ * conversation.
34
+ */
35
+ export interface PkbContextConversation {
36
+ messages: Message[];
37
+ }
38
+
39
+ /**
40
+ * The structured tool_use block name the assistant emits when reading files
41
+ * from the workspace (see `assistant/src/tools/filesystem/read.ts`).
42
+ */
43
+ const FILE_READ_TOOL_NAME = "file_read";
44
+
45
+ /**
46
+ * Resolve `candidate` against `pkbRoot` and return the absolute path ONLY if
47
+ * it stays inside `pkbRoot`. Otherwise return `undefined`. Guards against
48
+ * `..`-style path traversal.
49
+ */
50
+ function resolveInsidePkbRoot(
51
+ candidate: string,
52
+ pkbRoot: string,
53
+ ): string | undefined {
54
+ if (typeof candidate !== "string" || candidate.length === 0) {
55
+ return undefined;
56
+ }
57
+ const resolved = path.resolve(pkbRoot, candidate);
58
+ // `path.resolve` normalizes any `..` segments in `candidate`. We still need
59
+ // to verify the result is inside `pkbRoot`. Comparing with a trailing
60
+ // separator avoids treating `<pkbRoot>somethingElse` as inside the root.
61
+ if (resolved === pkbRoot) {
62
+ return resolved;
63
+ }
64
+ const rootWithSep = pkbRoot.endsWith(path.sep) ? pkbRoot : pkbRoot + path.sep;
65
+ if (resolved.startsWith(rootWithSep)) {
66
+ return resolved;
67
+ }
68
+ return undefined;
69
+ }
70
+
71
+ /**
72
+ * Returns the set of absolute PKB file paths already in the conversation's
73
+ * in-memory context. This is the union of `autoInjectPaths` (resolved into
74
+ * `pkbRoot`) and any `file_read` tool_use block inputs found in
75
+ * `conversation.messages` that resolve inside `pkbRoot`.
76
+ *
77
+ * `file_read` resolves its `path` argument against `workingDir` (the tool's
78
+ * working directory), so this helper mirrors that rule: relative tool paths
79
+ * are resolved against `workingDir`, absolute paths are taken as-is, and the
80
+ * resulting absolute path is then accepted only if it falls inside `pkbRoot`.
81
+ *
82
+ * Paths outside `pkbRoot` (including `..`-traversal attempts) are excluded.
83
+ * Tool uses whose `name` is not `file_read` are ignored.
84
+ */
85
+ export function getInContextPkbPaths(
86
+ conversation: PkbContextConversation,
87
+ autoInjectPaths: string[],
88
+ pkbRoot: string,
89
+ workingDir: string,
90
+ ): Set<string> {
91
+ const normalizedRoot = path.resolve(pkbRoot);
92
+ const normalizedWorkingDir = path.resolve(workingDir);
93
+ const inContext = new Set<string>();
94
+
95
+ for (const candidate of autoInjectPaths) {
96
+ const resolved = resolveInsidePkbRoot(candidate, normalizedRoot);
97
+ if (resolved !== undefined) {
98
+ inContext.add(resolved);
99
+ }
100
+ }
101
+
102
+ for (const message of conversation.messages) {
103
+ if (!Array.isArray(message.content)) continue;
104
+ for (const block of message.content as ContentBlock[]) {
105
+ if (block.type !== "tool_use") continue;
106
+ if (block.name !== FILE_READ_TOOL_NAME) continue;
107
+ const rawPath = block.input?.path;
108
+ if (typeof rawPath !== "string" || rawPath.length === 0) continue;
109
+ // Mirror `file_read`'s own path resolution: absolute paths are taken
110
+ // as-is; relative paths resolve against the tool's working directory
111
+ // (NOT `pkbRoot`). Resolving relative paths against `pkbRoot` would
112
+ // double-prefix workspace-relative inputs like `pkb/threads.md` into
113
+ // `<pkbRoot>/pkb/threads.md` and miss the actually-loaded file.
114
+ const absolute = path.isAbsolute(rawPath)
115
+ ? path.resolve(rawPath)
116
+ : path.resolve(normalizedWorkingDir, rawPath);
117
+ const resolved = resolveInsidePkbRoot(absolute, normalizedRoot);
118
+ if (resolved !== undefined) {
119
+ inContext.add(resolved);
120
+ }
121
+ }
122
+ }
123
+
124
+ return inContext;
125
+ }
@@ -0,0 +1,70 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { buildPkbReminder } from "./pkb-reminder-builder.js";
4
+
5
+ // Byte-for-byte fixture of the original PKB_SYSTEM_REMINDER from
6
+ // conversation-runtime-assembly.ts. If this ever needs to change, the
7
+ // matching string in conversation-runtime-assembly.ts must change too.
8
+ const ORIGINAL_REMINDER =
9
+ "<system_reminder>" +
10
+ "\nRead any unread Personal Knowledge Base files that might be even partially relevant to this conversation" +
11
+ "\nUse `remember` for anything you learn immediately" +
12
+ "\n</system_reminder>";
13
+
14
+ describe("buildPkbReminder", () => {
15
+ test("empty hints returns exact original reminder byte-for-byte", () => {
16
+ expect(buildPkbReminder([])).toBe(ORIGINAL_REMINDER);
17
+ });
18
+
19
+ test("single hint renders one bullet with no duplicates or trailing blank line", () => {
20
+ const out = buildPkbReminder(["projects/alpha.md"]);
21
+ const expected =
22
+ "<system_reminder>" +
23
+ "\nRead any unread Personal Knowledge Base files that might be even partially relevant to this conversation." +
24
+ "\nBased on the current context, these files look especially relevant:" +
25
+ "\n- projects/alpha.md" +
26
+ "\nUse `remember` for anything you learn immediately" +
27
+ "\n</system_reminder>";
28
+ expect(out).toBe(expected);
29
+
30
+ // Exactly one bullet.
31
+ const bulletCount = (out.match(/^- /gm) ?? []).length;
32
+ expect(bulletCount).toBe(1);
33
+
34
+ // No blank line before closing tag.
35
+ expect(out.includes("\n\n</system_reminder>")).toBe(false);
36
+ });
37
+
38
+ test("three hints render all three in order", () => {
39
+ const hints = ["a.md", "sub/b.md", "c/d/e.md"];
40
+ const out = buildPkbReminder(hints);
41
+ const expected =
42
+ "<system_reminder>" +
43
+ "\nRead any unread Personal Knowledge Base files that might be even partially relevant to this conversation." +
44
+ "\nBased on the current context, these files look especially relevant:" +
45
+ "\n- a.md" +
46
+ "\n- sub/b.md" +
47
+ "\n- c/d/e.md" +
48
+ "\nUse `remember` for anything you learn immediately" +
49
+ "\n</system_reminder>";
50
+ expect(out).toBe(expected);
51
+
52
+ // Order check — each should appear after the previous.
53
+ const idxA = out.indexOf("- a.md");
54
+ const idxB = out.indexOf("- sub/b.md");
55
+ const idxC = out.indexOf("- c/d/e.md");
56
+ expect(idxA).toBeGreaterThan(-1);
57
+ expect(idxB).toBeGreaterThan(idxA);
58
+ expect(idxC).toBeGreaterThan(idxB);
59
+ });
60
+
61
+ test("hints with special chars (< and &) are emitted verbatim (no escaping)", () => {
62
+ const hints = ["weird<name>.md", "foo&bar.md"];
63
+ const out = buildPkbReminder(hints);
64
+ expect(out).toContain("- weird<name>.md");
65
+ expect(out).toContain("- foo&bar.md");
66
+ // Ensure no HTML-style escaping happened.
67
+ expect(out).not.toContain("&lt;");
68
+ expect(out).not.toContain("&amp;");
69
+ });
70
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Render the PKB system_reminder text, optionally with a bulleted list of
3
+ * hint paths that look especially relevant to the current conversation.
4
+ *
5
+ * When `hints` is empty, returns the legacy two-line reminder byte-for-byte.
6
+ * When `hints` is non-empty, renders an extended reminder with a bullet per
7
+ * hint. Hints are emitted verbatim — they are trusted internal paths, not
8
+ * user input, so no escaping is performed.
9
+ *
10
+ * Caller is responsible for capping the hints array at 3 entries.
11
+ */
12
+ export function buildPkbReminder(hints: ReadonlyArray<string>): string {
13
+ if (hints.length === 0) {
14
+ return (
15
+ "<system_reminder>" +
16
+ "\nRead any unread Personal Knowledge Base files that might be even partially relevant to this conversation" +
17
+ "\nUse `remember` for anything you learn immediately" +
18
+ "\n</system_reminder>"
19
+ );
20
+ }
21
+
22
+ const bullets = hints.map((h) => `- ${h}`).join("\n");
23
+ return (
24
+ "<system_reminder>" +
25
+ "\nRead any unread Personal Knowledge Base files that might be even partially relevant to this conversation." +
26
+ "\nBased on the current context, these files look especially relevant:" +
27
+ `\n${bullets}` +
28
+ "\nUse `remember` for anything you learn immediately" +
29
+ "\n</system_reminder>"
30
+ );
31
+ }
@@ -27,6 +27,12 @@ import { googleCalendarProvider } from "../watcher/providers/google-calendar.js"
27
27
  import { linearProvider } from "../watcher/providers/linear.js";
28
28
  import { outlookProvider } from "../watcher/providers/outlook.js";
29
29
  import { outlookCalendarProvider } from "../watcher/providers/outlook-calendar.js";
30
+
31
+ // Side-effect import: runs each bundled first-party skill's tool
32
+ // registration before `initializeTools()` so external tools are visible
33
+ // to the LLM. See `external-skills-bootstrap.ts` for the rationale.
34
+ import "./external-skills-bootstrap.js";
35
+
30
36
  const log = getLogger("lifecycle");
31
37
 
32
38
  export async function initializeProvidersAndTools(
@@ -27,6 +27,7 @@ import type { CesProcessManager } from "../credential-execution/process-manager.
27
27
  import type { FilingService } from "../filing/filing-service.js";
28
28
  import type { HeartbeatService } from "../heartbeat/heartbeat-service.js";
29
29
  import { CliIpcServer } from "../ipc/cli-server.js";
30
+ import { registerBrowserIpcContextResolver } from "../ipc/routes/browser-context.js";
30
31
  import { getApp, getAppDirPath, isMultifileApp } from "../memory/app-store.js";
31
32
  import * as attachmentsStore from "../memory/attachments-store.js";
32
33
  import {
@@ -49,6 +50,7 @@ import {
49
50
  import { getOrCreateConversation } from "../memory/conversation-key-store.js";
50
51
  import { syncIdentityNameToPlatform } from "../platform/sync-identity.js";
51
52
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
53
+ import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
52
54
  import { RateLimitProvider } from "../providers/ratelimit.js";
53
55
  import { getProvider, initializeProviders } from "../providers/registry.js";
54
56
  import {
@@ -60,6 +62,7 @@ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
60
62
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
61
63
  import { getSigningKeyFingerprint } from "../runtime/auth/token-service.js";
62
64
  import { bridgeConfirmationRequestToGuardian } from "../runtime/confirmation-request-guardian-bridge.js";
65
+ import { registerInteractiveUiResolver } from "../runtime/interactive-ui.js";
63
66
  import * as pendingInteractions from "../runtime/pending-interactions.js";
64
67
  import { checkIngressForSecrets } from "../security/secret-ingress.js";
65
68
  import { redactSecrets } from "../security/secret-scanner.js";
@@ -90,10 +93,14 @@ import {
90
93
  } from "./conversation.js";
91
94
  import { ConversationEvictor } from "./conversation-evictor.js";
92
95
  import { registerLaunchConversationDeps } from "./conversation-launch.js";
96
+ import { buildSlackMetaForPersistence } from "./conversation-messaging.js";
93
97
  import { formatCompactResult } from "./conversation-process.js";
94
98
  import { resolveChannelCapabilities } from "./conversation-runtime-assembly.js";
95
99
  import { resolveSlash, type SlashContext } from "./conversation-slash.js";
96
- import { refreshSurfacesForApp } from "./conversation-surfaces.js";
100
+ import {
101
+ refreshSurfacesForApp,
102
+ showStandaloneSurface,
103
+ } from "./conversation-surfaces.js";
97
104
  import { undoLastMessage } from "./handlers/conversations.js";
98
105
  import { parseIdentityFields } from "./handlers/identity.js";
99
106
  import type {
@@ -813,6 +820,11 @@ export class DaemonServer {
813
820
  // DB, exposing only the narrow surface the wake helper needs.
814
821
  registerDefaultWakeResolver(async (conversationId) => {
815
822
  try {
823
+ // Only resolve existing conversations — don't create ghost
824
+ // conversations for stale targets (e.g. meetings that ended
825
+ // but a delayed opportunity callback still fires).
826
+ const existing = getConversation(conversationId);
827
+ if (!existing) return null;
816
828
  const conversation = await this.getOrCreateConversation(conversationId);
817
829
  return conversationToWakeTarget(conversation);
818
830
  } catch (err) {
@@ -824,6 +836,59 @@ export class DaemonServer {
824
836
  }
825
837
  });
826
838
 
839
+ // Install the interactive UI resolver so skills and IPC handlers can
840
+ // present ad-hoc UI surfaces (confirmations, forms) to the user via
841
+ // `requestInteractiveUi()`. Interactive UI requires a client to be
842
+ // actively connected to the conversation (via SSE), which means the
843
+ // conversation must be in the in-memory map. If the conversation was
844
+ // evicted from memory the client is definitely disconnected, so
845
+ // hydration from persistent storage is pointless — the hydrated
846
+ // conversation would have hasNoClient=true, causing
847
+ // canShowInteractiveUi() to return false and the surface to be
848
+ // cancelled with no_interactive_surface. We skip that wasted work
849
+ // and return conversation_not_found directly.
850
+ registerInteractiveUiResolver(async (request) => {
851
+ const conversation = this.conversations.get(request.conversationId);
852
+
853
+ if (!conversation) {
854
+ log.warn(
855
+ {
856
+ conversationId: request.conversationId,
857
+ surfaceType: request.surfaceType,
858
+ },
859
+ "interactive-ui resolver: conversation not in memory (client not connected); failing closed",
860
+ );
861
+ return {
862
+ status: "cancelled" as const,
863
+ surfaceId: `ui-resolver-${Date.now()}`,
864
+ cancellationReason: "conversation_not_found" as const,
865
+ };
866
+ }
867
+
868
+ // Generate a unique surface ID and delegate to the conversation's
869
+ // standalone surface lifecycle. The returned Promise blocks until
870
+ // the user submits, cancels, or the timeout elapses.
871
+ const surfaceId = `ui-standalone-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
872
+ return showStandaloneSurface(conversation, request, surfaceId);
873
+ });
874
+
875
+ // Allow `browser_execute` IPC calls to reuse live conversation browser
876
+ // proxy wiring (when a caller passes a conversationId from
877
+ // __CONVERSATION_ID / __SKILL_CONTEXT_JSON). This keeps nested
878
+ // `assistant browser status` checks consistent with the parent turn's
879
+ // extension connectivity instead of always falling back to a synthetic
880
+ // browser-cli session that has no hostBrowserProxy.
881
+ registerBrowserIpcContextResolver((conversationId) => {
882
+ const conversation = this.conversations.get(conversationId);
883
+ if (!conversation) return null;
884
+ return {
885
+ conversationId,
886
+ trustClass: conversation.trustContext?.trustClass ?? "guardian",
887
+ hostBrowserProxy: conversation.hostBrowserProxy,
888
+ transportInterface: conversation.transportInterface,
889
+ };
890
+ });
891
+
827
892
  // Start the CLI IPC server. Built-in methods (wake_conversation) are
828
893
  // registered by the constructor; CLI commands connect to this socket to
829
894
  // invoke daemon-side operations that require in-process state.
@@ -1033,7 +1098,19 @@ export class DaemonServer {
1033
1098
 
1034
1099
  const createPromise = (async () => {
1035
1100
  const config = getConfig();
1036
- let provider = getProvider(config.services.inference.provider);
1101
+ let provider = getProvider(config.llm.default.provider);
1102
+ // Per-call `options.config.callSite` can resolve to a provider name
1103
+ // that differs from `llm.default.provider`. Wrap the default
1104
+ // provider so the actual transport routes correctly per call,
1105
+ // rather than only forwarding metadata to the default's HTTP
1106
+ // client. See `providers/call-site-routing.ts`.
1107
+ provider = new CallSiteRoutingProvider(provider, (name) => {
1108
+ try {
1109
+ return getProvider(name);
1110
+ } catch {
1111
+ return undefined;
1112
+ }
1113
+ });
1037
1114
  const { rateLimit } = config;
1038
1115
  if (rateLimit.maxRequestsPerMinute > 0) {
1039
1116
  provider = new RateLimitProvider(
@@ -1046,7 +1123,8 @@ export class DaemonServer {
1046
1123
 
1047
1124
  const systemPrompt =
1048
1125
  storedOptions?.systemPromptOverride ?? buildSystemPrompt();
1049
- const maxTokens = storedOptions?.maxResponseTokens ?? config.maxTokens;
1126
+ const maxTokens =
1127
+ storedOptions?.maxResponseTokens ?? config.llm.default.maxTokens;
1050
1128
 
1051
1129
  const memoryPolicy = this.deriveMemoryPolicy(conversationId);
1052
1130
  // Resolve the shared CES client (may still be initializing).
@@ -1065,7 +1143,6 @@ export class DaemonServer {
1065
1143
  sharedCesClient,
1066
1144
  storedOptions?.speed,
1067
1145
  undefined,
1068
- storedOptions?.modelIntent,
1069
1146
  storedOptions?.modelOverride,
1070
1147
  );
1071
1148
  newConversation.updateClient(sendToClient, true);
@@ -1397,6 +1474,7 @@ export class DaemonServer {
1397
1474
  .runAgentLoop(content, messageId, onEvent, {
1398
1475
  isInteractive: options?.isInteractive ?? false,
1399
1476
  isUserMessage: true,
1477
+ ...(options?.callSite ? { callSite: options.callSite } : {}),
1400
1478
  })
1401
1479
  .finally(() => {
1402
1480
  if (
@@ -1437,14 +1515,26 @@ export class DaemonServer {
1437
1515
  messageCount: conversation.getMessages().length,
1438
1516
  inputTokens: conversation.usageStats.inputTokens,
1439
1517
  outputTokens: conversation.usageStats.outputTokens,
1440
- maxInputTokens: config.contextWindow.maxInputTokens,
1441
- model: config.services.inference.model,
1442
- provider: config.services.inference.provider,
1518
+ maxInputTokens: config.llm.default.contextWindow.maxInputTokens,
1519
+ model: config.llm.default.model,
1520
+ provider: config.llm.default.provider,
1443
1521
  estimatedCost: conversation.usageStats.estimatedCost,
1444
1522
  userMessageInterface: serverInterfaceCtx?.userMessageInterface,
1445
1523
  };
1446
1524
  const slashResult = await resolveSlash(content, slashContext);
1447
1525
 
1526
+ // Slack inbound metadata is materialized once here for the slash-command
1527
+ // bypass paths (unknown-slash and /compact), which persist the user row
1528
+ // directly via `addMessage` and would otherwise drop the envelope. The
1529
+ // agent-loop path does not consume this variable — it forwards
1530
+ // `options.slackInbound` through `persistMetadata` and the envelope is
1531
+ // built internally by `buildSlackMetaForPersistence` inside
1532
+ // `persistQueuedMessageBody`.
1533
+ const slackMeta = buildSlackMetaForPersistence({
1534
+ slackInbound: options?.slackInbound,
1535
+ turnChannel: conversation.getTurnChannelContext()?.userMessageChannel,
1536
+ });
1537
+
1448
1538
  if (slashResult.kind === "unknown") {
1449
1539
  const serverTurnCtx = conversation.getTurnChannelContext();
1450
1540
  const serverProvenance = provenanceFromTrustContext(
@@ -1476,13 +1566,20 @@ export class DaemonServer {
1476
1566
  ? { imageSourcePaths }
1477
1567
  : {}),
1478
1568
  };
1569
+ // slackMeta encodes the inbound user message's ts/thread — it attaches
1570
+ // to the user row only. The assistant's slash-command response does not
1571
+ // originate from Slack and must not inherit the user's channelTs, which
1572
+ // would break ordering in the chronological renderer.
1573
+ const userMetaWithSlack = slackMeta
1574
+ ? { ...serverChannelMeta, slackMeta }
1575
+ : serverChannelMeta;
1479
1576
  const cleanMsg = createUserMessage(content, attachments);
1480
1577
  const llmMsg = enrichMessageWithSourcePaths(cleanMsg, attachments);
1481
1578
  const persisted = await addMessage(
1482
1579
  conversationId,
1483
1580
  "user",
1484
1581
  JSON.stringify(cleanMsg.content),
1485
- serverChannelMeta,
1582
+ userMetaWithSlack,
1486
1583
  );
1487
1584
  conversation.getMessages().push(llmMsg);
1488
1585
 
@@ -1560,12 +1657,15 @@ export class DaemonServer {
1560
1657
  }
1561
1658
  : {}),
1562
1659
  };
1660
+ const compactUserMeta = slackMeta
1661
+ ? { ...compactChannelMeta, slackMeta }
1662
+ : compactChannelMeta;
1563
1663
  const cleanMsg = createUserMessage(content, attachments);
1564
1664
  const persisted = await addMessage(
1565
1665
  conversationId,
1566
1666
  "user",
1567
1667
  JSON.stringify(cleanMsg.content),
1568
- compactChannelMeta,
1668
+ compactUserMeta,
1569
1669
  );
1570
1670
  conversation.getMessages().push(cleanMsg);
1571
1671
 
@@ -1590,10 +1690,17 @@ export class DaemonServer {
1590
1690
  const resolvedContent = slashResult.content;
1591
1691
 
1592
1692
  const requestId = crypto.randomUUID();
1693
+ // Slack inbound metadata captured at the channel ingress boundary is
1694
+ // forwarded into the persistence call so `persistQueuedMessageBody` can
1695
+ // emit a `slackMeta` envelope on the row's metadata column.
1696
+ const persistMetadata = options?.slackInbound
1697
+ ? { slackInbound: options.slackInbound }
1698
+ : undefined;
1593
1699
  const messageId = await conversation.persistUserMessage(
1594
1700
  resolvedContent,
1595
1701
  attachments,
1596
1702
  requestId,
1703
+ persistMetadata,
1597
1704
  );
1598
1705
 
1599
1706
  // Register pending interactions so channel approval interception can
@@ -1623,6 +1730,7 @@ export class DaemonServer {
1623
1730
  await conversation.runAgentLoop(resolvedContent, messageId, onEvent, {
1624
1731
  isInteractive: options?.isInteractive ?? false,
1625
1732
  isUserMessage: true,
1733
+ ...(options?.callSite ? { callSite: options.callSite } : {}),
1626
1734
  });
1627
1735
  } finally {
1628
1736
  if (
@@ -195,15 +195,6 @@ registerHook(
195
195
  },
196
196
  );
197
197
 
198
- // Broadcast tasks_changed so connected clients (e.g. macOS Tasks window)
199
- // auto-refresh when the LLM mutates the task queue via tools
200
- registerHook(
201
- ["task_list_add", "task_list_update", "task_list_remove", "task_queue_run"],
202
- (_name, _input, _result, { broadcastToAllClients }) => {
203
- broadcastToAllClients?.({ type: "tasks_changed" });
204
- },
205
- );
206
-
207
198
  // Broadcast voice config changes to all connected clients so every window
208
199
  // picks up the updated UserDefaults value immediately.
209
200
  registerHook(