@vellumai/assistant 0.8.4 → 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 (438) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docs/browser-use-architecture-phase2.md +1 -1
  3. package/knip.json +2 -1
  4. package/openapi.yaml +809 -11
  5. package/package.json +1 -1
  6. package/src/__tests__/anthropic-provider.test.ts +34 -37
  7. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  8. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  9. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
  11. package/src/__tests__/btw-routes.test.ts +2 -3
  12. package/src/__tests__/call-controller.test.ts +0 -1
  13. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  14. package/src/__tests__/channel-guardian.test.ts +3 -3
  15. package/src/__tests__/checker.test.ts +6 -15
  16. package/src/__tests__/compaction-events.test.ts +1 -0
  17. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  18. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  19. package/src/__tests__/computer-use-tools.test.ts +2 -4
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  21. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  22. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
  24. package/src/__tests__/conversation-agent-loop.test.ts +163 -122
  25. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  26. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  27. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  29. package/src/__tests__/conversation-error.test.ts +31 -0
  30. package/src/__tests__/conversation-fork-crud.test.ts +178 -15
  31. package/src/__tests__/conversation-lifecycle.test.ts +52 -11
  32. package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
  33. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
  34. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  36. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  37. package/src/__tests__/conversation-store.test.ts +1 -1
  38. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  40. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  42. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  43. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  44. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  45. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  46. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  47. package/src/__tests__/email-html-renderer.test.ts +12 -0
  48. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  49. package/src/__tests__/gemini-provider.test.ts +78 -0
  50. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  51. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  52. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  53. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  54. package/src/__tests__/heartbeat-service.test.ts +4 -0
  55. package/src/__tests__/host-shell-tool.test.ts +1 -1
  56. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  57. package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
  58. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  59. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  60. package/src/__tests__/llm-resolver.test.ts +77 -9
  61. package/src/__tests__/llm-usage-store.test.ts +66 -0
  62. package/src/__tests__/logger.test.ts +89 -0
  63. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  64. package/src/__tests__/media-generate-image.test.ts +31 -0
  65. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  66. package/src/__tests__/model-intents.test.ts +2 -4
  67. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  68. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  69. package/src/__tests__/openai-provider.test.ts +46 -0
  70. package/src/__tests__/openai-responses-provider.test.ts +114 -12
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
  72. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  73. package/src/__tests__/platform.test.ts +2 -2
  74. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  75. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  76. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  77. package/src/__tests__/plugin-types.test.ts +3 -2
  78. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  79. package/src/__tests__/pricing.test.ts +12 -0
  80. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  81. package/src/__tests__/registry.test.ts +2 -8
  82. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  83. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  84. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  85. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  86. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  87. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  88. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  89. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  90. package/src/__tests__/suggestion-routes.test.ts +1 -0
  91. package/src/__tests__/sync-message-contract.test.ts +59 -0
  92. package/src/__tests__/system-prompt.test.ts +145 -131
  93. package/src/__tests__/terminal-tools.test.ts +1 -1
  94. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  95. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  96. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  97. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  98. package/src/__tests__/tool-executor.test.ts +9 -62
  99. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  100. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  101. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  102. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  103. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  104. package/src/__tests__/usage-routes.test.ts +3 -0
  105. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  106. package/src/__tests__/workspace-git-service.test.ts +6 -5
  107. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  108. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  109. package/src/acp/prepare-agent-env.ts +78 -0
  110. package/src/acp/session-manager.ts +1 -1
  111. package/src/agent/loop.ts +8 -0
  112. package/src/api/README.md +5 -0
  113. package/src/api/index.ts +4 -0
  114. package/src/api/package.json +10 -0
  115. package/src/background-wake/background-wake-routes.test.ts +233 -0
  116. package/src/background-wake/runtime-registry.ts +24 -0
  117. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  118. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  119. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  120. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  121. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  122. package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
  123. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  124. package/src/cli/commands/browser.ts +247 -0
  125. package/src/cli/commands/domain.ts +91 -41
  126. package/src/cli/commands/inference.ts +93 -40
  127. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  128. package/src/cli/commands/memory-v2.ts +176 -1
  129. package/src/cli/commands/memory-v3-render.ts +344 -0
  130. package/src/cli/commands/memory-v3.ts +316 -0
  131. package/src/cli/program.ts +2 -0
  132. package/src/config/assistant-feature-flags.ts +21 -9
  133. package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
  134. package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
  135. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  136. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  137. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  138. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  139. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  140. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  141. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  142. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  143. package/src/config/bundled-tool-registry.ts +2 -0
  144. package/src/config/call-site-defaults.ts +7 -6
  145. package/src/config/feature-flag-registry.json +16 -0
  146. package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
  147. package/src/config/schemas/call-site-catalog.ts +21 -7
  148. package/src/config/schemas/llm.ts +12 -1
  149. package/src/config/schemas/memory-v2.ts +246 -0
  150. package/src/config/schemas/memory.ts +2 -1
  151. package/src/context/compactor.ts +52 -0
  152. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  153. package/src/conversations/message-consolidation.ts +404 -0
  154. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  155. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  156. package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
  157. package/src/daemon/conversation-agent-loop.ts +126 -76
  158. package/src/daemon/conversation-error.ts +31 -1
  159. package/src/daemon/conversation-lifecycle.ts +27 -22
  160. package/src/daemon/conversation-runtime-assembly.ts +10 -9
  161. package/src/daemon/conversation-tool-setup.ts +63 -3
  162. package/src/daemon/conversation-usage.ts +2 -0
  163. package/src/daemon/conversation.ts +14 -29
  164. package/src/daemon/disk-pressure-guard.ts +14 -2
  165. package/src/daemon/handlers/config-model.test.ts +1 -0
  166. package/src/daemon/handlers/conversations.ts +11 -3
  167. package/src/daemon/host-browser-proxy.ts +5 -5
  168. package/src/daemon/host-cu-proxy.ts +4 -4
  169. package/src/daemon/host-file-proxy.ts +4 -4
  170. package/src/daemon/host-proxy-base.ts +4 -4
  171. package/src/daemon/host-transfer-proxy.ts +10 -10
  172. package/src/daemon/lifecycle.ts +23 -20
  173. package/src/daemon/meet-manifest-loader.ts +1 -7
  174. package/src/daemon/message-types/conversations.ts +6 -9
  175. package/src/daemon/message-types/home.ts +1 -13
  176. package/src/daemon/message-types/messages.ts +6 -14
  177. package/src/daemon/message-types/sync.ts +14 -0
  178. package/src/daemon/shutdown-handlers.ts +24 -5
  179. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  180. package/src/daemon/tool-setup-types.ts +13 -0
  181. package/src/events/relationship-state-updated.ts +25 -0
  182. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
  183. package/src/home/home-greeting.ts +0 -9
  184. package/src/home/suggested-prompts.ts +0 -9
  185. package/src/ipc/gateway-flag-listener.ts +123 -0
  186. package/src/ipc/skill-routes/registries.ts +8 -12
  187. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  188. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  189. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  190. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  191. package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
  192. package/src/memory/auto-analysis-enqueue.ts +5 -1
  193. package/src/memory/conversation-crud.ts +71 -70
  194. package/src/memory/conversation-starters-cadence.ts +3 -1
  195. package/src/memory/conversation-title-service.ts +19 -3
  196. package/src/memory/db-async-query.ts +214 -0
  197. package/src/memory/db-init.ts +10 -0
  198. package/src/memory/db-maintenance.ts +30 -21
  199. package/src/memory/graph/bootstrap.ts +8 -1
  200. package/src/memory/graph/capability-seed.ts +7 -3
  201. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  202. package/src/memory/graph/extraction.ts +1 -5
  203. package/src/memory/graph/graph-search.ts +7 -1
  204. package/src/memory/indexer.ts +28 -18
  205. package/src/memory/job-handlers/cleanup.ts +76 -18
  206. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  207. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  208. package/src/memory/jobs-store.ts +14 -0
  209. package/src/memory/jobs-worker.ts +55 -22
  210. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  211. package/src/memory/llm-request-log-source-local.ts +7 -0
  212. package/src/memory/llm-request-log-source.ts +9 -2
  213. package/src/memory/llm-request-log-store.ts +43 -1
  214. package/src/memory/llm-usage-store.ts +24 -0
  215. package/src/memory/memory-retrospective-enqueue.ts +8 -1
  216. package/src/memory/memory-retrospective-job.ts +5 -0
  217. package/src/memory/memory-v2-activation-log-store.ts +15 -6
  218. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  219. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  220. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  221. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  222. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  223. package/src/memory/migrations/index.ts +17 -0
  224. package/src/memory/migrations/registry.ts +33 -0
  225. package/src/memory/schema/conversations.ts +1 -1
  226. package/src/memory/schema/infrastructure.ts +21 -0
  227. package/src/memory/tool-usage-store.ts +36 -8
  228. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  229. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  230. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  231. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  232. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  233. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  234. package/src/memory/v2/__tests__/injection.test.ts +127 -98
  235. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  236. package/src/memory/v2/__tests__/router.test.ts +171 -3
  237. package/src/memory/v2/harness/compare.ts +57 -0
  238. package/src/memory/v2/harness/metrics.ts +124 -0
  239. package/src/memory/v2/harness/oracle.ts +145 -0
  240. package/src/memory/v2/harness/replay-input.ts +224 -0
  241. package/src/memory/v2/harness/retriever.ts +74 -0
  242. package/src/memory/v2/harness/router-retriever.ts +43 -0
  243. package/src/memory/v2/harness/runner.ts +106 -0
  244. package/src/memory/v2/harness/trace.ts +58 -0
  245. package/src/memory/v2/injection.ts +21 -15
  246. package/src/memory/v2/prompts/router.ts +26 -1
  247. package/src/memory/v2/qdrant.ts +14 -2
  248. package/src/memory/v2/router.ts +171 -18
  249. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  250. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  251. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  252. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  253. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  254. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  255. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  256. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  257. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  258. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  259. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  260. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  261. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  262. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  263. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  264. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  265. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  266. package/src/memory/v3/auto-edges.ts +223 -0
  267. package/src/memory/v3/coactivation-store.ts +124 -0
  268. package/src/memory/v3/consolidation-job.ts +323 -0
  269. package/src/memory/v3/edge-learning-job.ts +160 -0
  270. package/src/memory/v3/edges.ts +249 -0
  271. package/src/memory/v3/filter.ts +281 -0
  272. package/src/memory/v3/gate.ts +334 -0
  273. package/src/memory/v3/index-composition.ts +113 -0
  274. package/src/memory/v3/llm-capture.ts +46 -0
  275. package/src/memory/v3/loop.ts +382 -0
  276. package/src/memory/v3/maintenance.ts +144 -0
  277. package/src/memory/v3/prompt-context.ts +33 -0
  278. package/src/memory/v3/prompts/consolidation.ts +458 -0
  279. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  280. package/src/memory/v3/retriever.ts +33 -0
  281. package/src/memory/v3/scouts.ts +420 -0
  282. package/src/memory/v3/shadow-middleware.ts +305 -0
  283. package/src/memory/v3/traversal.ts +206 -0
  284. package/src/memory/v3/tree-index.ts +237 -0
  285. package/src/memory/v3/tree-store.ts +394 -0
  286. package/src/memory/v3/tree-walk.ts +351 -0
  287. package/src/memory/v3/types.ts +65 -0
  288. package/src/memory/v3/validate.ts +300 -0
  289. package/src/notifications/adapters/macos.ts +18 -1
  290. package/src/notifications/adapters/platform.ts +1 -1
  291. package/src/notifications/decision-engine.ts +1 -4
  292. package/src/notifications/emit-signal.ts +29 -49
  293. package/src/permissions/prompter.ts +3 -3
  294. package/src/permissions/question-prompter.ts +5 -2
  295. package/src/permissions/secret-prompter.ts +2 -2
  296. package/src/plugin-api/index.ts +4 -0
  297. package/src/plugin-api/types.ts +7 -33
  298. package/src/plugins/defaults/index.ts +6 -0
  299. package/src/plugins/defaults/injectors.ts +18 -11
  300. package/src/plugins/external-plugin-loader.ts +5 -68
  301. package/src/plugins/types.ts +11 -16
  302. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  303. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  304. package/src/prompts/persona-resolver.ts +36 -21
  305. package/src/prompts/sections.ts +39 -7
  306. package/src/prompts/system-prompt.ts +50 -185
  307. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  308. package/src/prompts/templates/system-sections.ts +230 -8
  309. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  310. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  311. package/src/providers/anthropic/client.ts +32 -66
  312. package/src/providers/call-site-routing.ts +14 -2
  313. package/src/providers/connection-model-compat.ts +38 -0
  314. package/src/providers/connection-resolution.ts +16 -2
  315. package/src/providers/gemini/client.ts +49 -6
  316. package/src/providers/inference/adapter-factory.ts +3 -0
  317. package/src/providers/minimax/client.ts +106 -0
  318. package/src/providers/model-catalog.ts +43 -0
  319. package/src/providers/model-intents.ts +1 -1
  320. package/src/providers/openai/chat-completions-provider.ts +6 -3
  321. package/src/providers/openai/codex-models.ts +18 -0
  322. package/src/providers/openai/responses-provider.ts +78 -21
  323. package/src/providers/provider-send-message.ts +7 -1
  324. package/src/providers/retry.ts +34 -3
  325. package/src/providers/thinking-config.ts +26 -1
  326. package/src/providers/usage-tracking.ts +2 -0
  327. package/src/runtime/AGENTS.md +2 -2
  328. package/src/runtime/agent-wake.ts +1 -0
  329. package/src/runtime/assistant-event-hub.ts +76 -6
  330. package/src/runtime/auth/route-policy.ts +36 -0
  331. package/src/runtime/btw-sidechain.ts +0 -6
  332. package/src/runtime/http-types.ts +0 -2
  333. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  334. package/src/runtime/pending-interactions.ts +0 -1
  335. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
  336. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
  337. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  338. package/src/runtime/routes/acp-routes.test.ts +255 -6
  339. package/src/runtime/routes/acp-routes.ts +8 -1
  340. package/src/runtime/routes/avatar-routes.ts +10 -10
  341. package/src/runtime/routes/background-wake-routes.ts +188 -0
  342. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  343. package/src/runtime/routes/btw-routes.ts +0 -6
  344. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  345. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  346. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  347. package/src/runtime/routes/conversation-query-routes.ts +142 -36
  348. package/src/runtime/routes/conversation-routes.ts +252 -410
  349. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  350. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  351. package/src/runtime/routes/domain-routes.ts +60 -10
  352. package/src/runtime/routes/email-routes.ts +5 -2
  353. package/src/runtime/routes/events-routes.ts +54 -10
  354. package/src/runtime/routes/group-routes.ts +24 -8
  355. package/src/runtime/routes/host-browser-routes.ts +10 -2
  356. package/src/runtime/routes/host-cu-routes.ts +2 -2
  357. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  358. package/src/runtime/routes/index.ts +8 -0
  359. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  360. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  361. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  362. package/src/runtime/routes/memory-item-routes.ts +8 -3
  363. package/src/runtime/routes/memory-v2-routes.ts +215 -5
  364. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  365. package/src/runtime/routes/migration-routes.ts +21 -24
  366. package/src/runtime/routes/plugins-routes.ts +337 -0
  367. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  368. package/src/runtime/routes/secret-routes.ts +25 -5
  369. package/src/runtime/routes/settings-routes.ts +12 -11
  370. package/src/runtime/routes/slack-channel-routes.ts +5 -4
  371. package/src/runtime/routes/workspace-routes.ts +25 -10
  372. package/src/runtime/sync/resource-sync-events.ts +106 -38
  373. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  374. package/src/runtime/sync/sync-publisher.ts +2 -1
  375. package/src/runtime/verification-outbound-actions.ts +73 -1
  376. package/src/telemetry/types.ts +12 -0
  377. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  378. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  379. package/src/tools/acp/spawn.test.ts +119 -0
  380. package/src/tools/acp/spawn.ts +15 -2
  381. package/src/tools/apps/definitions.ts +2 -8
  382. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  383. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  384. package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
  385. package/src/tools/browser/browser-execution.ts +16 -3
  386. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  387. package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
  388. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
  389. package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
  390. package/src/tools/browser/cdp-client/factory.ts +100 -17
  391. package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
  392. package/src/tools/browser/cdp-client/types.ts +65 -0
  393. package/src/tools/browser/pinned-tabs.ts +96 -40
  394. package/src/tools/computer-use/definitions.ts +22 -78
  395. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  396. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  397. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  398. package/src/tools/credentials/vault.ts +3 -9
  399. package/src/tools/document/document-tool.ts +59 -0
  400. package/src/tools/execution-target.ts +21 -23
  401. package/src/tools/executor.ts +6 -1
  402. package/src/tools/filesystem/edit.ts +3 -9
  403. package/src/tools/filesystem/list.ts +3 -9
  404. package/src/tools/filesystem/read.ts +3 -9
  405. package/src/tools/filesystem/write.ts +3 -9
  406. package/src/tools/host-filesystem/edit.ts +3 -9
  407. package/src/tools/host-filesystem/read.ts +3 -9
  408. package/src/tools/host-filesystem/transfer.ts +3 -9
  409. package/src/tools/host-filesystem/write.ts +3 -9
  410. package/src/tools/host-terminal/host-shell.ts +3 -9
  411. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  412. package/src/tools/memory/register.test.ts +1 -1
  413. package/src/tools/memory/register.ts +4 -9
  414. package/src/tools/network/web-fetch.ts +3 -9
  415. package/src/tools/network/web-search.ts +25 -32
  416. package/src/tools/registry.ts +7 -23
  417. package/src/tools/schema-transforms.ts +1 -1
  418. package/src/tools/skills/execute.ts +3 -9
  419. package/src/tools/skills/load.ts +3 -9
  420. package/src/tools/skills/skill-tool-factory.ts +1 -8
  421. package/src/tools/subagent/notify-parent.ts +3 -9
  422. package/src/tools/system/request-permission.ts +3 -9
  423. package/src/tools/terminal/shell.ts +3 -9
  424. package/src/tools/tool-defaults.ts +94 -0
  425. package/src/tools/types.ts +27 -98
  426. package/src/tools/ui-surface/definitions.ts +6 -22
  427. package/src/usage/pricing.ts +23 -0
  428. package/src/usage/types.ts +12 -0
  429. package/src/util/logger.ts +16 -7
  430. package/src/util/platform.ts +7 -2
  431. package/src/util/sqlite3-runtime.ts +65 -0
  432. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  433. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  434. package/src/workspace/migrations/registry.ts +2 -0
  435. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  436. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  437. package/src/daemon/query-complexity-router.ts +0 -75
  438. package/src/prompts/cache-boundary.ts +0 -8
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Routes for browser tab management commands.
3
+ *
4
+ * Exposes `browser_tabs` so CLI commands can list, create, select, and
5
+ * close browser tabs via the Chrome extension backend.
6
+ */
7
+
8
+ import { z } from "zod";
9
+
10
+ import { findConversation } from "../../daemon/conversation-store.js";
11
+ import { getCdpClient } from "../../tools/browser/cdp-client/factory.js";
12
+ import {
13
+ clearPinnedTab,
14
+ clearPinnedTabByTabId,
15
+ setPinnedTab,
16
+ } from "../../tools/browser/pinned-tabs.js";
17
+ import type { ToolContext } from "../../tools/types.js";
18
+ import { browserCliConversationKey } from "./browser-routes.js";
19
+ import { BadRequestError } from "./errors.js";
20
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
21
+
22
+ const BrowserTabsParams = z.object({
23
+ command: z.enum(["list", "select", "new", "close"]),
24
+ sessionId: z.string().min(1).default("default"),
25
+ conversationId: z.string().min(1).optional(),
26
+ tabId: z.number().optional(),
27
+ url: z.string().optional(),
28
+ // Route tab operations to a specific extension client in multi-client
29
+ // setups. Mirrors browser/execute's `target_client_id` semantics.
30
+ targetClientId: z.string().min(1).optional(),
31
+ });
32
+
33
+ async function handleBrowserTabs({ body = {} }: RouteHandlerArgs) {
34
+ const { command, sessionId, conversationId, tabId, url, targetClientId } =
35
+ BrowserTabsParams.parse(body);
36
+
37
+ const conversation = conversationId
38
+ ? findConversation(conversationId)
39
+ : undefined;
40
+ const resolvedConversationId = conversation
41
+ ? conversationId!
42
+ : browserCliConversationKey(sessionId);
43
+
44
+ const context = {
45
+ workingDir: process.cwd(),
46
+ conversationId: resolvedConversationId,
47
+ trustClass: conversation?.trustContext?.trustClass ?? "unknown",
48
+ transportInterface: conversation?.transportInterface,
49
+ } as unknown as ToolContext;
50
+
51
+ const cdpOptions = { mode: "extension" as const, targetClientId };
52
+
53
+ if (command === "list") {
54
+ const cdp = getCdpClient(context, cdpOptions);
55
+ try {
56
+ const tabs = await cdp.listTabs();
57
+ return { ok: true, tabs };
58
+ } finally {
59
+ cdp.dispose();
60
+ }
61
+ }
62
+
63
+ if (command === "select") {
64
+ if (tabId === undefined) {
65
+ throw new BadRequestError("tabId is required for the select command");
66
+ }
67
+ const cdp = getCdpClient(context, cdpOptions);
68
+ try {
69
+ const result = await cdp.selectTab(tabId);
70
+ const clientId =
71
+ typeof result?.clientId === "string" && result.clientId.length > 0
72
+ ? result.clientId
73
+ : undefined;
74
+ if (result?.tabId !== undefined) {
75
+ setPinnedTab(
76
+ resolvedConversationId,
77
+ String(result.tabId),
78
+ clientId,
79
+ );
80
+ }
81
+ return { ok: true, tab: result };
82
+ } finally {
83
+ cdp.dispose();
84
+ }
85
+ }
86
+
87
+ if (command === "new") {
88
+ const cdp = getCdpClient(context, cdpOptions);
89
+ try {
90
+ const result = await cdp.send<{ tabId?: number | string; clientId?: string }>(
91
+ "Vellum.createTab",
92
+ {},
93
+ );
94
+ // Normalise to string for internal use (setCdpSessionId / setPinnedTab)
95
+ // and keep the numeric form for the API response.
96
+ const newTabIdStr: string | undefined =
97
+ typeof result?.tabId === "number"
98
+ ? String(result.tabId)
99
+ : typeof result?.tabId === "string"
100
+ ? result.tabId
101
+ : undefined;
102
+ const newTabIdNum: number | undefined =
103
+ typeof result?.tabId === "number"
104
+ ? result.tabId
105
+ : typeof result?.tabId === "string"
106
+ ? parseInt(result.tabId, 10)
107
+ : undefined;
108
+ const clientId =
109
+ typeof result?.clientId === "string" && result.clientId.length > 0
110
+ ? result.clientId
111
+ : undefined;
112
+ if (newTabIdStr) {
113
+ cdp.setCdpSessionId?.(newTabIdStr);
114
+ setPinnedTab(resolvedConversationId, newTabIdStr, clientId);
115
+ if (url) {
116
+ await cdp.send("Page.navigate", { url });
117
+ }
118
+ } else if (targetClientId) {
119
+ // Only scope-clear the targeted client's pin. With the per-(conversationId,
120
+ // clientId) pin store (#31361), passing no clientId to clearPinnedTab
121
+ // would wipe pins for *every* connected client on this conversation
122
+ // and break their routing — so we skip the clear entirely when the
123
+ // caller didn't explicitly target a client. The stale pin (if any)
124
+ // is overwritten on the next successful tab operation.
125
+ clearPinnedTab(resolvedConversationId, targetClientId);
126
+ }
127
+ return { ok: true, tabId: newTabIdNum, clientId };
128
+ } finally {
129
+ cdp.dispose();
130
+ }
131
+ }
132
+
133
+ if (command === "close") {
134
+ if (tabId === undefined) {
135
+ throw new BadRequestError("tabId is required for the close command");
136
+ }
137
+ const cdp = getCdpClient(context, cdpOptions);
138
+ try {
139
+ const result = await cdp.closeTab(tabId);
140
+ // Clear any pinned-tab slot still pointing at the closed tabId so
141
+ // subsequent browser tool calls don't route to a dead cdpSessionId
142
+ // and fail with session-not-found. Tabs that never debugger-attached
143
+ // (e.g. `tabs new` without `--url`) won't emit a detach invalidation
144
+ // event, so the pin would otherwise leak.
145
+ //
146
+ // Scope the clear to the actual responding client. Prefer the
147
+ // clientId from the closeTab response (resolved by the extension
148
+ // dispatcher), fall back to the caller-supplied targetClientId.
149
+ // Without a resolved clientId we skip the clear entirely — calling
150
+ // clearPinnedTabByTabId without a clientId would wipe matching pins
151
+ // across every client (Chrome tab IDs are per-instance, not
152
+ // globally unique), breaking the per-(conversationId, clientId)
153
+ // pin isolation added in #31361. The stale pin in the unscoped
154
+ // case will self-heal via the session-not-found cleanup on the
155
+ // next browser op against that pin.
156
+ const resolvedClientId = result.clientId ?? targetClientId;
157
+ if (resolvedClientId) {
158
+ clearPinnedTabByTabId(String(tabId), resolvedClientId);
159
+ }
160
+ return { ok: true, ...result };
161
+ } finally {
162
+ cdp.dispose();
163
+ }
164
+ }
165
+
166
+ throw new BadRequestError(`Unknown tabs command: ${command}`);
167
+ }
168
+
169
+ export const ROUTES: RouteDefinition[] = [
170
+ {
171
+ operationId: "browser_tabs",
172
+ endpoint: "browser/tabs",
173
+ method: "POST",
174
+ handler: handleBrowserTabs,
175
+ summary: "Manage browser tabs",
176
+ description:
177
+ "List, create, select, or close browser tabs via the Chrome extension backend.",
178
+ tags: ["browser"],
179
+ requestBody: BrowserTabsParams,
180
+ responseBody: z.object({
181
+ ok: z.boolean(),
182
+ tabs: z
183
+ .array(
184
+ z.object({
185
+ tabId: z.number().optional(),
186
+ windowId: z.number().optional(),
187
+ url: z.string().optional(),
188
+ title: z.string().optional(),
189
+ active: z.boolean(),
190
+ pinned: z.boolean(),
191
+ }),
192
+ )
193
+ .optional(),
194
+ tab: z.unknown().optional(),
195
+ tabId: z.number().optional(),
196
+ clientId: z.string().optional(),
197
+ closed: z.boolean().optional(),
198
+ }),
199
+ },
200
+ ];
@@ -22,7 +22,6 @@ import { getOrCreateConversation } from "../../daemon/conversation-store.js";
22
22
  import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
23
23
  import { parseIdentityFields } from "../../daemon/handlers/identity.js";
24
24
  import { getConversationByKey } from "../../memory/conversation-key-store.js";
25
- import { resolvePersonaContext } from "../../prompts/persona-resolver.js";
26
25
  import { getLogger } from "../../util/logger.js";
27
26
  import { getWorkspacePromptPath } from "../../util/platform.js";
28
27
  import { runBtwSidechain } from "../btw-sidechain.js";
@@ -120,16 +119,11 @@ async function handleBtw({
120
119
  try {
121
120
  const isIntroRequest = conversationKey === IDENTITY_INTRO_KEY;
122
121
  const isGreeting = conversationKey === GREETING_KEY;
123
- const { userPersona, userSlug, channelPersona } =
124
- resolvePersonaContext(undefined, undefined);
125
122
  const result = await runBtwSidechain({
126
123
  content: effectiveContent,
127
124
  conversation,
128
125
  tools: buildToolDefinitions(),
129
126
  signal: abortSignal,
130
- userPersona,
131
- channelPersona,
132
- userSlug,
133
127
  ...(isGreeting ? { callSite: "emptyStateGreeting" as const } : {}),
134
128
  onEvent: (event) => {
135
129
  if (event.type === "text_delta") {
@@ -145,7 +145,7 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
145
145
 
146
146
  async function handleClearCli(_args: RouteHandlerArgs) {
147
147
  // Tear down in-memory conversation state before DB clear.
148
- const cleared = clearAllActive();
148
+ const cleared = await clearAllActive();
149
149
  log.info(
150
150
  { cleared },
151
151
  "CLI conversations clear: active conversations torn down",
@@ -111,7 +111,7 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
111
111
  return response;
112
112
  }
113
113
 
114
- function handleRecordSeen({ body = {} }: RouteHandlerArgs) {
114
+ function handleRecordSeen({ body = {}, headers }: RouteHandlerArgs) {
115
115
  const rawConversationId = body.conversationId as string | undefined;
116
116
  if (!rawConversationId) {
117
117
  throw new BadRequestError("Missing conversationId");
@@ -142,7 +142,11 @@ function handleRecordSeen({ body = {} }: RouteHandlerArgs) {
142
142
  });
143
143
 
144
144
  if (wasUnseen) {
145
- publishConversationListAndMetadataChanged("seen_changed", conversationId);
145
+ publishConversationListAndMetadataChanged(
146
+ "seen_changed",
147
+ conversationId,
148
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
149
+ );
146
150
  }
147
151
 
148
152
  return { ok: true };
@@ -152,7 +156,7 @@ function handleRecordSeen({ body = {} }: RouteHandlerArgs) {
152
156
  }
153
157
  }
154
158
 
155
- function handleMarkUnread({ body = {} }: RouteHandlerArgs) {
159
+ function handleMarkUnread({ body = {}, headers }: RouteHandlerArgs) {
156
160
  const rawConversationId = body.conversationId as string | undefined;
157
161
  if (!rawConversationId) {
158
162
  throw new BadRequestError("Missing conversationId");
@@ -162,7 +166,11 @@ function handleMarkUnread({ body = {} }: RouteHandlerArgs) {
162
166
  try {
163
167
  const changed = markConversationUnread(conversationId);
164
168
  if (changed) {
165
- publishConversationListAndMetadataChanged("seen_changed", conversationId);
169
+ publishConversationListAndMetadataChanged(
170
+ "seen_changed",
171
+ conversationId,
172
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
173
+ );
166
174
  }
167
175
  return { ok: true };
168
176
  } catch (err) {
@@ -84,7 +84,7 @@ function cancelScheduleIfLast(conversationId: string): void {
84
84
  // Handlers
85
85
  // ---------------------------------------------------------------------------
86
86
 
87
- function handleCreateConversation({ body = {} }: RouteHandlerArgs) {
87
+ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
88
88
  const conversationKey =
89
89
  (body.conversationKey as string | undefined) ?? crypto.randomUUID();
90
90
  const result = getOrCreateConversation(conversationKey, {
@@ -92,7 +92,11 @@ function handleCreateConversation({ body = {} }: RouteHandlerArgs) {
92
92
  });
93
93
  if (result.created) {
94
94
  updateConversationTitle(result.conversationId, "New Conversation");
95
- publishConversationListAndMetadataChanged("created", result.conversationId);
95
+ publishConversationListAndMetadataChanged(
96
+ "created",
97
+ result.conversationId,
98
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
99
+ );
96
100
  }
97
101
  log.info(
98
102
  {
@@ -110,7 +114,7 @@ function handleCreateConversation({ body = {} }: RouteHandlerArgs) {
110
114
  };
111
115
  }
112
116
 
113
- async function handleForkConversation({ body = {} }: RouteHandlerArgs) {
117
+ async function handleForkConversation({ body = {}, headers }: RouteHandlerArgs) {
114
118
  const conversationId = body.conversationId as string | undefined;
115
119
  if (!conversationId || typeof conversationId !== "string") {
116
120
  throw new BadRequestError("Missing conversationId");
@@ -136,7 +140,11 @@ async function handleForkConversation({ body = {} }: RouteHandlerArgs) {
136
140
  `Forked conversation ${forkedConversation.id} could not be loaded`,
137
141
  );
138
142
  }
139
- publishConversationListAndMetadataChanged("created", forkedConversation.id);
143
+ publishConversationListAndMetadataChanged(
144
+ "created",
145
+ forkedConversation.id,
146
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
147
+ );
140
148
  return { conversation: detail.conversation };
141
149
  } catch (err) {
142
150
  if (err instanceof UserError) {
@@ -171,6 +179,7 @@ async function handleSwitchConversation({ body = {} }: RouteHandlerArgs) {
171
179
  async function handleSetInferenceProfile({
172
180
  pathParams = {},
173
181
  body = {},
182
+ headers,
174
183
  }: RouteHandlerArgs) {
175
184
  if (
176
185
  body.profile !== null &&
@@ -184,6 +193,7 @@ async function handleSetInferenceProfile({
184
193
  profile: body.profile as string | null,
185
194
  ttlSeconds: body.ttlSeconds as number | null | undefined,
186
195
  sessionId: body.sessionId as string | undefined,
196
+ originClientId: headers?.["x-vellum-client-id"]?.trim() || undefined,
187
197
  });
188
198
 
189
199
  return result;
@@ -192,6 +202,7 @@ async function handleSetInferenceProfile({
192
202
  function handleRenameConversation({
193
203
  pathParams = {},
194
204
  body = {},
205
+ headers,
195
206
  }: RouteHandlerArgs) {
196
207
  const name = body.name as string | undefined;
197
208
  if (!name || typeof name !== "string") {
@@ -203,12 +214,18 @@ function handleRenameConversation({
203
214
  }
204
215
  updateConversationTitle(pathParams.id!, name, 0);
205
216
 
206
- publishConversationTitleChanged(pathParams.id!, name);
217
+ publishConversationTitleChanged(
218
+ pathParams.id!,
219
+ name,
220
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
221
+ );
207
222
 
208
223
  return { ok: true };
209
224
  }
210
225
 
211
- function handleClearAllConversations({ headers = {} }: RouteHandlerArgs) {
226
+ async function handleClearAllConversations({
227
+ headers = {},
228
+ }: RouteHandlerArgs) {
212
229
  const confirm = headers["x-confirm-destructive"];
213
230
  if (confirm !== "clear-all-conversations") {
214
231
  throw new BadRequestError(
@@ -216,12 +233,15 @@ function handleClearAllConversations({ headers = {} }: RouteHandlerArgs) {
216
233
  "To confirm, set header X-Confirm-Destructive: clear-all-conversations",
217
234
  );
218
235
  }
219
- clearAllConversations();
220
- publishConversationListChanged("deleted");
236
+ await clearAllConversations();
237
+ publishConversationListChanged(
238
+ "deleted",
239
+ headers["x-vellum-client-id"]?.trim() || undefined,
240
+ );
221
241
  return undefined;
222
242
  }
223
243
 
224
- function handleWipeConversation({ pathParams = {} }: RouteHandlerArgs) {
244
+ function handleWipeConversation({ pathParams = {}, headers }: RouteHandlerArgs) {
225
245
  const resolvedId = resolveOrThrow(pathParams.id!);
226
246
 
227
247
  cancelScheduleIfLast(resolvedId);
@@ -248,7 +268,11 @@ function handleWipeConversation({ pathParams = {} }: RouteHandlerArgs) {
248
268
  },
249
269
  "Wiped conversation and reverted memory changes",
250
270
  );
251
- publishConversationListAndMetadataChanged("deleted", resolvedId);
271
+ publishConversationListAndMetadataChanged(
272
+ "deleted",
273
+ resolvedId,
274
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
275
+ );
252
276
  return {
253
277
  wiped: true,
254
278
  unsupersededItems: 0,
@@ -257,7 +281,10 @@ function handleWipeConversation({ pathParams = {} }: RouteHandlerArgs) {
257
281
  };
258
282
  }
259
283
 
260
- function handleDeleteConversation({ pathParams = {} }: RouteHandlerArgs) {
284
+ function handleDeleteConversation({
285
+ pathParams = {},
286
+ headers,
287
+ }: RouteHandlerArgs) {
261
288
  const resolvedId = resolveOrThrow(pathParams.id!);
262
289
 
263
290
  cancelScheduleIfLast(resolvedId);
@@ -278,28 +305,46 @@ function handleDeleteConversation({ pathParams = {} }: RouteHandlerArgs) {
278
305
  }
279
306
  log.info({ conversationId: resolvedId }, "Deleted conversation");
280
307
 
281
- publishConversationListAndMetadataChanged("deleted", resolvedId);
308
+ publishConversationListAndMetadataChanged(
309
+ "deleted",
310
+ resolvedId,
311
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
312
+ );
282
313
 
283
314
  return undefined;
284
315
  }
285
316
 
286
- function handleArchiveConversation({ pathParams = {} }: RouteHandlerArgs) {
317
+ function handleArchiveConversation({
318
+ pathParams = {},
319
+ headers,
320
+ }: RouteHandlerArgs) {
287
321
  const resolvedId = resolveOrThrow(pathParams.id!);
288
322
  const archived = archiveConversation(resolvedId);
289
323
  if (!archived) {
290
324
  throw new NotFoundError(`Conversation ${pathParams.id} not found`);
291
325
  }
292
- publishConversationListAndMetadataChanged("reordered", resolvedId);
326
+ publishConversationListAndMetadataChanged(
327
+ "reordered",
328
+ resolvedId,
329
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
330
+ );
293
331
  return { ok: true, conversationId: resolvedId };
294
332
  }
295
333
 
296
- function handleUnarchiveConversation({ pathParams = {} }: RouteHandlerArgs) {
334
+ function handleUnarchiveConversation({
335
+ pathParams = {},
336
+ headers,
337
+ }: RouteHandlerArgs) {
297
338
  const resolvedId = resolveOrThrow(pathParams.id!);
298
339
  const unarchived = unarchiveConversation(resolvedId);
299
340
  if (!unarchived) {
300
341
  throw new NotFoundError(`Conversation ${pathParams.id} not found`);
301
342
  }
302
- publishConversationListAndMetadataChanged("reordered", resolvedId);
343
+ publishConversationListAndMetadataChanged(
344
+ "reordered",
345
+ resolvedId,
346
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
347
+ );
303
348
  return { ok: true, conversationId: resolvedId };
304
349
  }
305
350
 
@@ -339,7 +384,7 @@ async function handleRegenerateResponse({ pathParams = {} }: RouteHandlerArgs) {
339
384
  }
340
385
  }
341
386
 
342
- function handleReorderConversations({ body = {} }: RouteHandlerArgs) {
387
+ function handleReorderConversations({ body = {}, headers }: RouteHandlerArgs) {
343
388
  const updates = body.updates as
344
389
  | Array<{
345
390
  conversationId: string;
@@ -362,6 +407,7 @@ function handleReorderConversations({ body = {} }: RouteHandlerArgs) {
362
407
  publishConversationListAndMetadataChanged(
363
408
  "reordered",
364
409
  updates.map((u) => u.conversationId),
410
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
365
411
  );
366
412
  return { ok: true };
367
413
  }
@@ -382,15 +428,26 @@ export const ROUTES: RouteDefinition[] = [
382
428
  requestBody: z.object({
383
429
  conversationKey: z
384
430
  .string()
385
- .describe("Idempotency key for the conversation"),
431
+ .optional()
432
+ .describe(
433
+ "Optional external key. Echoed back in the response. Non-vellum channels (Telegram, WhatsApp) use this to scope to a logical channel thread; vellum-web clients can omit it and rely on the assistant-minted `id`.",
434
+ ),
386
435
  conversationType: z
387
436
  .literal("standard")
388
437
  .optional()
389
438
  .describe("Only standard conversations are created by this endpoint"),
390
439
  }),
391
440
  responseBody: z.object({
392
- id: z.string(),
393
- conversationKey: z.string(),
441
+ id: z
442
+ .string()
443
+ .describe(
444
+ "Assistant-minted internal conversation id. The authoritative identifier for the conversation.",
445
+ ),
446
+ conversationKey: z
447
+ .string()
448
+ .describe(
449
+ "Echo of the optional external key supplied by the client.",
450
+ ),
394
451
  conversationType: z.string(),
395
452
  created: z.boolean(),
396
453
  }),