@vellumai/assistant 0.11.2 → 0.11.3-staging.2

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 (720) hide show
  1. package/ARCHITECTURE.md +58 -3
  2. package/docs/trusted-contact-access.md +9 -5
  3. package/docs/vellum-doctor.md +195 -0
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  7. package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
  8. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
  9. package/node_modules/@vellumai/environments/package.json +2 -1
  10. package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
  11. package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
  12. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
  13. package/node_modules/@vellumai/environments/src/index.ts +17 -6
  14. package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
  15. package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
  16. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  19. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
  20. package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
  21. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
  22. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
  23. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
  24. package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
  25. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
  26. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
  27. package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  28. package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  29. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  30. package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
  31. package/openapi.yaml +589 -30
  32. package/package.json +1 -1
  33. package/src/__tests__/agent-image-optimize.test.ts +4 -4
  34. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
  35. package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
  36. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
  37. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  38. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  39. package/src/__tests__/answered-question-persistence.test.ts +240 -0
  40. package/src/__tests__/anthropic-provider.test.ts +165 -30
  41. package/src/__tests__/app-control-flow.test.ts +9 -8
  42. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  43. package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
  44. package/src/__tests__/attachments-store.test.ts +130 -68
  45. package/src/__tests__/attachments.test.ts +36 -36
  46. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  47. package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
  48. package/src/__tests__/canned-reply-release.test.ts +86 -0
  49. package/src/__tests__/channel-guardian.test.ts +59 -29
  50. package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
  51. package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
  52. package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
  53. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  54. package/src/__tests__/consult-deadline.test.ts +65 -0
  55. package/src/__tests__/conversation-agent-loop.test.ts +438 -2
  56. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
  57. package/src/__tests__/conversation-disk-view.test.ts +4 -4
  58. package/src/__tests__/conversation-error.test.ts +22 -3
  59. package/src/__tests__/conversation-fork-crud.test.ts +5 -1
  60. package/src/__tests__/conversation-fork-referential.test.ts +352 -0
  61. package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
  62. package/src/__tests__/conversation-group-tools.test.ts +32 -2
  63. package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
  64. package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
  65. package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
  66. package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
  67. package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
  68. package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
  69. package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
  70. package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
  71. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
  72. package/src/__tests__/conversation-queue.test.ts +433 -1
  73. package/src/__tests__/conversation-retry-route.test.ts +3 -1
  74. package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
  75. package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
  76. package/src/__tests__/conversation-store.test.ts +26 -10
  77. package/src/__tests__/conversation-summarize-route.test.ts +1 -1
  78. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
  79. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
  81. package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
  82. package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
  83. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
  84. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  85. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
  90. package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
  91. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
  92. package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
  93. package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
  94. package/src/__tests__/credential-prompt-route.test.ts +57 -7
  95. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  96. package/src/__tests__/cu-unified-flow.test.ts +89 -28
  97. package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
  98. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
  99. package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
  100. package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
  101. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  102. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  103. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  104. package/src/__tests__/disk-usage.test.ts +35 -20
  105. package/src/__tests__/document-sync-tags.test.ts +379 -0
  106. package/src/__tests__/document-update-default-surface.test.ts +28 -0
  107. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  108. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
  109. package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
  110. package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
  111. package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
  112. package/src/__tests__/file-list-tool.test.ts +12 -10
  113. package/src/__tests__/file-ops-service.test.ts +151 -44
  114. package/src/__tests__/file-read-container-boundary.test.ts +137 -0
  115. package/src/__tests__/file-read-tool.test.ts +21 -9
  116. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  117. package/src/__tests__/filesystem-tools.test.ts +82 -66
  118. package/src/__tests__/guardian-outbound-http.test.ts +8 -8
  119. package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
  120. package/src/__tests__/helpers/hub-clients.ts +42 -0
  121. package/src/__tests__/helpers/mock-conversation.ts +46 -0
  122. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
  123. package/src/__tests__/history-repair.test.ts +112 -12
  124. package/src/__tests__/host-bash-proxy.test.ts +10 -5
  125. package/src/__tests__/host-bash-routes.test.ts +67 -0
  126. package/src/__tests__/host-browser-proxy.test.ts +2 -2
  127. package/src/__tests__/host-cu-proxy.test.ts +3 -7
  128. package/src/__tests__/host-file-proxy.test.ts +3 -7
  129. package/src/__tests__/host-file-read-tool.test.ts +5 -1
  130. package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
  131. package/src/__tests__/http-conversation-lineage.test.ts +2 -5
  132. package/src/__tests__/http-user-message-parity.test.ts +44 -0
  133. package/src/__tests__/identity-routes.test.ts +13 -13
  134. package/src/__tests__/image-conversion.test.ts +29 -26
  135. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  136. package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
  137. package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
  138. package/src/__tests__/introduction-card-resolver.test.ts +6 -1
  139. package/src/__tests__/list-messages-attachments.test.ts +56 -32
  140. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  141. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  142. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  143. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  144. package/src/__tests__/list-messages-provider-error.test.ts +6 -6
  145. package/src/__tests__/list-messages-queued.test.ts +49 -6
  146. package/src/__tests__/list-messages-system-card.test.ts +4 -4
  147. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  148. package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
  149. package/src/__tests__/llm-usage-store.test.ts +55 -0
  150. package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
  151. package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
  152. package/src/__tests__/media-stream-server-integration.test.ts +36 -0
  153. package/src/__tests__/migration-export-http.test.ts +1 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  155. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  156. package/src/__tests__/migration-validate-http.test.ts +1 -1
  157. package/src/__tests__/mtime-cache.test.ts +65 -3
  158. package/src/__tests__/notification-platform-adapter.test.ts +104 -0
  159. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  160. package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
  161. package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
  162. package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
  163. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  164. package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
  165. package/src/__tests__/path-policy.test.ts +164 -1
  166. package/src/__tests__/persist-media-references.test.ts +2 -2
  167. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  168. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  169. package/src/__tests__/persona-resolver.test.ts +154 -0
  170. package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
  171. package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
  172. package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
  173. package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
  174. package/src/__tests__/profiler-routes.test.ts +13 -13
  175. package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
  176. package/src/__tests__/proxy-approval-callback.test.ts +3 -3
  177. package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
  178. package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
  179. package/src/__tests__/resolve-trust-class.test.ts +20 -0
  180. package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
  181. package/src/__tests__/run-due-schedules.test.ts +174 -0
  182. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  183. package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
  184. package/src/__tests__/schedule-routes.test.ts +730 -8
  185. package/src/__tests__/schedule-store.test.ts +540 -0
  186. package/src/__tests__/schedule-tools.test.ts +103 -0
  187. package/src/__tests__/scheduler-wake.test.ts +5 -0
  188. package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
  189. package/src/__tests__/secure-keys.test.ts +91 -0
  190. package/src/__tests__/server-history-render.test.ts +97 -7
  191. package/src/__tests__/size-guard.test.ts +8 -8
  192. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  193. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  194. package/src/__tests__/skills-install-staging.test.ts +15 -6
  195. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  196. package/src/__tests__/slack-inbound-verification.test.ts +4 -1
  197. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  198. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  199. package/src/__tests__/starter-task-flow.test.ts +5 -4
  200. package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
  201. package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
  202. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  203. package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
  204. package/src/__tests__/subagent-disposal.test.ts +10 -0
  205. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  206. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  207. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  208. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  209. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  210. package/src/__tests__/subagent-persistence.test.ts +141 -0
  211. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  212. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  213. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  214. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  215. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  216. package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
  217. package/src/__tests__/subagent-tools.test.ts +1901 -108
  218. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  219. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  220. package/src/__tests__/system-prompt.test.ts +82 -7
  221. package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
  222. package/src/__tests__/tool-result-spool.test.ts +74 -18
  223. package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
  224. package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
  225. package/src/__tests__/tools-audio-read.test.ts +10 -10
  226. package/src/__tests__/tools-get-route.test.ts +85 -12
  227. package/src/__tests__/tools-list-cli.test.ts +171 -0
  228. package/src/__tests__/top-level-renderer.test.ts +54 -1
  229. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
  230. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
  231. package/src/__tests__/turn-tail-chain.test.ts +135 -0
  232. package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
  233. package/src/__tests__/ui-visual-surface.test.ts +5 -4
  234. package/src/__tests__/ui-work-result-surface.test.ts +5 -4
  235. package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
  236. package/src/__tests__/usage-routes.test.ts +62 -0
  237. package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
  238. package/src/__tests__/visible-app-context.test.ts +20 -4
  239. package/src/__tests__/web-search-history.test.ts +96 -0
  240. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
  241. package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
  242. package/src/acp/failure-error.ts +3 -5
  243. package/src/agent/attachments.ts +26 -24
  244. package/src/agent/history-repair/history-repair.ts +27 -26
  245. package/src/agent/image-optimize.ts +6 -6
  246. package/src/agent/loop.ts +40 -22
  247. package/src/agent/message-types.ts +3 -3
  248. package/src/api/constants/document-tools.ts +55 -0
  249. package/src/api/events/question-answered.ts +53 -0
  250. package/src/api/events/tool-result.ts +7 -0
  251. package/src/api/index.ts +13 -0
  252. package/src/api/responses/conversation-message.ts +11 -0
  253. package/src/api/surfaces-oauth-connect.test.ts +96 -0
  254. package/src/api/surfaces.ts +36 -8
  255. package/src/approvals/guardian-channel-delivery.ts +83 -0
  256. package/src/approvals/guardian-expiry-notifier.ts +13 -11
  257. package/src/approvals/guardian-request-resolvers.ts +222 -135
  258. package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
  259. package/src/calls/media-stream-server.ts +9 -1
  260. package/src/calls/voice-session-bridge.ts +38 -0
  261. package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
  262. package/src/channels/config.ts +7 -2
  263. package/src/channels/gateway-verification-sessions.ts +7 -2
  264. package/src/channels/types.ts +7 -1
  265. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  266. package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
  267. package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
  268. package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
  269. package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
  270. package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
  271. package/src/cli/commands/__tests__/plugins.test.ts +692 -0
  272. package/src/cli/commands/__tests__/schedules.test.ts +136 -37
  273. package/src/cli/commands/conversations.ts +7 -3
  274. package/src/cli/commands/credentials.help.ts +7 -0
  275. package/src/cli/commands/inference-profiles.ts +9 -3
  276. package/src/cli/commands/inference.help.ts +16 -2
  277. package/src/cli/commands/mcp.help.ts +4 -2
  278. package/src/cli/commands/memory/memory-retrospective.ts +18 -0
  279. package/src/cli/commands/notifications.ts +3 -6
  280. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
  281. package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
  282. package/src/cli/commands/oauth/connect.test.ts +26 -1
  283. package/src/cli/commands/oauth/connect.ts +4 -1
  284. package/src/cli/commands/oauth/index.help.ts +3 -1
  285. package/src/cli/commands/oauth/providers.ts +3 -0
  286. package/src/cli/commands/plugins.help.ts +25 -2
  287. package/src/cli/commands/plugins.ts +289 -10
  288. package/src/cli/commands/schedules.help.ts +14 -12
  289. package/src/cli/commands/schedules.ts +19 -5
  290. package/src/cli/commands/tools.help.ts +4 -2
  291. package/src/cli/commands/tools.ts +38 -0
  292. package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
  293. package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
  294. package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
  295. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
  296. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
  297. package/src/cli/lib/install-from-github.ts +61 -0
  298. package/src/cli/lib/install-from-platform.ts +13 -2
  299. package/src/cli/lib/plugin-surfaces.ts +124 -4
  300. package/src/cli/lib/upgrade-plugin.ts +18 -0
  301. package/src/cli.ts +1 -1
  302. package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
  303. package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
  304. package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
  305. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  306. package/src/config/bundled-skills/AGENTS.md +1 -1
  307. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  308. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
  309. package/src/config/bundled-skills/schedule/SKILL.md +5 -1
  310. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  311. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  312. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
  313. package/src/config/bundled-skills/subagent/SKILL.md +53 -22
  314. package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
  315. package/src/config/bundled-skills/visualize/SKILL.md +1 -1
  316. package/src/config/default-profile-catalog.ts +6 -2
  317. package/src/config/feature-flag-registry.json +25 -17
  318. package/src/config/llm-resolver.ts +45 -15
  319. package/src/config/loader.ts +70 -1
  320. package/src/config/profile-tool-support.ts +110 -0
  321. package/src/config/sanitize-for-transfer.ts +11 -0
  322. package/src/config/schema.ts +4 -0
  323. package/src/config/schemas/__tests__/stt.test.ts +20 -5
  324. package/src/config/schemas/channels.ts +13 -0
  325. package/src/config/schemas/memory-retrospective.ts +25 -0
  326. package/src/config/schemas/plugin-updates.ts +55 -0
  327. package/src/config/schemas/services.ts +8 -4
  328. package/src/config/schemas/stt.ts +17 -5
  329. package/src/config/schemas/timeouts.ts +1 -1
  330. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
  331. package/src/contacts/guardian-delivery-reader.ts +29 -2
  332. package/src/context/compactor.ts +4 -4
  333. package/src/context/post-turn-tool-result-truncation.ts +32 -16
  334. package/src/context/strip-injections.ts +42 -0
  335. package/src/context/tool-result-spool.ts +32 -18
  336. package/src/credential-execution/ces-runtime.ts +3 -0
  337. package/src/credential-execution/client.ts +22 -1
  338. package/src/credential-execution/process-manager.test.ts +99 -0
  339. package/src/credential-execution/process-manager.ts +62 -16
  340. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  341. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
  342. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  343. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
  344. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
  345. package/src/daemon/channel-ui-capability.ts +4 -4
  346. package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
  347. package/src/daemon/conversation-agent-loop.ts +318 -148
  348. package/src/daemon/conversation-attachments.ts +1 -1
  349. package/src/daemon/conversation-error.ts +8 -1
  350. package/src/daemon/conversation-initial-prompt.ts +16 -38
  351. package/src/daemon/conversation-lifecycle.ts +154 -32
  352. package/src/daemon/conversation-messaging.ts +106 -43
  353. package/src/daemon/conversation-process.ts +131 -33
  354. package/src/daemon/conversation-queue-manager.ts +10 -0
  355. package/src/daemon/conversation-runtime-assembly.ts +9 -4
  356. package/src/daemon/conversation-store.ts +52 -3
  357. package/src/daemon/conversation-surface-state.ts +9 -0
  358. package/src/daemon/conversation-surfaces.ts +403 -210
  359. package/src/daemon/conversation-tool-setup.ts +56 -7
  360. package/src/daemon/conversation-turn-finalize.ts +134 -89
  361. package/src/daemon/conversation.ts +111 -27
  362. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  363. package/src/daemon/disk-pressure-guard.ts +3 -3
  364. package/src/daemon/doordash-steps.ts +5 -5
  365. package/src/daemon/external-plugins-bootstrap.ts +7 -1
  366. package/src/daemon/handlers/config-channels.ts +48 -5
  367. package/src/daemon/handlers/conversation-history.ts +1 -1
  368. package/src/daemon/handlers/conversations.ts +62 -17
  369. package/src/daemon/handlers/shared.ts +12 -0
  370. package/src/daemon/handlers/skills.ts +11 -1
  371. package/src/daemon/identity-helpers.ts +38 -10
  372. package/src/daemon/install-assistant-command.ts +322 -0
  373. package/src/daemon/lifecycle.ts +14 -3
  374. package/src/daemon/message-types/conversations.ts +6 -7
  375. package/src/daemon/message-types/sync.ts +1 -0
  376. package/src/daemon/persist-media-references.ts +23 -14
  377. package/src/daemon/process-message.ts +6 -6
  378. package/src/daemon/tool-setup-types.ts +19 -122
  379. package/src/daemon/tool-side-effects.ts +17 -94
  380. package/src/daemon/trust-context-types.ts +39 -0
  381. package/src/daemon/trust-context.ts +14 -6
  382. package/src/daemon/turn-tail-chain.ts +73 -0
  383. package/src/daemon/web-search-history.ts +47 -33
  384. package/src/heartbeat/heartbeat-service.ts +6 -6
  385. package/src/ipc/__tests__/socket-path.test.ts +21 -0
  386. package/src/ipc/assistant-server.ts +17 -10
  387. package/src/ipc/cli-client.ts +10 -1
  388. package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
  389. package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
  390. package/src/ipc/socket-cleanup.ts +9 -7
  391. package/src/ipc/socket-path.ts +4 -96
  392. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  393. package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
  394. package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
  395. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  396. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
  397. package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
  398. package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
  399. package/src/live-voice/__tests__/protocol.test.ts +52 -0
  400. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
  401. package/src/live-voice/live-voice-archive.ts +13 -13
  402. package/src/live-voice/live-voice-connection.ts +7 -1
  403. package/src/live-voice/live-voice-photo.ts +169 -0
  404. package/src/live-voice/live-voice-session.ts +108 -4
  405. package/src/live-voice/protocol.ts +89 -1
  406. package/src/mcp/client.ts +10 -0
  407. package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
  408. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
  409. package/src/messaging/providers/callback-routing.ts +1 -0
  410. package/src/messaging/providers/discord/api.ts +312 -0
  411. package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
  412. package/src/messaging/providers/discord/render.test.ts +204 -0
  413. package/src/messaging/providers/discord/render.ts +195 -0
  414. package/src/messaging/providers/discord/send.test.ts +179 -0
  415. package/src/messaging/providers/discord/send.ts +212 -0
  416. package/src/messaging/providers/discord/transport.ts +81 -0
  417. package/src/messaging/providers/index.ts +3 -1
  418. package/src/messaging/providers/retry-policy.test.ts +247 -0
  419. package/src/messaging/providers/retry-policy.ts +206 -0
  420. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  421. package/src/messaging/providers/slack/mention-source.ts +287 -0
  422. package/src/messaging/providers/telegram-bot/api.ts +47 -130
  423. package/src/messaging/providers/whatsapp/api.ts +47 -136
  424. package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
  425. package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
  426. package/src/monitoring/db-integrity-sample.ts +6 -1
  427. package/src/monitoring/plugin-auto-update.ts +359 -0
  428. package/src/monitoring/resource-sampler.ts +21 -5
  429. package/src/monitoring/worker.ts +13 -0
  430. package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
  431. package/src/notifications/__tests__/broadcaster.test.ts +37 -1
  432. package/src/notifications/__tests__/copy-composer.test.ts +165 -0
  433. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
  434. package/src/notifications/__tests__/notification-utils.test.ts +249 -0
  435. package/src/notifications/adapters/platform.ts +31 -2
  436. package/src/notifications/assistant-reply-producer.ts +79 -32
  437. package/src/notifications/broadcaster.ts +30 -10
  438. package/src/notifications/copy-composer.ts +69 -0
  439. package/src/notifications/emit-signal.ts +82 -15
  440. package/src/notifications/events-store.ts +10 -2
  441. package/src/notifications/home-feed-side-effect.ts +6 -3
  442. package/src/notifications/notification-utils.ts +173 -5
  443. package/src/notifications/signal.ts +12 -0
  444. package/src/oauth/AGENTS.md +4 -2
  445. package/src/oauth/byo-connection.ts +6 -1
  446. package/src/oauth/credential-token-resolver.ts +3 -10
  447. package/src/oauth/manual-token-connection.ts +29 -64
  448. package/src/oauth/manual-token-providers.ts +62 -0
  449. package/src/oauth/provider-serializer.ts +13 -0
  450. package/src/oauth/seed-providers.ts +62 -11
  451. package/src/onboarding/onboarding-events-store.ts +91 -1
  452. package/src/permissions/question-prompter.test.ts +4 -0
  453. package/src/permissions/question-prompter.ts +21 -4
  454. package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
  455. package/src/persistence/attachments-store.ts +15 -15
  456. package/src/persistence/conversation-attention-store.ts +30 -10
  457. package/src/persistence/conversation-bootstrap.ts +17 -0
  458. package/src/persistence/conversation-crud.ts +363 -97
  459. package/src/persistence/conversation-group-migration.ts +1 -1
  460. package/src/persistence/conversation-key-store.ts +38 -10
  461. package/src/persistence/conversation-lineage.ts +226 -0
  462. package/src/persistence/conversation-plugin-facade.ts +28 -3
  463. package/src/persistence/conversation-queries.ts +207 -33
  464. package/src/persistence/conversation-types.ts +107 -1
  465. package/src/persistence/jobs-store.ts +32 -8
  466. package/src/persistence/llm-usage-store.ts +22 -0
  467. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  468. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  469. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  470. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  471. package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
  472. package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
  473. package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
  474. package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
  475. package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
  476. package/src/persistence/schema/conversations.ts +32 -0
  477. package/src/persistence/schema/infrastructure.ts +3 -0
  478. package/src/persistence/steps.ts +30 -0
  479. package/src/persistence/subagent-store.ts +148 -6
  480. package/src/platform/managed-speech.test.ts +20 -0
  481. package/src/platform/managed-speech.ts +9 -0
  482. package/src/plugin-api/index.ts +8 -0
  483. package/src/plugin-api/webhook-url.ts +151 -0
  484. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
  485. package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
  486. package/src/plugins/collect-source-versions.ts +4 -27
  487. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  488. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  489. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  490. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  491. package/src/plugins/defaults/index.ts +1 -1
  492. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
  493. package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
  494. package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
  495. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
  496. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
  497. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
  498. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
  499. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
  500. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
  501. package/src/plugins/defaults/memory/job-handlers.ts +87 -5
  502. package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
  503. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  504. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
  505. package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
  506. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
  507. package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
  508. package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
  509. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  510. package/src/plugins/defaults/memory/v2/router.ts +8 -0
  511. package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
  512. package/src/plugins/external-plugin-loader.ts +17 -8
  513. package/src/plugins/installed-plugin-dirs.ts +101 -0
  514. package/src/plugins/mtime-cache.ts +34 -22
  515. package/src/plugins/types.ts +69 -8
  516. package/src/prompts/persona-resolver.ts +6 -2
  517. package/src/prompts/system-prompt.ts +72 -17
  518. package/src/providers/__tests__/inference.test.ts +40 -0
  519. package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
  520. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  521. package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
  522. package/src/providers/anthropic/client.ts +112 -95
  523. package/src/providers/connection-resolution.ts +35 -1
  524. package/src/providers/gemini/client.ts +5 -5
  525. package/src/providers/inference/adapter-factory.ts +16 -10
  526. package/src/providers/inference/auth.ts +16 -0
  527. package/src/providers/inference/connection-availability.ts +164 -12
  528. package/src/providers/inference/connections.ts +25 -1
  529. package/src/providers/media-resolve.ts +21 -11
  530. package/src/providers/model-catalog.ts +15 -0
  531. package/src/providers/openai/chat-completions-provider.ts +4 -4
  532. package/src/providers/openai/responses-provider.ts +12 -25
  533. package/src/providers/registry.ts +9 -4
  534. package/src/providers/retry.ts +25 -0
  535. package/src/providers/server-tool-pairing.ts +134 -0
  536. package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
  537. package/src/providers/speech-to-text/deepgram.ts +1 -0
  538. package/src/providers/speech-to-text/resolve.ts +80 -10
  539. package/src/providers/speech-to-text/vellum-managed.ts +7 -1
  540. package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
  541. package/src/providers/types.ts +26 -6
  542. package/src/providers/vellum-model-routing.ts +6 -7
  543. package/src/runtime/AGENTS.md +2 -0
  544. package/src/runtime/__tests__/agent-wake.test.ts +16 -16
  545. package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
  546. package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
  547. package/src/runtime/agent-wake.ts +63 -24
  548. package/src/runtime/assistant-event-hub.ts +87 -12
  549. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
  550. package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
  551. package/src/runtime/auth/same-actor.ts +56 -8
  552. package/src/runtime/auth/scopes.ts +12 -0
  553. package/src/runtime/auth/types.ts +2 -0
  554. package/src/runtime/background-job-runner.ts +5 -27
  555. package/src/runtime/channel-readiness-service.ts +59 -3
  556. package/src/runtime/channel-readiness-types.ts +18 -0
  557. package/src/runtime/desktop-presence.ts +69 -0
  558. package/src/runtime/http-server.ts +12 -0
  559. package/src/runtime/local-actor-identity.ts +11 -9
  560. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  561. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  562. package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
  563. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
  564. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
  565. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
  566. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
  567. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  568. package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
  569. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  570. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
  571. package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
  572. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
  573. package/src/runtime/routes/archive-utils.ts +16 -12
  574. package/src/runtime/routes/attachment-routes.ts +13 -6
  575. package/src/runtime/routes/canned-reply-release.ts +54 -0
  576. package/src/runtime/routes/channel-verification-routes.ts +2 -27
  577. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
  578. package/src/runtime/routes/client-routes.ts +114 -2
  579. package/src/runtime/routes/conversation-cli-routes.ts +10 -12
  580. package/src/runtime/routes/conversation-list-routes.ts +59 -10
  581. package/src/runtime/routes/conversation-management-routes.ts +47 -18
  582. package/src/runtime/routes/conversation-query-routes.ts +32 -53
  583. package/src/runtime/routes/conversation-routes.ts +360 -293
  584. package/src/runtime/routes/credential-prompt-routes.ts +23 -2
  585. package/src/runtime/routes/debug-routes.ts +4 -1
  586. package/src/runtime/routes/default-provider-routes.ts +7 -11
  587. package/src/runtime/routes/documents-routes.ts +44 -1
  588. package/src/runtime/routes/events-routes.ts +28 -1
  589. package/src/runtime/routes/host-app-control-routes.ts +2 -0
  590. package/src/runtime/routes/host-bash-routes.ts +2 -0
  591. package/src/runtime/routes/host-browser-routes.ts +2 -0
  592. package/src/runtime/routes/host-cu-routes.ts +2 -0
  593. package/src/runtime/routes/host-file-routes.ts +2 -0
  594. package/src/runtime/routes/host-transfer-routes.ts +4 -0
  595. package/src/runtime/routes/identity-routes.ts +6 -6
  596. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  597. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
  598. package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
  599. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
  600. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
  601. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
  602. package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
  603. package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
  604. package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
  605. package/src/runtime/routes/inference-profiles-routes.ts +152 -73
  606. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
  607. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  608. package/src/runtime/routes/log-export-routes.ts +1 -1
  609. package/src/runtime/routes/notification-routes.ts +0 -14
  610. package/src/runtime/routes/oauth-providers.ts +1 -0
  611. package/src/runtime/routes/plugins-routes.ts +106 -1
  612. package/src/runtime/routes/profiler-routes.ts +4 -2
  613. package/src/runtime/routes/question-routes.ts +28 -10
  614. package/src/runtime/routes/retrospective-routes.ts +9 -3
  615. package/src/runtime/routes/schedule-routes.ts +210 -12
  616. package/src/runtime/routes/secret-routes.ts +40 -23
  617. package/src/runtime/routes/settings-routes.ts +41 -13
  618. package/src/runtime/routes/skills-routes.ts +79 -0
  619. package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
  620. package/src/runtime/routes/wake-conversation-routes.ts +23 -0
  621. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  622. package/src/runtime/services/conversation-serializer.ts +24 -9
  623. package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
  624. package/src/runtime/sync/resource-sync-events.ts +79 -1
  625. package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
  626. package/src/runtime/sync/worker-daemon-notify.ts +44 -6
  627. package/src/runtime/verification-outbound-actions.ts +250 -222
  628. package/src/runtime/verification-templates.ts +41 -30
  629. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
  630. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
  631. package/src/schedule/inference-profile.ts +64 -3
  632. package/src/schedule/plugin-schedule-declarations.ts +518 -0
  633. package/src/schedule/plugin-schedule-reconciler.ts +605 -0
  634. package/src/schedule/plugin-schedules-gate.ts +23 -0
  635. package/src/schedule/schedule-store.ts +520 -26
  636. package/src/schedule/scheduler.ts +38 -0
  637. package/src/security/credential-backend.ts +51 -4
  638. package/src/security/encrypted-store.ts +64 -42
  639. package/src/security/secure-keys.ts +55 -7
  640. package/src/skills/catalog-install.ts +20 -7
  641. package/src/skills/inline-command-runner.ts +2 -7
  642. package/src/skills/skill-history.test.ts +269 -0
  643. package/src/skills/skill-history.ts +250 -0
  644. package/src/skills/skillssh-registry.ts +1 -1
  645. package/src/stt/daemon-batch-transcriber.ts +8 -6
  646. package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
  647. package/src/subagent/consult-prompt.ts +3 -1
  648. package/src/subagent/consult-transcript.ts +1 -1
  649. package/src/subagent/manager.ts +304 -44
  650. package/src/subagent/progress-events.ts +35 -0
  651. package/src/subagent/role-resolution.ts +88 -0
  652. package/src/subagent/types.ts +302 -67
  653. package/src/subagent/validate-allowlists.ts +3 -4
  654. package/src/telegram/__tests__/webhook-health.test.ts +73 -1
  655. package/src/telegram/webhook-health.ts +101 -3
  656. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  657. package/src/telemetry/activation-funnel.ts +6 -1
  658. package/src/telemetry/live-voice-funnel.ts +75 -0
  659. package/src/telemetry/telemetry-event-sources.ts +6 -0
  660. package/src/telemetry/telemetry-wire-source.json +1 -1
  661. package/src/telemetry/telemetry-wire.generated.ts +2 -0
  662. package/src/telemetry/types.ts +23 -4
  663. package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
  664. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  665. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  666. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  667. package/src/tools/browser/browser-execution.ts +1 -1
  668. package/src/tools/calls/call-start.ts +8 -5
  669. package/src/tools/conversation-groups/move_to_group.ts +10 -12
  670. package/src/tools/document/document-tool.ts +11 -4
  671. package/src/tools/execution-timeout.ts +9 -2
  672. package/src/tools/executor.ts +7 -6
  673. package/src/tools/filesystem/edit.ts +1 -1
  674. package/src/tools/filesystem/list.ts +1 -1
  675. package/src/tools/filesystem/read.ts +7 -13
  676. package/src/tools/filesystem/search.ts +23 -21
  677. package/src/tools/filesystem/write.ts +4 -1
  678. package/src/tools/host-filesystem/edit.ts +7 -2
  679. package/src/tools/host-filesystem/read.ts +21 -8
  680. package/src/tools/host-filesystem/write.ts +10 -2
  681. package/src/tools/host-terminal/host-shell.ts +2 -2
  682. package/src/tools/mcp/mcp-tool-factory.ts +25 -1
  683. package/src/tools/permission-checker.ts +8 -3
  684. package/src/tools/schedule/delete.ts +13 -1
  685. package/src/tools/schedule/list.ts +14 -3
  686. package/src/tools/schedule/update.ts +56 -33
  687. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  688. package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
  689. package/src/tools/shared/filesystem/image-read.ts +12 -12
  690. package/src/tools/shared/filesystem/path-policy.ts +70 -5
  691. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  692. package/src/tools/shared/input-misuse.ts +72 -0
  693. package/src/tools/skills/scaffold-managed.ts +82 -0
  694. package/src/tools/skills/skill-tool-factory.ts +14 -1
  695. package/src/tools/subagent/consult-deadline.ts +12 -7
  696. package/src/tools/subagent/message.ts +3 -1
  697. package/src/tools/subagent/read.ts +66 -4
  698. package/src/tools/subagent/spawn.ts +500 -78
  699. package/src/tools/tool-approval-handler.ts +45 -4
  700. package/src/tools/types.ts +22 -3
  701. package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
  702. package/src/tools/ui-surface/visual-validation.ts +2 -0
  703. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  704. package/src/usage/subagent-attribution.ts +108 -0
  705. package/src/util/__tests__/sqlite-retry.test.ts +112 -0
  706. package/src/util/abort-reasons.ts +16 -0
  707. package/src/util/ansi.ts +44 -0
  708. package/src/util/disk-usage.ts +17 -13
  709. package/src/util/image-conversion.ts +20 -13
  710. package/src/util/schedule-source-key.ts +23 -0
  711. package/src/util/worker-process.ts +7 -1
  712. package/src/workspace/git-service.ts +33 -9
  713. package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
  714. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
  715. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
  716. package/src/workspace/migrations/registry.ts +4 -0
  717. package/src/workspace/top-level-renderer.ts +15 -2
  718. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
  719. package/src/daemon/install-symlink.ts +0 -207
  720. package/src/notifications/deferred-emit.ts +0 -147
@@ -35,8 +35,6 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
35
35
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
36
36
  import {
37
37
  cancelOutbound,
38
- deliverVerificationEmail,
39
- deliverVerificationSlack,
40
38
  normalizeTelegramDestination,
41
39
  resendOutbound,
42
40
  startOutbound,
@@ -152,16 +150,6 @@ export async function handleCreateVerificationSession({
152
150
  verificationRateLimiter.recordFailure(rateLimitKey);
153
151
  }
154
152
 
155
- // Dispatch delivery from the daemon process (not sandboxed).
156
- if (result._pendingSlackDm) {
157
- const { userId, text, assistantId: aid } = result._pendingSlackDm;
158
- deliverVerificationSlack(userId, text, aid);
159
- }
160
- if (result._pendingEmail) {
161
- const { to, text, subject, assistantId: aid } = result._pendingEmail;
162
- deliverVerificationEmail(to, text, subject, aid);
163
- }
164
-
165
153
  if (!result.success) {
166
154
  if (result.error === "rate_limited") {
167
155
  throw new TooManyRequestsError(
@@ -174,9 +162,7 @@ export async function handleCreateVerificationSession({
174
162
  );
175
163
  }
176
164
 
177
- // Strip internal fields from the response
178
- const { _pendingSlackDm: _, _pendingEmail: __, ...publicResult } = result;
179
- return publicResult;
165
+ return result;
180
166
  }
181
167
 
182
168
  // Inbound challenge path
@@ -222,16 +208,6 @@ export async function handleResendVerificationSession({
222
208
 
223
209
  const result = await resendOutbound({ channel, originConversationId });
224
210
 
225
- // Dispatch delivery from the daemon process (not sandboxed).
226
- if (result._pendingSlackDm) {
227
- const { userId, text, assistantId: aid } = result._pendingSlackDm;
228
- deliverVerificationSlack(userId, text, aid);
229
- }
230
- if (result._pendingEmail) {
231
- const { to, text, subject, assistantId: aid } = result._pendingEmail;
232
- deliverVerificationEmail(to, text, subject, aid);
233
- }
234
-
235
211
  if (!result.success) {
236
212
  if (result.error === "rate_limited") {
237
213
  throw new TooManyRequestsError(
@@ -243,8 +219,7 @@ export async function handleResendVerificationSession({
243
219
  );
244
220
  }
245
221
 
246
- const { _pendingSlackDm: _, _pendingEmail: __, ...publicResult } = result;
247
- return publicResult;
222
+ return result;
248
223
  }
249
224
 
250
225
  /**
@@ -159,8 +159,13 @@ async function handleExchange(args: RouteHandlerArgs) {
159
159
 
160
160
  const existing = getConnection(db, CONNECTION_NAME);
161
161
  if (existing) {
162
+ // Stamp the provider with the auth: this row is the subscription
163
+ // connection by name, and dispatch derives auth from the provider for
164
+ // managed rows, so a claiming row with e.g. provider "vellum" would
165
+ // otherwise strand the fresh token behind derived platform auth.
162
166
  const updateResult = updateConnection(db, CONNECTION_NAME, {
163
167
  auth: authInput,
168
+ provider: "openai",
164
169
  });
165
170
  if (!updateResult.ok) {
166
171
  log.error(
@@ -10,15 +10,33 @@ import { z } from "zod";
10
10
  import type { HostProxyCapability } from "../../channels/types.js";
11
11
  import { isHttpAuthDisabled } from "../../config/env.js";
12
12
  import { datesToISO } from "../../util/json.js";
13
- import { assistantEventHub } from "../assistant-event-hub.js";
13
+ import { getLogger } from "../../util/logger.js";
14
+ import {
15
+ assistantEventHub,
16
+ DESKTOP_PRESENCE_STATES,
17
+ } from "../assistant-event-hub.js";
14
18
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
15
19
  import {
16
20
  DEFAULT_HEARTBEAT_INTERVAL_MS,
17
21
  isClientDegraded,
18
22
  } from "../client-health.js";
19
- import { NotFoundError } from "./errors.js";
23
+ import { BadRequestError, NotFoundError } from "./errors.js";
24
+ import { parseBody } from "./parse-body.js";
20
25
  import type { RouteDefinition } from "./types.js";
21
26
 
27
+ const log = getLogger("client-routes");
28
+
29
+ /**
30
+ * Body of `POST /v1/clients/presence`, declared as the route's `requestBody`
31
+ * and parsed by the handler, so the OpenAPI contract and the runtime check are
32
+ * one schema rather than two hand-kept copies.
33
+ */
34
+ const PresenceBodySchema = z.object({
35
+ state: z
36
+ .enum(DESKTOP_PRESENCE_STATES)
37
+ .describe("Reported desktop presence state."),
38
+ });
39
+
22
40
  export const ROUTES: RouteDefinition[] = [
23
41
  {
24
42
  operationId: "list_clients",
@@ -116,4 +134,98 @@ export const ROUTES: RouteDefinition[] = [
116
134
  return { disconnected: count };
117
135
  },
118
136
  },
137
+ {
138
+ operationId: "report_client_presence",
139
+ endpoint: "clients/presence",
140
+ method: "POST",
141
+ policy: {
142
+ requiredScopes: ["settings.write"],
143
+ allowedPrincipalTypes: ACTOR_PRINCIPALS,
144
+ },
145
+ summary: "Report desktop presence",
146
+ description:
147
+ "Record the desktop presence state reported by the client identified by the X-Vellum-Client-Id header.",
148
+ tags: ["clients"],
149
+ requestBody: PresenceBodySchema,
150
+ responseBody: z.object({
151
+ recorded: z
152
+ .boolean()
153
+ .describe("Whether a connected client matched the reporting clientId."),
154
+ }),
155
+ handler: ({ body, headers }) => {
156
+ const clientId = headers?.["x-vellum-client-id"]?.trim();
157
+ if (!clientId) {
158
+ throw new BadRequestError(
159
+ "x-vellum-client-id header is required to report presence.",
160
+ );
161
+ }
162
+ const { state } = parseBody(PresenceBodySchema, body);
163
+
164
+ // Resolving the client first separates "nobody is listening" from
165
+ // "somebody else owns this", so only the second one is worth a warn.
166
+ const client = assistantEventHub.getClientById(clientId);
167
+ if (!client) {
168
+ // Debug, not warn: a report racing an SSE reconnect matches nothing,
169
+ // and a reconnect storm would otherwise emit a warn per client every
170
+ // 30 seconds for a benign race. Not a 404 either, for the same reason.
171
+ log.debug(
172
+ { op: "report_client_presence", state },
173
+ "Presence report matched no connected client",
174
+ );
175
+ return { recorded: false };
176
+ }
177
+
178
+ // Only the actor that opened the target client's SSE stream may report
179
+ // its presence, so a caller who learns another user's clientId cannot
180
+ // spoof that desktop. Clients with no stored `actorPrincipalId` (legacy
181
+ // SSE subscribers, service-gateway tokens) never match: fail-closed, the
182
+ // same posture as the listing filter above. Dev-bypass mode
183
+ // (DISABLE_HTTP_AUTH=true) skips the check for platform-managed
184
+ // deployments where the platform handles auth.
185
+ if (!isHttpAuthDisabled()) {
186
+ const callerPrincipalId = headers?.["x-vellum-actor-principal-id"];
187
+ const ownerPrincipalId = client.actorPrincipalId;
188
+ if (
189
+ ownerPrincipalId === undefined ||
190
+ ownerPrincipalId !== callerPrincipalId
191
+ ) {
192
+ // Warn, not debug: the client is connected, so a mismatch means the
193
+ // gateway stopped forwarding the actor header, a scope profile
194
+ // shifted, or a caller is probing someone else's client. Without this
195
+ // line presence gating dies silently and every suppressed push
196
+ // quietly resumes. Client and principal ids stay out of the entry so
197
+ // the log cannot be used to enumerate them.
198
+ log.warn(
199
+ {
200
+ op: "report_client_presence",
201
+ hasStoredOwner: ownerPrincipalId !== undefined,
202
+ hasCallerPrincipal: callerPrincipalId !== undefined,
203
+ targetInterfaceId: client.interfaceId,
204
+ },
205
+ "Rejecting presence report from a caller that does not own the client",
206
+ );
207
+ // Answering like "no match" keeps the reply from probing client ids.
208
+ return { recorded: false };
209
+ }
210
+ }
211
+
212
+ // The lookup ran in this same synchronous handler, so the write lands on
213
+ // the entry it resolved.
214
+ assistantEventHub.setClientPresence(clientId, state);
215
+
216
+ // Records which state a client actually reported. Nothing else persists
217
+ // it, so this is the only evidence for why a machine did or did not
218
+ // count as attended. Only `macos` clients gate pushes, hence the
219
+ // interface id.
220
+ log.debug(
221
+ {
222
+ op: "report_client_presence",
223
+ state,
224
+ interfaceId: client.interfaceId,
225
+ },
226
+ "Recorded desktop presence",
227
+ );
228
+ return { recorded: true };
229
+ },
230
+ },
119
231
  ];
@@ -44,12 +44,11 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
44
44
  // user sees archived rows alongside live ones in the picker.
45
45
  const includeArchived = (body.includeArchived as boolean) ?? false;
46
46
 
47
- const rows = listConversations(
47
+ const rows = listConversations({
48
48
  limit,
49
- "standard",
50
- 0,
51
- includeArchived ? "all" : "active",
52
- );
49
+ conversationType: "standard",
50
+ archiveStatus: includeArchived ? "all" : "active",
51
+ });
53
52
  return {
54
53
  conversations: rows.map((c) => ({
55
54
  id: c.id,
@@ -140,7 +139,7 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
140
139
  let conversationId = body.conversationId as string | undefined;
141
140
 
142
141
  if (!conversationId) {
143
- const all = listConversations(1);
142
+ const all = listConversations({ limit: 1 });
144
143
  if (all.length === 0) {
145
144
  throw new NotFoundError("No conversations found");
146
145
  }
@@ -151,12 +150,11 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
151
150
  // behavior of letting `vellum export <prefix>` resolve an archived row.
152
151
  let conversation = getConversation(conversationId);
153
152
  if (!conversation) {
154
- const all = listConversations(
155
- Number.MAX_SAFE_INTEGER,
156
- "standard",
157
- 0,
158
- "all",
159
- );
153
+ const all = listConversations({
154
+ limit: Number.MAX_SAFE_INTEGER,
155
+ conversationType: "standard",
156
+ archiveStatus: "all",
157
+ });
160
158
  const match = all.find((c) => c.id.startsWith(conversationId!));
161
159
  if (match) {
162
160
  conversation = match;
@@ -2,6 +2,7 @@
2
2
  * Route handlers for conversation listing, detail, and seen/unread state.
3
3
  *
4
4
  * GET /v1/conversations — paginated conversation list
5
+ * GET /v1/conversations/unread-count - count of unseen foreground conversations
5
6
  * POST /v1/conversations/seen — record a seen signal (single)
6
7
  * POST /v1/conversations/seen/bulk — record seen signals (batch)
7
8
  * POST /v1/conversations/unread — mark a conversation unread
@@ -26,7 +27,9 @@ import {
26
27
  } from "../../persistence/conversation-crud.js";
27
28
  import { resolveConversationId } from "../../persistence/conversation-key-store.js";
28
29
  import {
30
+ type ConversationListFilter,
29
31
  countConversations,
32
+ countUnreadConversations,
30
33
  listConversations,
31
34
  listPinnedConversations,
32
35
  } from "../../persistence/conversation-queries.js";
@@ -101,6 +104,13 @@ export const conversationSummarySchema = z.object({
101
104
  displayOrder: z.number().nullable().optional(),
102
105
  groupId: z.string().nullable(),
103
106
  forkParent: forkParentSchema.optional(),
107
+ /**
108
+ * Present only on a referential fork whose parent conversation was deleted.
109
+ * The fork keeps the messages it owns and the lineage read truncates at the
110
+ * missing parent, so it renders as a conversation that starts mid-thought.
111
+ * Clients surface this so that reads as a deletion rather than as data loss.
112
+ */
113
+ historyOrphaned: z.literal(true).optional(),
104
114
  archivedAt: z.number().optional(),
105
115
  /**
106
116
  * Epoch-ms timestamp set when a background/scheduled conversation was
@@ -141,6 +151,10 @@ const conversationDetailResponseSchema = z.object({
141
151
  conversation: conversationSummarySchema,
142
152
  });
143
153
 
154
+ const unreadConversationCountResponseSchema = z.object({
155
+ count: z.number(),
156
+ });
157
+
144
158
  // ---------------------------------------------------------------------------
145
159
  // Helpers
146
160
  // ---------------------------------------------------------------------------
@@ -194,18 +208,19 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
194
208
  ? queryParams.originChannel
195
209
  : undefined;
196
210
 
197
- let rows = listConversations(
198
- limit,
199
- conversationType,
200
- offset,
201
- archiveStatus,
202
- originChannel,
203
- );
204
- const totalCount = countConversations(
211
+ const groupId =
212
+ queryParams.groupId !== undefined && queryParams.groupId !== ""
213
+ ? queryParams.groupId
214
+ : undefined;
215
+
216
+ const filter: ConversationListFilter = {
205
217
  conversationType,
206
218
  archiveStatus,
207
219
  originChannel,
208
- );
220
+ groupId,
221
+ };
222
+ let rows = listConversations({ ...filter, limit, offset });
223
+ const totalCount = countConversations(filter);
209
224
 
210
225
  // On the first page, ensure all pinned conversations are included
211
226
  // even if they fall outside the paginated window. Pinned injection is
@@ -213,11 +228,19 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
213
228
  // rows in archive-time order, not pin order. Also skipped for
214
229
  // channel-scoped queries — those return only items matching the
215
230
  // requested origin channel; pinned items render in their own section.
231
+ //
232
+ // Skipped for group-scoped queries for the same reason: a caller asking
233
+ // for one group gets that group, and a client that fetches the Pinned
234
+ // section via `groupId=system:pinned` has no use for rows appended to
235
+ // some other group's page. This is the compatibility shim for clients
236
+ // that still read Pinned out of the unfiltered list; it goes away once
237
+ // every section fetches its own group.
216
238
  if (
217
239
  offset === 0 &&
218
240
  conversationType === "standard" &&
219
241
  archiveStatus === "active" &&
220
- originChannel === undefined
242
+ originChannel === undefined &&
243
+ groupId === undefined
221
244
  ) {
222
245
  const pinned = listPinnedConversations(archiveStatus);
223
246
  const seen = new Set(rows.map((c) => c.id));
@@ -265,6 +288,10 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
265
288
  return response;
266
289
  }
267
290
 
291
+ function handleGetUnreadConversationCount() {
292
+ return { count: countUnreadConversations() };
293
+ }
294
+
268
295
  function handleRecordSeen({ body = {}, headers }: RouteHandlerArgs) {
269
296
  const rawConversationId = body.conversationId as string | undefined;
270
297
  if (!rawConversationId) {
@@ -450,10 +477,32 @@ export const ROUTES: RouteDefinition[] = [
450
477
  enum: [...CHANNEL_IDS],
451
478
  },
452
479
  },
480
+ {
481
+ name: "groupId",
482
+ type: "string",
483
+ required: false,
484
+ description:
485
+ 'Filter to a single group, so each sidebar section can load independently of the paginated list. Pass "system:all" for conversations in no group, "system:pinned" for the Pinned section, or a custom group id. A group-scoped request is ordered by the user\'s arrangement (display order, then recency) and never has pinned rows appended to it. Omit to span every group.',
486
+ },
453
487
  ],
454
488
  responseBody: listConversationsResponseSchema,
455
489
  handler: handleListConversations,
456
490
  },
491
+ {
492
+ operationId: "getUnreadConversationCount",
493
+ endpoint: "conversations/unread-count",
494
+ method: "GET",
495
+ policy: {
496
+ requiredScopes: ["chat.read"],
497
+ allowedPrincipalTypes: ACTOR_PRINCIPALS,
498
+ },
499
+ summary: "Unread conversation count",
500
+ description:
501
+ "Count of foreground conversations whose latest assistant message is unseen. Matches the sidebar's unread indicators: archived rows and non-surfaced background/scheduled rows are excluded.",
502
+ tags: ["conversations"],
503
+ responseBody: unreadConversationCountResponseSchema,
504
+ handler: handleGetUnreadConversationCount,
505
+ },
457
506
  {
458
507
  operationId: "recordConversationSeen",
459
508
  endpoint: "conversations/seen",
@@ -46,7 +46,7 @@ import { normalizeConversationType } from "../../daemon/message-types/shared.js"
46
46
  import { stripConversationIds } from "../../home/feed-writer.js";
47
47
  import {
48
48
  archiveConversation,
49
- batchSetDisplayOrders,
49
+ batchSetConversationPlacement,
50
50
  countConversationsByScheduleJobId,
51
51
  deleteConversation,
52
52
  forkConversation as forkConversationInStore,
@@ -63,9 +63,10 @@ import {
63
63
  resolveConversationId,
64
64
  setConversationKeyIfAbsent,
65
65
  } from "../../persistence/conversation-key-store.js";
66
+ import type { NonScheduledConversationType } from "../../persistence/conversation-types.js";
66
67
  import { enqueueMemoryJob } from "../../persistence/jobs-store.js";
67
68
  import { linkRequestLogsToMessage } from "../../persistence/llm-request-log-store.js";
68
- import { deleteSchedule } from "../../schedule/schedule-store.js";
69
+ import { deleteSchedule, getSchedule } from "../../schedule/schedule-store.js";
69
70
  import { UserError } from "../../util/errors.js";
70
71
  import { safeParseRecord } from "../../util/json.js";
71
72
  import { getLogger } from "../../util/logger.js";
@@ -100,6 +101,12 @@ const log = getLogger("conversation-management-routes");
100
101
  // Helpers
101
102
  // ---------------------------------------------------------------------------
102
103
 
104
+ /** Conversation types this endpoint may mint. */
105
+ const createConversationTypeSchema = z.enum([
106
+ "standard",
107
+ "background",
108
+ ] as const satisfies readonly NonScheduledConversationType[]);
109
+
103
110
  function resolveOrThrow(rawId: string): string {
104
111
  const id = resolveConversationId(rawId);
105
112
  if (!id) {
@@ -111,11 +118,17 @@ function resolveOrThrow(rawId: string): string {
111
118
  async function cancelScheduleIfLast(conversationId: string): Promise<void> {
112
119
  const conv = getConversation(conversationId);
113
120
  if (
114
- conv?.scheduleJobId &&
115
- countConversationsByScheduleJobId(conv.scheduleJobId) <= 1
121
+ !conv?.scheduleJobId ||
122
+ countConversationsByScheduleJobId(conv.scheduleJobId) > 1
116
123
  ) {
117
- await deleteSchedule(conv.scheduleJobId);
124
+ return;
125
+ }
126
+ // A plugin-declared schedule outlives its run conversations: its lifecycle
127
+ // belongs to the reconciler, and `deleteSchedule` refuses sourced rows.
128
+ if (getSchedule(conv.scheduleJobId)?.sourceKey != null) {
129
+ return;
118
130
  }
131
+ await deleteSchedule(conv.scheduleJobId);
119
132
  }
120
133
 
121
134
  // ---------------------------------------------------------------------------
@@ -126,14 +139,26 @@ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
126
139
  const conversationKey =
127
140
  (body.conversationKey as string | undefined) ?? crypto.randomUUID();
128
141
  // The shared route adapter does not runtime-validate the body against the
129
- // Zod requestBody (it's codegen-only), so guard the type before trimming
130
- // a malformed `{ title: 123 }` would otherwise throw on `.trim()` and 500.
142
+ // Zod requestBody (it's codegen-only), so guard the types here: a malformed
143
+ // `{ title: 123 }` would otherwise throw on `.trim()` and 500, and an
144
+ // unsupported conversationType would reach the store unchecked.
145
+ // `.nullish()`: an explicit JSON `null` is how serializers spell an absent
146
+ // optional, so it means the same thing as omitting the key.
147
+ const requestedType = createConversationTypeSchema
148
+ .nullish()
149
+ .safeParse(body.conversationType);
150
+ if (!requestedType.success) {
151
+ throw new BadRequestError(
152
+ `conversationType must be one of ${createConversationTypeSchema.options.join(", ")}`,
153
+ );
154
+ }
131
155
  if (body.title !== undefined && typeof body.title !== "string") {
132
156
  throw new BadRequestError("title must be a string");
133
157
  }
134
158
  const customTitle = body.title?.trim() || undefined;
159
+ const conversationType = requestedType.data ?? "standard";
135
160
  const result = getOrCreateConversation(conversationKey, {
136
- conversationType: "standard",
161
+ conversationType,
137
162
  });
138
163
  if (result.created) {
139
164
  // A caller-supplied title is user-set: persist it with isAutoTitle = 0 so
@@ -151,10 +176,14 @@ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
151
176
  headers?.["x-vellum-client-id"]?.trim() || undefined,
152
177
  );
153
178
  }
179
+ // On a conversationKey hit the row already exists, so the type it carries
180
+ // can differ from the requested one.
181
+ const storedType = normalizeConversationType(result.conversationType);
154
182
  log.info(
155
183
  {
156
184
  conversationId: result.conversationId,
157
185
  conversationKey,
186
+ conversationType: storedType,
158
187
  created: result.created,
159
188
  },
160
189
  "Created conversation via POST",
@@ -162,7 +191,7 @@ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
162
191
  return {
163
192
  id: result.conversationId,
164
193
  conversationKey,
165
- conversationType: normalizeConversationType(result.conversationType),
194
+ conversationType: storedType,
166
195
  created: result.created,
167
196
  };
168
197
  }
@@ -816,7 +845,6 @@ function handleReorderConversations({ body = {}, headers }: RouteHandlerArgs) {
816
845
  const updates = body.updates as
817
846
  | Array<{
818
847
  conversationId: string;
819
- displayOrder?: number;
820
848
  isPinned?: boolean;
821
849
  groupId?: string | null;
822
850
  }>
@@ -824,10 +852,9 @@ function handleReorderConversations({ body = {}, headers }: RouteHandlerArgs) {
824
852
  if (!Array.isArray(updates)) {
825
853
  throw new BadRequestError("Missing updates array");
826
854
  }
827
- batchSetDisplayOrders(
855
+ batchSetConversationPlacement(
828
856
  updates.map((u) => ({
829
857
  id: u.conversationId,
830
- displayOrder: u.displayOrder ?? null,
831
858
  isPinned: u.isPinned,
832
859
  groupId: u.groupId,
833
860
  })),
@@ -863,10 +890,11 @@ export const ROUTES: RouteDefinition[] = [
863
890
  .describe(
864
891
  "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`.",
865
892
  ),
866
- conversationType: z
867
- .literal("standard")
893
+ conversationType: createConversationTypeSchema
868
894
  .optional()
869
- .describe("Only standard conversations are created by this endpoint"),
895
+ .describe(
896
+ 'Conversation type for the new row. "background" keeps it out of the foreground list and the sidebar\'s Recents grouping, used by internal side-channel flows (onboarding research, persona/identity rewrites) that mint a throwaway thread the user should never see. "scheduled" is not accepted here; scheduled rows are owned by the schedule pipeline.',
897
+ ),
870
898
  title: z
871
899
  .string()
872
900
  .optional()
@@ -1274,14 +1302,15 @@ export const ROUTES: RouteDefinition[] = [
1274
1302
  requiredScopes: ["chat.write"],
1275
1303
  allowedPrincipalTypes: ACTOR_PRINCIPALS,
1276
1304
  },
1277
- summary: "Reorder conversations",
1278
- description: "Batch-update display order and pin state for conversations.",
1305
+ summary: "Move conversations between sections",
1306
+ description:
1307
+ "Batch-update which group holds each conversation, and its pin state. " +
1308
+ "Lists are ordered by recency, so this sets placement, not order.",
1279
1309
  tags: ["conversations"],
1280
1310
  requestBody: z.object({
1281
1311
  updates: z.array(
1282
1312
  z.object({
1283
1313
  conversationId: z.string(),
1284
- displayOrder: z.number().optional(),
1285
1314
  isPinned: z.boolean().optional(),
1286
1315
  groupId: z.string().nullable().optional(),
1287
1316
  }),