@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
@@ -709,7 +709,7 @@ describe("HostTransferProxy — targetClientId", () => {
709
709
  );
710
710
 
711
711
  expect(result.isError).toBe(true);
712
- expect(result.content).toContain("does not match");
712
+ expect(result.content).toContain("signed in as a different user");
713
713
  expect(sentMessages).toHaveLength(0);
714
714
  });
715
715
 
@@ -738,7 +738,7 @@ describe("HostTransferProxy — targetClientId", () => {
738
738
  );
739
739
 
740
740
  expect(result.isError).toBe(true);
741
- expect(result.content).toContain("does not match");
741
+ expect(result.content).toContain("no authenticated actor");
742
742
  expect(sentMessages).toHaveLength(0);
743
743
  });
744
744
 
@@ -767,7 +767,9 @@ describe("HostTransferProxy — targetClientId", () => {
767
767
  );
768
768
 
769
769
  expect(result.isError).toBe(true);
770
- expect(result.content).toContain("does not match");
770
+ expect(result.content).toContain(
771
+ "registered without an authenticated user",
772
+ );
771
773
  expect(sentMessages).toHaveLength(0);
772
774
  });
773
775
 
@@ -863,7 +865,7 @@ describe("HostTransferProxy — targetClientId", () => {
863
865
  );
864
866
 
865
867
  expect(result.isError).toBe(true);
866
- expect(result.content).toContain("does not match");
868
+ expect(result.content).toContain("signed in as a different user");
867
869
  expect(sentMessages).toHaveLength(0);
868
870
  });
869
871
 
@@ -13,7 +13,7 @@ mock.module("../config/env.js", () => ({
13
13
  }));
14
14
 
15
15
  import {
16
- batchSetDisplayOrders,
16
+ batchSetConversationPlacement,
17
17
  createConversation,
18
18
  updateConversationTitle,
19
19
  } from "../persistence/conversation-crud.js";
@@ -100,9 +100,7 @@ describe("conversation lineage in HTTP reads", () => {
100
100
 
101
101
  test("GET /v1/conversations/:id includes pin metadata when present", async () => {
102
102
  const conversation = createConversation("Pinned conversation");
103
- batchSetDisplayOrders([
104
- { id: conversation.id, displayOrder: 7, isPinned: true },
105
- ]);
103
+ batchSetConversationPlacement([{ id: conversation.id, isPinned: true }]);
106
104
  await startServer();
107
105
 
108
106
  const response = await fetch(url(`/conversations/${conversation.id}`));
@@ -115,7 +113,6 @@ describe("conversation lineage in HTTP reads", () => {
115
113
  expect(body.conversation).toMatchObject({
116
114
  id: conversation.id,
117
115
  title: conversation.title ?? "Untitled",
118
- displayOrder: 7,
119
116
  isPinned: true,
120
117
  });
121
118
  });
@@ -650,6 +650,50 @@ describe("HTTP POST /v1/messages client metadata headers", () => {
650
650
  ];
651
651
  expect(persistOptions.metadata).toBeUndefined();
652
652
  });
653
+
654
+ // Persistence merges the row's `client.os` from two sources and only one of
655
+ // them is this row's own: the request. Threading the body's `clientOs` is
656
+ // what lets it tell a reported OS apart from the one a transport-less turn
657
+ // inherits off the live conversation.
658
+ test("threads the body clientOs as this row's own OS evidence", async () => {
659
+ const persistUserMessage = mock(
660
+ async (_options: { requestClientOs?: string }) => ({
661
+ id: "persisted-msg-id",
662
+ deduplicated: false,
663
+ }),
664
+ );
665
+ const runAgentLoop = mock(async () => undefined);
666
+ const conversation = makeConversation({ persistUserMessage, runAgentLoop });
667
+
668
+ const res = await sendMessage("hello", conversation, {
669
+ clientOs: "macos",
670
+ });
671
+
672
+ expect(res.status).toBe(202);
673
+ const [persistOptions] = persistUserMessage.mock.calls[0] as unknown as [
674
+ { requestClientOs?: string },
675
+ ];
676
+ expect(persistOptions.requestClientOs).toBe("macos");
677
+ });
678
+
679
+ test("omits the OS evidence when the body reports no clientOs", async () => {
680
+ const persistUserMessage = mock(
681
+ async (_options: { requestClientOs?: string }) => ({
682
+ id: "persisted-msg-id",
683
+ deduplicated: false,
684
+ }),
685
+ );
686
+ const runAgentLoop = mock(async () => undefined);
687
+ const conversation = makeConversation({ persistUserMessage, runAgentLoop });
688
+
689
+ const res = await sendMessage("hello", conversation);
690
+
691
+ expect(res.status).toBe(202);
692
+ const [persistOptions] = persistUserMessage.mock.calls[0] as unknown as [
693
+ { requestClientOs?: string },
694
+ ];
695
+ expect(persistOptions.requestClientOs).toBeUndefined();
696
+ });
653
697
  });
654
698
 
655
699
  // ============================================================================
@@ -151,7 +151,7 @@ afterEach(() => {
151
151
  describe("identity routes — health endpoint", () => {
152
152
  describe("backward compatibility (profiler disabled)", () => {
153
153
  test("/v1/health returns expected shape without profiler key when env vars are absent", async () => {
154
- const res = handleDetailedHealth();
154
+ const res = await handleDetailedHealth();
155
155
  expect(res.status).toBe(200);
156
156
 
157
157
  const body = (await res.json()) as Record<string, unknown>;
@@ -179,7 +179,7 @@ describe("identity routes — health endpoint", () => {
179
179
 
180
180
  test("/v1/healthz returns the same shape as /v1/health", async () => {
181
181
  // Both endpoints call handleDetailedHealth, so the shape must match
182
- const res = handleDetailedHealth();
182
+ const res = await handleDetailedHealth();
183
183
  const body = (await res.json()) as Record<string, unknown>;
184
184
 
185
185
  expect(body.status).toBe("healthy");
@@ -188,7 +188,7 @@ describe("identity routes — health endpoint", () => {
188
188
  });
189
189
 
190
190
  test("includes ces.connected=false when no CES client is registered", async () => {
191
- const res = handleDetailedHealth();
191
+ const res = await handleDetailedHealth();
192
192
  const body = (await res.json()) as Record<string, unknown>;
193
193
 
194
194
  expect(body.ces).toBeDefined();
@@ -197,7 +197,7 @@ describe("identity routes — health endpoint", () => {
197
197
 
198
198
  test("detailed health reports MIGRATING while DB migrations are running", async () => {
199
199
  setDbMigrating();
200
- const res = handleDetailedHealth();
200
+ const res = await handleDetailedHealth();
201
201
  expect(res.status).toBe(200);
202
202
 
203
203
  const body = (await res.json()) as Record<string, unknown>;
@@ -229,7 +229,7 @@ describe("identity routes — health endpoint", () => {
229
229
  close: () => {},
230
230
  } as unknown as import("../credential-execution/client.js").CesClient;
231
231
  setCesClient(mockClient);
232
- const res = handleDetailedHealth();
232
+ const res = await handleDetailedHealth();
233
233
  const body = (await res.json()) as Record<string, unknown>;
234
234
 
235
235
  expect(body.ces).toBeDefined();
@@ -242,7 +242,7 @@ describe("identity routes — health endpoint", () => {
242
242
  close: () => {},
243
243
  } as unknown as import("../credential-execution/client.js").CesClient;
244
244
  setCesClient(mockClient);
245
- const res = handleDetailedHealth();
245
+ const res = await handleDetailedHealth();
246
246
  const body = (await res.json()) as Record<string, unknown>;
247
247
 
248
248
  expect(body.ces).toBeDefined();
@@ -258,7 +258,7 @@ describe("identity routes — health endpoint", () => {
258
258
  });
259
259
  ensureProfilerRunDir("run-health-test-1");
260
260
 
261
- const res = handleDetailedHealth();
261
+ const res = await handleDetailedHealth();
262
262
  const body = (await res.json()) as Record<string, unknown>;
263
263
 
264
264
  expect(body.profiler).toBeDefined();
@@ -278,7 +278,7 @@ describe("identity routes — health endpoint", () => {
278
278
  });
279
279
  ensureProfilerRunDir("run-budget-test");
280
280
 
281
- const res = handleDetailedHealth();
281
+ const res = await handleDetailedHealth();
282
282
  const body = (await res.json()) as Record<string, unknown>;
283
283
  const profiler = body.profiler as Record<string, unknown>;
284
284
  const budget = profiler.budget as Record<string, unknown>;
@@ -301,7 +301,7 @@ describe("identity routes — health endpoint", () => {
301
301
  // Non-artifact file should not count
302
302
  writeArtifactFile("run-artifact-count", "log.txt", 512);
303
303
 
304
- const res = handleDetailedHealth();
304
+ const res = await handleDetailedHealth();
305
305
  const body = (await res.json()) as Record<string, unknown>;
306
306
  const profiler = body.profiler as Record<string, unknown>;
307
307
 
@@ -316,7 +316,7 @@ describe("identity routes — health endpoint", () => {
316
316
  // Write a file larger than the budget
317
317
  writeArtifactFile("run-over-budget", "big.cpuprofile", 5000);
318
318
 
319
- const res = handleDetailedHealth();
319
+ const res = await handleDetailedHealth();
320
320
  const body = (await res.json()) as Record<string, unknown>;
321
321
  const profiler = body.profiler as Record<string, unknown>;
322
322
  const budget = profiler.budget as Record<string, unknown>;
@@ -334,7 +334,7 @@ describe("identity routes — health endpoint", () => {
334
334
  });
335
335
  ensureProfilerRunDir("run-no-completed");
336
336
 
337
- const res = handleDetailedHealth();
337
+ const res = await handleDetailedHealth();
338
338
  const body = (await res.json()) as Record<string, unknown>;
339
339
  const profiler = body.profiler as Record<string, unknown>;
340
340
 
@@ -361,7 +361,7 @@ describe("identity routes — health endpoint", () => {
361
361
  writeArtifactFile(completedId, "profile.cpuprofile", 3072);
362
362
  writeArtifactFile(completedId, "summary.md", 256);
363
363
 
364
- const res = handleDetailedHealth();
364
+ const res = await handleDetailedHealth();
365
365
  const body = (await res.json()) as Record<string, unknown>;
366
366
  const profiler = body.profiler as Record<string, unknown>;
367
367
  const last = profiler.lastCompletedRun as Record<string, unknown>;
@@ -398,7 +398,7 @@ describe("identity routes — health endpoint", () => {
398
398
  });
399
399
  writeArtifactFile("newer-completed", "new.heapsnapshot", 1024);
400
400
 
401
- const res = handleDetailedHealth();
401
+ const res = await handleDetailedHealth();
402
402
  const body = (await res.json()) as Record<string, unknown>;
403
403
  const profiler = body.profiler as Record<string, unknown>;
404
404
  const last = profiler.lastCompletedRun as Record<string, unknown>;
@@ -132,17 +132,17 @@ describe("sniffImageMimeType", () => {
132
132
  });
133
133
 
134
134
  describe("normalizeImageBytes passthrough", () => {
135
- test("non-HEIF bytes pass through untouched", () => {
136
- const result = normalizeImageBytes("image/png", PNG_1PX_BYTES);
135
+ test("non-HEIF bytes pass through untouched", async () => {
136
+ const result = await normalizeImageBytes("image/png", PNG_1PX_BYTES);
137
137
  expect(result.converted).toBe(false);
138
138
  expect(result.mimeType).toBe("image/png");
139
139
  expect(result.bytes).toBe(PNG_1PX_BYTES);
140
140
  });
141
141
 
142
- test("HEIF header with undecodable payload passes through", () => {
142
+ test("HEIF header with undecodable payload passes through", async () => {
143
143
  // sips fails (or is absent off-macOS) → the original bytes are kept.
144
144
  const fake = fakeHeifHeaderBytes();
145
- const result = normalizeImageBytes("image/heic", fake);
145
+ const result = await normalizeImageBytes("image/heic", fake);
146
146
  expect(result.converted).toBe(false);
147
147
  expect(result.mimeType).toBe("image/heic");
148
148
  expect(result.bytes).toBe(fake);
@@ -150,35 +150,35 @@ describe("normalizeImageBytes passthrough", () => {
150
150
  });
151
151
 
152
152
  describe("normalizeImageBase64 passthrough", () => {
153
- test("non-HEIF payloads skip conversion", () => {
153
+ test("non-HEIF payloads skip conversion", async () => {
154
154
  const b64 = PNG_1PX_BYTES.toString("base64");
155
- const result = normalizeImageBase64("image/png", b64);
155
+ const result = await normalizeImageBase64("image/png", b64);
156
156
  expect(result.converted).toBe(false);
157
157
  expect(result.dataBase64).toBe(b64);
158
158
  });
159
159
  });
160
160
 
161
161
  describe("declared-MIME correction from sniffed bytes", () => {
162
- test("normalizeImageBytes relabels a mislabeled image, bytes untouched", () => {
162
+ test("normalizeImageBytes relabels a mislabeled image, bytes untouched", async () => {
163
163
  // A JPEG renamed to .png arrives declared as image/png; providers reject
164
164
  // the mismatch, so the sniffed format wins.
165
- const result = normalizeImageBytes("image/png", JPEG_HEADER_BYTES);
165
+ const result = await normalizeImageBytes("image/png", JPEG_HEADER_BYTES);
166
166
  expect(result.converted).toBe(false);
167
167
  expect(result.mimeType).toBe("image/jpeg");
168
168
  expect(result.bytes).toBe(JPEG_HEADER_BYTES);
169
169
  });
170
170
 
171
- test("normalizeImageBase64 relabels a mislabeled image, payload untouched", () => {
171
+ test("normalizeImageBase64 relabels a mislabeled image, payload untouched", async () => {
172
172
  const b64 = PNG_1PX_BYTES.toString("base64");
173
- const result = normalizeImageBase64("image/jpeg", b64);
173
+ const result = await normalizeImageBase64("image/jpeg", b64);
174
174
  expect(result.converted).toBe(false);
175
175
  expect(result.mimeType).toBe("image/png");
176
176
  expect(result.dataBase64).toBe(b64);
177
177
  });
178
178
 
179
- test("unrecognized bytes keep the declared MIME", () => {
179
+ test("unrecognized bytes keep the declared MIME", async () => {
180
180
  const bytes = Buffer.from("plain text content");
181
- const result = normalizeImageBytes("text/plain", bytes);
181
+ const result = await normalizeImageBytes("text/plain", bytes);
182
182
  expect(result.mimeType).toBe("text/plain");
183
183
  expect(result.bytes).toBe(bytes);
184
184
  });
@@ -201,17 +201,17 @@ describe.skipIf(process.platform !== "darwin")(
201
201
  expect(isHeifImage(heicBytes)).toBe(true);
202
202
  });
203
203
 
204
- test("convertImageToJpeg produces JPEG bytes", () => {
205
- const converted = convertImageToJpeg(heicBytes);
204
+ test("convertImageToJpeg produces JPEG bytes", async () => {
205
+ const converted = await convertImageToJpeg(heicBytes);
206
206
  expect(converted).not.toBeNull();
207
207
  expect(startsWithJpegMagic(converted!)).toBe(true);
208
208
  });
209
209
 
210
- test("conversion options produce distinct outputs (cache key isolation)", () => {
210
+ test("conversion options produce distinct outputs (cache key isolation)", async () => {
211
211
  // A hash-only cache key would make the second call return the first
212
212
  // call's cached full-resolution output.
213
- const fullRes = convertImageToJpeg(heicBytes, { quality: 90 });
214
- const downscaled = convertImageToJpeg(heicBytes, {
213
+ const fullRes = await convertImageToJpeg(heicBytes, { quality: 90 });
214
+ const downscaled = await convertImageToJpeg(heicBytes, {
215
215
  maxDimensionPx: 16,
216
216
  quality: 90,
217
217
  });
@@ -220,31 +220,34 @@ describe.skipIf(process.platform !== "darwin")(
220
220
  expect(fullRes!.equals(downscaled!)).toBe(false);
221
221
  });
222
222
 
223
- test("repeated conversion is stable (cache round-trip)", () => {
224
- const first = convertImageToJpeg(heicBytes, { quality: 90 });
225
- const second = convertImageToJpeg(heicBytes, { quality: 90 });
223
+ test("repeated conversion is stable (cache round-trip)", async () => {
224
+ const first = await convertImageToJpeg(heicBytes, { quality: 90 });
225
+ const second = await convertImageToJpeg(heicBytes, { quality: 90 });
226
226
  expect(first).not.toBeNull();
227
227
  expect(second).not.toBeNull();
228
228
  expect(first!.equals(second!)).toBe(true);
229
229
  });
230
230
 
231
- test("normalizeImageBytes converts to a JPEG master", () => {
232
- const result = normalizeImageBytes("image/heic", heicBytes);
231
+ test("normalizeImageBytes converts to a JPEG master", async () => {
232
+ const result = await normalizeImageBytes("image/heic", heicBytes);
233
233
  expect(result.converted).toBe(true);
234
234
  expect(result.mimeType).toBe("image/jpeg");
235
235
  expect(startsWithJpegMagic(result.bytes)).toBe(true);
236
236
  });
237
237
 
238
- test("normalizeImageBytes converts even when the declared mime is wrong", () => {
238
+ test("normalizeImageBytes converts even when the declared mime is wrong", async () => {
239
239
  // Chromium reports empty file.type for .heic; clients coerce it to
240
240
  // application/octet-stream. Detection is content-based.
241
- const result = normalizeImageBytes("application/octet-stream", heicBytes);
241
+ const result = await normalizeImageBytes(
242
+ "application/octet-stream",
243
+ heicBytes,
244
+ );
242
245
  expect(result.converted).toBe(true);
243
246
  expect(result.mimeType).toBe("image/jpeg");
244
247
  });
245
248
 
246
- test("normalizeImageBase64 converts and re-encodes", () => {
247
- const result = normalizeImageBase64(
249
+ test("normalizeImageBase64 converts and re-encodes", async () => {
250
+ const result = await normalizeImageBase64(
248
251
  "image/heic",
249
252
  heicBytes.toString("base64"),
250
253
  );
@@ -233,7 +233,7 @@ describe("reinjectAttachmentPathAnnotations", () => {
233
233
  );
234
234
  });
235
235
 
236
- test("rebuilds the exact annotation block enrichMessageWithSourcePaths appends", () => {
236
+ test("rebuilds the exact annotation block enrichMessageWithSourcePaths appends", async () => {
237
237
  // Prefix-cache parity tripwire: the block appended at persist time (from
238
238
  // live attachment inputs) and the block rebuilt on history reload (from
239
239
  // persisted metadata) must be byte-identical.
@@ -253,7 +253,7 @@ describe("reinjectAttachmentPathAnnotations", () => {
253
253
  },
254
254
  ];
255
255
  const enriched = enrichMessageWithSourcePaths(
256
- createUserMessage("compare", attachments),
256
+ await createUserMessage("compare", attachments),
257
257
  attachments,
258
258
  );
259
259
  const liveBlock = enriched.content.at(-1) as {
@@ -24,6 +24,30 @@ mock.module("../runtime/assistant-event.js", () => ({
24
24
  buildAssistantEvent: (event: unknown) => event,
25
25
  }));
26
26
 
27
+ // The default profiles used below (`balanced`, `cost-optimized`) route through
28
+ // the Vellum-managed connection, and the handler's availability guard judges
29
+ // that route for real. Stand in for a signed-in platform session so the pin
30
+ // path under test is the healthy one; `managedProxyEnabled` is flipped by the
31
+ // guard test.
32
+ let managedProxyEnabled = true;
33
+ mock.module("../providers/platform-proxy/context.js", () => ({
34
+ resolveManagedProxyContext: async () => ({
35
+ enabled: managedProxyEnabled,
36
+ platformBaseUrl: "https://platform.example",
37
+ assistantApiKey: managedProxyEnabled ? "key" : "",
38
+ }),
39
+ }));
40
+
41
+ // Vault stand-in: tests that exercise BYOK availability drop the credential
42
+ // they need into this map and clean it up after.
43
+ const storedKeys: Record<string, string> = {};
44
+ mock.module("../security/secure-keys.js", () => ({
45
+ getSecureKeyResultAsync: async (key: string) => ({
46
+ value: storedKeys[key],
47
+ unreachable: false,
48
+ }),
49
+ }));
50
+
27
51
  // The handler reads the real config: the "balanced" and "cost-optimized"
28
52
  // profiles used below are code-default catalog entries that always resolve,
29
53
  // and llm.profileSession's schema defaults (1800/43200) are what the TTL
@@ -44,9 +68,24 @@ import {
44
68
  } from "../persistence/conversation-crud.js";
45
69
  import { getDb } from "../persistence/db-connection.js";
46
70
  import { initializeDb } from "../persistence/db-init.js";
71
+ import { providerConnections } from "../persistence/schema/inference.js";
72
+ import { setConfig } from "./helpers/set-config.js";
47
73
 
48
74
  await initializeDb();
49
75
 
76
+ // The Vellum-managed connection row the default profiles resolve to.
77
+ getDb()
78
+ .insert(providerConnections)
79
+ .values({
80
+ name: "vellum",
81
+ provider: "vellum",
82
+ auth: JSON.stringify({ type: "platform" }),
83
+ createdAt: Date.now(),
84
+ updatedAt: Date.now(),
85
+ })
86
+ .onConflictDoNothing()
87
+ .run();
88
+
50
89
  import {
51
90
  closeInferenceProfileSession,
52
91
  listInferenceProfileSessionsWithRemaining,
@@ -344,6 +383,62 @@ describe("setInferenceProfileSession", () => {
344
383
  );
345
384
  });
346
385
 
386
+ test("open with an unavailable profile — refuses the pin and names the fix", async () => {
387
+ const conv = createConversation("sess-handler-unavailable-profile");
388
+ managedProxyEnabled = false;
389
+ try {
390
+ const promise = setInferenceProfileSession({
391
+ conversationId: conv.id,
392
+ profile: "balanced",
393
+ ttlSeconds: 300,
394
+ });
395
+ await expect(promise).rejects.toThrow(/Not signed in to Vellum/);
396
+ await expect(promise).rejects.toThrow(
397
+ /assistant inference send --profile balanced "Reply with OK"/,
398
+ );
399
+ // Nothing was pinned.
400
+ expect(getConversation(conv.id)?.inferenceProfile).toBeNull();
401
+ } finally {
402
+ managedProxyEnabled = true;
403
+ }
404
+ });
405
+
406
+ test("BYOK default provider — pins a managed preset without a Vellum sign-in", async () => {
407
+ const conv = createConversation("sess-handler-byok-preset");
408
+ // Signed out of Vellum, but llm.defaultProvider points the managed
409
+ // presets at the user's own anthropic connection — the pin must judge
410
+ // that body, not the Vellum column.
411
+ managedProxyEnabled = false;
412
+ storedKeys["credential/anthropic/api_key"] = "test-key";
413
+ getDb()
414
+ .insert(providerConnections)
415
+ .values({
416
+ name: "anthropic-personal",
417
+ provider: "anthropic",
418
+ auth: JSON.stringify({
419
+ type: "api_key",
420
+ credential: "credential/anthropic/api_key",
421
+ }),
422
+ createdAt: Date.now(),
423
+ updatedAt: Date.now(),
424
+ })
425
+ .onConflictDoNothing()
426
+ .run();
427
+ setConfig("llm", { defaultProvider: { provider: "anthropic" } });
428
+ try {
429
+ const result = await setInferenceProfileSession({
430
+ conversationId: conv.id,
431
+ profile: "balanced",
432
+ ttlSeconds: 300,
433
+ });
434
+ expect(result.profile).toBe("balanced");
435
+ } finally {
436
+ managedProxyEnabled = true;
437
+ delete storedKeys["credential/anthropic/api_key"];
438
+ setConfig("llm", {});
439
+ }
440
+ });
441
+
347
442
  test("open with ttlSeconds=null — expiresAt=null, sessionId=null, profile kept", async () => {
348
443
  const conv = createConversation("sess-handler-null-ttl");
349
444
 
@@ -16,6 +16,17 @@ mock.module("../runtime/assistant-event.js", () => ({
16
16
  buildAssistantEvent: (event: unknown) => event,
17
17
  }));
18
18
 
19
+ // "balanced"/"cost-optimized" route through the Vellum-managed connection, and
20
+ // the open handler's availability guard judges that route for real. Stand in
21
+ // for a signed-in platform session so these tests exercise the healthy path.
22
+ mock.module("../providers/platform-proxy/context.js", () => ({
23
+ resolveManagedProxyContext: async () => ({
24
+ enabled: true,
25
+ platformBaseUrl: "https://platform.example",
26
+ assistantApiKey: "key",
27
+ }),
28
+ }));
29
+
19
30
  // The handler resolves "balanced"/"cost-optimized" through the code-defined
20
31
  // default profile catalog and reads `llm.profileSession` schema defaults
21
32
  // (1800/43200), so real config with no seeding covers these tests.
@@ -23,11 +34,25 @@ mock.module("../runtime/assistant-event.js", () => ({
23
34
  import { createConversation } from "../persistence/conversation-crud.js";
24
35
  import { getDb } from "../persistence/db-connection.js";
25
36
  import { initializeDb } from "../persistence/db-init.js";
37
+ import { providerConnections } from "../persistence/schema/inference.js";
26
38
  import { ROUTES } from "../runtime/routes/inference-profile-session-routes.js";
27
39
  import { resetDbForTesting } from "./db-test-helpers.js";
28
40
 
29
41
  await initializeDb();
30
42
 
43
+ // The Vellum-managed connection row the default profiles resolve to.
44
+ getDb()
45
+ .insert(providerConnections)
46
+ .values({
47
+ name: "vellum",
48
+ provider: "vellum",
49
+ auth: JSON.stringify({ type: "platform" }),
50
+ createdAt: Date.now(),
51
+ updatedAt: Date.now(),
52
+ })
53
+ .onConflictDoNothing()
54
+ .run();
55
+
31
56
  const openRoute = ROUTES.find(
32
57
  (r) => r.operationId === "inference_profile_open",
33
58
  )!;
@@ -182,7 +182,12 @@ describe("introduction card decisions", () => {
182
182
  expectedExternalUserId: "U-REQUESTER",
183
183
  expectedChatId: "C-CHAT",
184
184
  identityBindingStatus: "bound",
185
- destinationAddress: "C-CHAT",
185
+ // The person, not the room. Slack delivers to a user id, and the room
186
+ // may hold an audience the code was never meant for. `expectedChatId`
187
+ // still carries the room because that is where the conversation is;
188
+ // with both identity fields set the consume path requires the user
189
+ // match, so the room is not a credential.
190
+ destinationAddress: "U-REQUESTER",
186
191
  verificationPurpose: "trusted_contact",
187
192
  });
188
193
  expect(outcomesOfType("activate_member")).toHaveLength(0);