@vellumai/assistant 0.8.3 → 0.8.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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -20,6 +20,7 @@
20
20
  * | `memory-v2-static` | 38 | after-memory-prefix |
21
21
  * | `now-md` | 40 | after-memory-prefix |
22
22
  * | `active-documents` | 45 | prepend-user-tail |
23
+ * | `document-comments` | 46 | prepend-user-tail |
23
24
  * | `subagent-status` | 50 | append-user-tail |
24
25
  * | `slack-messages` | 60 | replace-run-messages |
25
26
  * | `thread-focus` | 70 | append-user-tail |
@@ -51,6 +52,7 @@ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-fl
51
52
  import { getConfig } from "../../config/loader.js";
52
53
  import { getInContextPkbPaths } from "../../daemon/pkb-context-tracker.js";
53
54
  import { buildPkbReminder } from "../../daemon/pkb-reminder-builder.js";
55
+ import { listComments } from "../../documents/document-comments-store.js";
54
56
  import { searchPkbFiles } from "../../memory/pkb/pkb-search.js";
55
57
  import { getLogger } from "../../util/logger.js";
56
58
  import { registerPlugin } from "../registry.js";
@@ -94,6 +96,7 @@ export const DEFAULT_INJECTOR_ORDER = {
94
96
  memoryV2Static: 38,
95
97
  nowMd: 40,
96
98
  activeDocuments: 45,
99
+ documentComments: 46,
97
100
  subagentStatus: 50,
98
101
  slackMessages: 60,
99
102
  threadFocus: 70,
@@ -133,12 +136,11 @@ const diskPressureWarningInjector: Injector = {
133
136
  };
134
137
 
135
138
  /**
136
- * v2 read-side cutover guard. The `pkb-context` injector silences itself
137
- * under v2 because the `<knowledge_base>` block surfaces PKB content the v2
138
- * activation block already covers. The `pkb-reminder` injector still fires
139
- * (its body is generic recall/remember guidance) but skips the hybrid-search
140
- * hints — those name PKB paths v2 is moving away from. NOW.md is workspace
141
- * state independent of PKB and fires unchanged.
139
+ * v2 read-side cutover guard. Under v2 both `pkb-context` and `pkb-reminder`
140
+ * silence themselves entirely the `<knowledge_base>` content and the
141
+ * generic recall/remember nudge are both supplanted by the v2 static
142
+ * `<memory>` block. NOW.md is workspace state independent of PKB and fires
143
+ * unchanged.
142
144
  */
143
145
  function isPkbInjectionSilencedByV2(): boolean {
144
146
  return getConfig().memory.v2.enabled;
@@ -287,9 +289,8 @@ const pkbReminderInjector: Injector = {
287
289
  const mode = inputs.mode ?? "full";
288
290
  if (mode !== "full") return null;
289
291
  if (!inputs.pkbActive) return null;
290
- const reminder = isPkbInjectionSilencedByV2()
291
- ? buildPkbReminder([])
292
- : await buildPkbReminderWithHints(inputs);
292
+ if (isPkbInjectionSilencedByV2()) return null;
293
+ const reminder = await buildPkbReminderWithHints(inputs);
293
294
  return {
294
295
  id: "pkb-reminder",
295
296
  text: reminder,
@@ -386,17 +387,20 @@ async function buildPkbReminderWithHints(
386
387
  * `memory-v2-static` injector — order 38, after-memory-prefix.
387
388
  *
388
389
  * Injects the v2 static memory block (essentials/threads/recent/buffer
389
- * concatenated under markdown headings) wrapped in `<memory>...</memory>`
390
+ * concatenated under markdown headings) wrapped in `<info>...</info>`
390
391
  * onto the user message. The agent loop only forwards `memoryV2Static` on
391
392
  * full-mode turns (first turn / post-compaction), mirroring the PKB
392
393
  * auto-inject cadence — subsequent turns get `null` and the prior block
393
394
  * stays cached on its original user message.
394
395
  *
395
- * Sits between `pkb-reminder` (35) and `now-md` (40) so the rendered order
396
- * after the memory prefix is `[pkb-reminder, pkb-context, memory-v2-static,
397
- * now-md, ...user text]` when every PKB injector also fires (transitional
398
- * state). Once PKB is fully retired under v2 this is the only block
399
- * adjacent to the memory prefix.
396
+ * Sits between `pkb-reminder` (35) and `now-md` (40). Because every
397
+ * after-memory-prefix splice lands at the memory-prefix boundary in
398
+ * ascending `order`, higher-order blocks end up closer to the memory
399
+ * prefix. The rendered layout is therefore `[<memory>dynamic</memory>,
400
+ * <info>memory-v2-static</info>, <NOW.md>, <system_reminder>,
401
+ * <knowledge_base>, ...user text]` when every PKB injector also fires.
402
+ * `countMemoryPrefixBlocks` treats the `<info>` static block as part of
403
+ * the memory prefix so `now-md` (40) splices after it.
400
404
  *
401
405
  * Gating:
402
406
  * - `mode === "full"`.
@@ -419,14 +423,18 @@ const memoryV2StaticInjector: Injector = {
419
423
  },
420
424
  };
421
425
 
426
+ const INFO_CLOSE_TAG_RE = /<\/info\s*>/gi;
427
+
422
428
  /**
423
- * Wrap the static memory content in `<memory>...</memory>`. Escapes any
424
- * closing `</memory>` inside the content so authored memory files cannot
425
- * accidentally break out of the wrapper.
429
+ * Wrap the static memory content in `<info>...</info>`. Escapes any
430
+ * closing `</info>` inside the content so authored memory files cannot
431
+ * accidentally break out of the wrapper. Distinct from the dynamic
432
+ * activation block (which uses `<memory>...</memory>`) so downstream
433
+ * logic can address the two differently.
426
434
  */
427
435
  function buildMemoryV2StaticBlock(content: string): string {
428
- const escaped = content.replace(/<\/memory\s*>/gi, "&lt;/memory&gt;");
429
- return `<memory>\n${escaped}\n</memory>`;
436
+ const escaped = content.replace(INFO_CLOSE_TAG_RE, "&lt;/info&gt;");
437
+ return `<info>\n${escaped}\n</info>`;
430
438
  }
431
439
 
432
440
  /**
@@ -491,6 +499,77 @@ const activeDocumentsInjector: Injector = {
491
499
  },
492
500
  };
493
501
 
502
+ /** Maximum open comments surfaced per document to limit context bloat. */
503
+ const DOCUMENT_COMMENTS_CAP = 10;
504
+
505
+ /**
506
+ * Escape closing `</document_comments>` inside user-controlled strings so
507
+ * they cannot break out of the XML wrapper — same pattern as
508
+ * {@link buildPkbContextBlock} and {@link buildMemoryV2StaticBlock}.
509
+ */
510
+ function escapeDocCommentTag(s: string): string {
511
+ return s.replace(/<\/document_comments\s*>/gi, "&lt;/document_comments&gt;");
512
+ }
513
+
514
+ /**
515
+ * `document-comments` injector — order 46, prepend-user-tail.
516
+ *
517
+ * Surfaces open top-level comments on active documents so the assistant
518
+ * knows what feedback to address. For each active document, queries the
519
+ * comment store for open top-level comments (capped at
520
+ * {@link DOCUMENT_COMMENTS_CAP} most recent per document). Inline comments
521
+ * include the quoted anchor text; doc-level comments are labelled as such.
522
+ *
523
+ * Gating:
524
+ * - `mode === "full"`.
525
+ * - `activeDocuments` has at least one entry.
526
+ * - At least one document has open comments (returns null otherwise).
527
+ */
528
+ const documentCommentsInjector: Injector = {
529
+ name: "document-comments",
530
+ order: DEFAULT_INJECTOR_ORDER.documentComments,
531
+ async produce(ctx: TurnContext): Promise<InjectionBlock | null> {
532
+ const inputs = readInjectionInputs(ctx);
533
+ const mode = inputs.mode ?? "full";
534
+ if (mode !== "full") return null;
535
+ const docs = inputs.activeDocuments;
536
+ if (!docs || docs.length === 0) return null;
537
+
538
+ const sections: string[] = [];
539
+ for (const doc of docs) {
540
+ const comments = listComments(doc.surfaceId, {
541
+ status: "open",
542
+ topLevelOnly: true,
543
+ }).slice(-DOCUMENT_COMMENTS_CAP);
544
+ if (comments.length === 0) continue;
545
+
546
+ const lines = comments.map((c) => {
547
+ const anchor =
548
+ c.anchorText != null ? escapeDocCommentTag(c.anchorText) : null;
549
+ const label =
550
+ anchor != null ? `inline, anchored to "${anchor}"` : "doc-level";
551
+ return `- Comment #${c.id} (${label}): "${escapeDocCommentTag(c.content)}"`;
552
+ });
553
+ sections.push(
554
+ `Document: "${escapeDocCommentTag(doc.title)}" (surface_id: "${doc.surfaceId}")\n${lines.join("\n")}`,
555
+ );
556
+ }
557
+
558
+ if (sections.length === 0) return null;
559
+
560
+ const text = `<document_comments>
561
+ Open comments on your documents. Address these by editing the document, then use comment_resolve to mark each resolved.
562
+
563
+ ${sections.join("\n\n")}
564
+ </document_comments>`;
565
+ return {
566
+ id: "document-comments",
567
+ text,
568
+ placement: "prepend-user-tail",
569
+ };
570
+ },
571
+ };
572
+
494
573
  /**
495
574
  * `subagent-status` injector — order 50, append-user-tail.
496
575
  *
@@ -626,6 +705,7 @@ export const defaultInjectorsPlugin: Plugin = {
626
705
  memoryV2StaticInjector,
627
706
  nowMdInjector,
628
707
  activeDocumentsInjector,
708
+ documentCommentsInjector,
629
709
  subagentStatusInjector,
630
710
  slackMessagesInjector,
631
711
  threadFocusInjector,
@@ -49,12 +49,8 @@ import semver from "semver";
49
49
  import { z } from "zod";
50
50
 
51
51
  import assistantPkg from "../../package.json" with { type: "json" };
52
- import type {
53
- LoadedPluginTool,
54
- PluginTool,
55
- RiskLevel,
56
- ToolExecutionResult,
57
- } from "../tools/types.js";
52
+ import { finalizeTool } from "../tools/tool-defaults.js";
53
+ import type { LoadedTool, ToolDefinition } from "../tools/types.js";
58
54
  import { getLogger } from "../util/logger.js";
59
55
  import { registerPlugin } from "./registry.js";
60
56
  import type {
@@ -62,7 +58,6 @@ import type {
62
58
  PluginHookFn,
63
59
  PluginHooks,
64
60
  PluginManifest,
65
- PluginToolRegistration,
66
61
  } from "./types.js";
67
62
 
68
63
  const PLUGIN_API_PEER_DEP = "@vellumai/plugin-api";
@@ -122,64 +117,6 @@ function deriveToolName(toolFileBaseName: string): string {
122
117
  return toToolNameSegment(toolFileBaseName);
123
118
  }
124
119
 
125
- /**
126
- * Defaults applied by {@link applyPluginToolDefaults} when a plugin tool
127
- * omits one of the normally-required fields. Exported as a constant so
128
- * tests and callers can reference the same source of truth.
129
- *
130
- * The default `execute` returns an error result so the model sees a clear
131
- * "this tool isn't wired up" signal at call time. The plugin still loads
132
- * cleanly — broken individual tools must never block daemon boot.
133
- */
134
- export const PLUGIN_TOOL_DEFAULTS = Object.freeze({
135
- description: "",
136
- defaultRiskLevel: "medium" as RiskLevel,
137
- input_schema: Object.freeze({
138
- type: "object",
139
- properties: {},
140
- additionalProperties: false,
141
- }) as object,
142
- });
143
-
144
- /**
145
- * Fill the four normally-required {@link PluginTool} fields with documented
146
- * defaults when the author omitted them. Returns a {@link LoadedPluginTool}
147
- * that is safe to register.
148
- */
149
- function applyPluginToolDefaults(
150
- tool: PluginTool,
151
- name: string,
152
- ): LoadedPluginTool {
153
- const description =
154
- typeof tool.description === "string"
155
- ? tool.description
156
- : PLUGIN_TOOL_DEFAULTS.description;
157
- const defaultRiskLevel =
158
- typeof tool.defaultRiskLevel === "string"
159
- ? tool.defaultRiskLevel
160
- : PLUGIN_TOOL_DEFAULTS.defaultRiskLevel;
161
- const input_schema =
162
- tool.input_schema !== null &&
163
- typeof tool.input_schema === "object"
164
- ? tool.input_schema
165
- : PLUGIN_TOOL_DEFAULTS.input_schema;
166
- const execute =
167
- typeof tool.execute === "function"
168
- ? tool.execute
169
- : async (): Promise<ToolExecutionResult> => ({
170
- content: `plugin tool ${name} has no execute implementation`,
171
- isError: true,
172
- });
173
- return {
174
- ...tool,
175
- name,
176
- description,
177
- defaultRiskLevel,
178
- input_schema,
179
- execute,
180
- };
181
- }
182
-
183
120
  /**
184
121
  * Dynamic-import `absolutePath` and return its default export. Throws when
185
122
  * the module has no default export — callers attribute the error.
@@ -339,17 +276,17 @@ async function buildPluginFromDir(pluginDir: string): Promise<Plugin> {
339
276
  const hooks = await loadHooks(pluginDir, name);
340
277
  if (hooks !== undefined) plugin.hooks = hooks;
341
278
 
342
- const tools: PluginToolRegistration[] = [];
279
+ const tools: LoadedTool[] = [];
343
280
  for (const { name: toolName, path: toolPath } of listSurfaceDir(
344
281
  join(pluginDir, "tools"),
345
282
  )) {
346
- const tool = await importDefault<PluginTool>(toolPath);
283
+ const tool = await importDefault<ToolDefinition>(toolPath);
347
284
  if (tool === null || typeof tool !== "object") {
348
285
  throw new Error(
349
286
  `external plugin ${name}: ${toolPath} default export must be an object`,
350
287
  );
351
288
  }
352
- tools.push(applyPluginToolDefaults(tool, deriveToolName(toolName)));
289
+ tools.push(finalizeTool(tool, deriveToolName(toolName)));
353
290
  }
354
291
  if (tools.length > 0) plugin.tools = tools;
355
292
 
@@ -43,7 +43,7 @@ import type {
43
43
  } from "../providers/types.js";
44
44
  import type { SkillRoute } from "../runtime/skill-route-registry.js";
45
45
  import type {
46
- LoadedPluginTool,
46
+ LoadedTool,
47
47
  ToolContext,
48
48
  ToolExecutionResult,
49
49
  } from "../tools/types.js";
@@ -1007,19 +1007,6 @@ export interface Injector {
1007
1007
  // `PluginSkillRegistration` shape below so plugins can declare
1008
1008
  // catalog-discoverable skills today.
1009
1009
 
1010
- /**
1011
- * Tool registration contributed by a plugin. Uses the narrow
1012
- * {@link LoadedPluginTool} shape. External plugin authors declare the
1013
- * nameless `PluginTool` file shape; the loader derives `name` from the
1014
- * `tools/<name>.ts` basename before storing it on `plugin.tools`. Authors
1015
- * also leave category / ownership metadata to the bootstrap, which stamps
1016
- * `category: "plugin"`, `origin: "plugin"`, and
1017
- * `ownerPluginId: <plugin.name>` before handing the batch to
1018
- * `registerPluginTools`. The registration boundary synthesizes
1019
- * `getDefinition()` from `{name, description, input_schema}` so the canonical
1020
- * {@link Tool} interface used by the internal registry stays unchanged.
1021
- */
1022
- export type PluginToolRegistration = LoadedPluginTool;
1023
1010
  /**
1024
1011
  * HTTP route registration contributed by a plugin. Plugins express routes as
1025
1012
  * {@link SkillRoute} values — the same shape the skill-route registry
@@ -1120,8 +1107,16 @@ export interface Plugin {
1120
1107
  manifest: PluginManifest;
1121
1108
  /** Lifecycle hooks (init, shutdown). See {@link PluginHooks}. */
1122
1109
  hooks?: PluginHooks;
1123
- /** Tool registrations visible to the model. */
1124
- tools?: PluginToolRegistration[];
1110
+ /**
1111
+ * Tool registrations visible to the model. External plugin authors
1112
+ * declare the nameless `ToolDefinition` file shape (from
1113
+ * `@vellumai/plugin-api`); the loader derives `name` from the
1114
+ * `tools/<name>.ts` basename and runs the definition through
1115
+ * `finalizeTool` to fill omitted required fields, producing the
1116
+ * `LoadedTool` values stored here. Category / ownership metadata is
1117
+ * stamped by `registerPluginTools` at registration time.
1118
+ */
1119
+ tools?: LoadedTool[];
1125
1120
  /** HTTP route registrations served by the assistant. */
1126
1121
  routes?: PluginRouteRegistration[];
1127
1122
  /** Skill registrations loaded at startup. */
@@ -71,10 +71,23 @@ export async function injectAuxAssistantMessage(params: {
71
71
  });
72
72
  }
73
73
 
74
- params.broadcastMessage({
75
- type: "conversation_list_invalidated",
76
- reason: "reordered",
77
- });
74
+ // The injected aux message bumps `lastMessageAt`, which can move the
75
+ // row in the paginated sidebar window — that's a shape change. macOS
76
+ // refreshes its full list on `conversation_list_invalidated`; web
77
+ // refreshes via the paired `sync_changed` `conversationsList` tag.
78
+ //
79
+ // TODO(electron-cutover): drop the `conversation_list_invalidated`
80
+ // emission once macOS migrates to the Electron client and consumes
81
+ // `sync_changed` directly. See `runtime/sync/resource-sync-events.ts`
82
+ // for the symmetric helper used by route handlers.
83
+ params.broadcastMessage(
84
+ {
85
+ type: "conversation_list_invalidated",
86
+ reason: "reordered",
87
+ },
88
+ undefined,
89
+ { targetInterfaceId: "macos" },
90
+ );
78
91
  params.broadcastMessage({
79
92
  type: "sync_changed",
80
93
  tags: [
@@ -6,7 +6,8 @@
6
6
  * user-message injection that replaced it.
7
7
  */
8
8
 
9
- import { mkdirSync } from "node:fs";
9
+ import { copyFileSync, mkdirSync, readFileSync } from "node:fs";
10
+ import { join } from "node:path";
10
11
  import { beforeEach, describe, expect, mock, test } from "bun:test";
11
12
 
12
13
  const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
@@ -57,7 +58,8 @@ mock.module("../../config/loader.js", () => ({
57
58
  setNestedValue: () => {},
58
59
  }));
59
60
 
60
- const { buildSystemPrompt } = await import("../system-prompt.js");
61
+ const { buildSystemPrompt, maybeReseedBootstrapForCohort } =
62
+ await import("../system-prompt.js");
61
63
 
62
64
  describe("buildSystemPrompt — tool routing guidance", () => {
63
65
  beforeEach(() => {
@@ -70,3 +72,45 @@ describe("buildSystemPrompt — tool routing guidance", () => {
70
72
  expect(result).not.toContain("ask_question");
71
73
  });
72
74
  });
75
+
76
+ describe("maybeReseedBootstrapForCohort — content-automation template", () => {
77
+ const templatesDir = join(import.meta.dirname!, "..", "templates");
78
+
79
+ beforeEach(() => {
80
+ mkdirSync(TEST_DIR, { recursive: true });
81
+ // Seed the workspace with the generic BOOTSTRAP.md so the cohort
82
+ // reseed detects it as an unmodified template and overwrites it.
83
+ copyFileSync(
84
+ join(templatesDir, "BOOTSTRAP.md"),
85
+ join(TEST_DIR, "BOOTSTRAP.md"),
86
+ );
87
+ });
88
+
89
+ function reseedAndRead(): string {
90
+ maybeReseedBootstrapForCohort("content-automation");
91
+ return readFileSync(join(TEST_DIR, "BOOTSTRAP.md"), "utf-8");
92
+ }
93
+
94
+ test("loads the geo-writing skill on first turn", () => {
95
+ const content = reseedAndRead();
96
+ expect(content).toContain("geo-writing");
97
+ });
98
+
99
+ test("uses skill-first onboarding approach", () => {
100
+ const content = reseedAndRead();
101
+ expect(content).toContain("Skill-First Onboarding");
102
+ expect(content).toContain("The skill is the onboarding");
103
+ });
104
+
105
+ test("includes comment-driven edit loop", () => {
106
+ const content = reseedAndRead();
107
+ expect(content).toContain("comment-driven");
108
+ expect(content).toContain("comment_resolve");
109
+ expect(content).toContain("document_update");
110
+ });
111
+
112
+ test("references VOICE.md for voice capture", () => {
113
+ const content = reseedAndRead();
114
+ expect(content).toContain("VOICE.md");
115
+ });
116
+ });
@@ -54,8 +54,9 @@ mock.module("../../config/loader.js", () => ({
54
54
  setNestedValue: () => {},
55
55
  }));
56
56
 
57
- const { buildSystemPrompt, ensurePromptFiles, SYSTEM_PROMPT_CACHE_BOUNDARY } =
58
- await import("../system-prompt.js");
57
+ const { buildSystemPrompt, ensurePromptFiles } = await import(
58
+ "../system-prompt.js"
59
+ );
59
60
 
60
61
  describe("task_progress hint in parallel-tool-calls section", () => {
61
62
  beforeEach(() => {
@@ -85,11 +86,4 @@ describe("task_progress hint in parallel-tool-calls section", () => {
85
86
  expect(withExcludePrefix).toContain("task_progress");
86
87
  });
87
88
 
88
- test("hint lives in the static (cached) block before SYSTEM_PROMPT_CACHE_BOUNDARY", () => {
89
- const result = buildSystemPrompt();
90
- const boundaryIdx = result.indexOf(SYSTEM_PROMPT_CACHE_BOUNDARY);
91
- expect(boundaryIdx).toBeGreaterThan(-1);
92
- const staticBlock = result.slice(0, boundaryIdx);
93
- expect(staticBlock).toContain("task_progress");
94
- });
95
89
  });
@@ -19,6 +19,20 @@ export const TOOL_DISPLAY_NAMES: Record<string, string> = {
19
19
  "apple-notes": "Apple Notes",
20
20
  };
21
21
 
22
+ /**
23
+ * Map of known prior-assistant IDs (from the client onboarding UI) to display names.
24
+ * Unknown IDs pass through with first-letter capitalization via `normalizePriorAssistants`.
25
+ */
26
+ export const PRIOR_ASSISTANT_DISPLAY_NAMES: Record<string, string> = {
27
+ chatgpt: "ChatGPT",
28
+ claude: "Claude",
29
+ openclaw: "OpenClaw",
30
+ hermes: "Hermes",
31
+ manus: "Manus",
32
+ gemini: "Gemini",
33
+ copilot: "Copilot",
34
+ };
35
+
22
36
  /**
23
37
  * Map of known task IDs to plain-language labels describing what the assistant
24
38
  * does for each task category.
@@ -56,14 +70,28 @@ export function normalizeTasks(tasks: string[]): string[] {
56
70
  return tasks.map((id) => TASK_DISPLAY_LABELS[id] ?? id);
57
71
  }
58
72
 
73
+ /**
74
+ * Maps each prior-assistant ID through `PRIOR_ASSISTANT_DISPLAY_NAMES`,
75
+ * falling back to first-letter capitalization for unknown IDs.
76
+ */
77
+ export function normalizePriorAssistants(assistants: string[]): string[] {
78
+ return assistants.map(
79
+ (id) => PRIOR_ASSISTANT_DISPLAY_NAMES[id] ?? capitalizeFirst(id),
80
+ );
81
+ }
82
+
59
83
  export interface NormalizedOnboarding {
60
84
  preferredName?: string;
61
85
  commonWork: string[];
62
86
  dailyTools: string[];
63
87
  tone?: string;
64
88
  assistantName?: string;
89
+ priorAssistants?: string[];
65
90
  googleConnected?: boolean;
66
91
  googleServices?: string[];
92
+ cohort?: string;
93
+ websiteUrl?: string;
94
+ contentSourceUrl?: string;
67
95
  }
68
96
 
69
97
  const SCOPE_SERVICE_MAP: Record<string, string> = {
@@ -103,5 +131,17 @@ export function normalizeOnboardingContext(
103
131
  googleServices: ctx.googleConnected
104
132
  ? deriveGoogleServices(ctx.googleScopes)
105
133
  : undefined,
134
+ priorAssistants: ctx.priorAssistants?.length
135
+ ? normalizePriorAssistants(ctx.priorAssistants)
136
+ : undefined,
137
+ cohort: ctx.cohort,
138
+ websiteUrl:
139
+ typeof ctx.websiteUrl === "string"
140
+ ? ctx.websiteUrl.trim().replace(/[\r\n\t]/g, "") || undefined
141
+ : undefined,
142
+ contentSourceUrl:
143
+ typeof ctx.contentSourceUrl === "string"
144
+ ? ctx.contentSourceUrl.trim().replace(/[\r\n\t]/g, "") || undefined
145
+ : undefined,
106
146
  };
107
147
  }
@@ -77,31 +77,46 @@ function resolveUserFilename(
77
77
  ): string | null {
78
78
  let filename: string | null = null;
79
79
 
80
- if (trustContext === undefined) {
81
- // Desktop / native (no gateway) — resolve via guardian contact,
82
- // preferring the vellum-channel guardian when multiple exist.
83
- const vellumGuardian = findGuardianForChannel("vellum");
84
- const guardian = vellumGuardian ?? listGuardianChannels();
85
- if (guardian) {
86
- filename = guardian.contact.userFile ?? "guardian.md";
87
- }
88
- } else if (trustContext.requesterExternalUserId) {
89
- // Channel-routed request — look up contact by channel identity
90
- const contactWithChannels = findContactByChannelExternalId(
91
- trustContext.sourceChannel,
92
- trustContext.requesterExternalUserId,
93
- );
94
- if (contactWithChannels) {
95
- filename = contactWithChannels.userFile ?? null;
96
- } else if (trustContext.trustClass === "guardian") {
97
- // Managed desktop: the JWT principal ID used as requesterExternalUserId
98
- // may differ from the contact channel's external_user_id (they are
99
- // separate identity concepts). Fall back to the channel-type guardian.
100
- const guardian = findGuardianForChannel(trustContext.sourceChannel);
80
+ try {
81
+ if (trustContext === undefined) {
82
+ // Desktop / native (no gateway) resolve via guardian contact,
83
+ // preferring the vellum-channel guardian when multiple exist.
84
+ const vellumGuardian = findGuardianForChannel("vellum");
85
+ const guardian = vellumGuardian ?? listGuardianChannels();
101
86
  if (guardian) {
102
87
  filename = guardian.contact.userFile ?? "guardian.md";
103
88
  }
89
+ } else if (trustContext.requesterExternalUserId) {
90
+ // Channel-routed request — look up contact by channel identity
91
+ const contactWithChannels = findContactByChannelExternalId(
92
+ trustContext.sourceChannel,
93
+ trustContext.requesterExternalUserId,
94
+ );
95
+ if (contactWithChannels) {
96
+ filename = contactWithChannels.userFile ?? null;
97
+ } else if (trustContext.trustClass === "guardian") {
98
+ // Managed desktop: the JWT principal ID used as requesterExternalUserId
99
+ // may differ from the contact channel's external_user_id (they are
100
+ // separate identity concepts). Fall back to the channel-type guardian.
101
+ const guardian = findGuardianForChannel(trustContext.sourceChannel);
102
+ if (guardian) {
103
+ filename = guardian.contact.userFile ?? "guardian.md";
104
+ }
105
+ }
104
106
  }
107
+ } catch (err) {
108
+ // Contacts table may be absent — happens during early bootstrap
109
+ // before migrations run, in CLI smoke commands that don't touch
110
+ // the DB, and in tests that build the system prompt without first
111
+ // initializing a schema. Treat the same as "no guardian found"
112
+ // so callers fall back to `users/default.md`. Mirrors the same
113
+ // try/catch pattern used by `renderConnectedServices()` around
114
+ // `listConnections()`.
115
+ log.debug(
116
+ { err: err instanceof Error ? err.message : String(err) },
117
+ "Contacts lookup failed during persona resolution; treating as no guardian",
118
+ );
119
+ return null;
105
120
  }
106
121
 
107
122
  // Validate basename to prevent path traversal