@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e

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 (456) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +8 -0
  3. package/docs/activation-funnel-telemetry.md +13 -7
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  7. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  9. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  12. package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  13. package/openapi.yaml +530 -107
  14. package/package.json +1 -1
  15. package/scripts/generate-openapi.ts +8 -0
  16. package/src/__tests__/activation-early-marking.test.ts +6 -5
  17. package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
  18. package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
  19. package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
  20. package/src/__tests__/app-bundler.test.ts +4 -12
  21. package/src/__tests__/app-executors.test.ts +2 -49
  22. package/src/__tests__/app-routes-csp.test.ts +114 -146
  23. package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
  24. package/src/__tests__/build-persisted-content.test.ts +96 -0
  25. package/src/__tests__/bundle-scanner.test.ts +27 -1
  26. package/src/__tests__/call-controller.test.ts +291 -0
  27. package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
  28. package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
  29. package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
  30. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  31. package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
  32. package/src/__tests__/config-loader-backfill.test.ts +9 -4
  33. package/src/__tests__/config-schema-cmd.test.ts +10 -11
  34. package/src/__tests__/config-schema.test.ts +190 -257
  35. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
  37. package/src/__tests__/conversation-agent-loop.test.ts +22 -9
  38. package/src/__tests__/conversation-error.test.ts +31 -0
  39. package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
  40. package/src/__tests__/conversation-process-callsite.test.ts +12 -19
  41. package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
  42. package/src/__tests__/conversation-summarize-route.test.ts +36 -44
  43. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  44. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
  45. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
  46. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
  47. package/src/__tests__/conversation-usage.test.ts +4 -12
  48. package/src/__tests__/credential-routes.test.ts +250 -0
  49. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  50. package/src/__tests__/db-migration-rollback.test.ts +22 -0
  51. package/src/__tests__/empty-response-hook.test.ts +186 -1
  52. package/src/__tests__/external-plugin-loader.test.ts +11 -5
  53. package/src/__tests__/heartbeat-service.test.ts +0 -28
  54. package/src/__tests__/host-shell-tool.test.ts +2 -0
  55. package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
  56. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
  57. package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
  58. package/src/__tests__/invite-routes-http.test.ts +12 -16
  59. package/src/__tests__/list-all-apps.test.ts +0 -4
  60. package/src/__tests__/llm-context-resolution.test.ts +32 -56
  61. package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
  62. package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
  63. package/src/__tests__/llm-resolver.test.ts +342 -602
  64. package/src/__tests__/llm-schema.test.ts +79 -37
  65. package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
  66. package/src/__tests__/media-stream-output.test.ts +259 -3
  67. package/src/__tests__/media-stream-server-integration.test.ts +22 -1
  68. package/src/__tests__/media-stream-stt-session.test.ts +47 -0
  69. package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
  70. package/src/__tests__/memory-recall-log-store.test.ts +47 -13
  71. package/src/__tests__/mock-gateway-ipc.ts +46 -1
  72. package/src/__tests__/mtime-cache.test.ts +61 -0
  73. package/src/__tests__/navigate-settings-tab.test.ts +2 -0
  74. package/src/__tests__/normalize-onboarding.test.ts +33 -0
  75. package/src/__tests__/onboarding-persona-write.test.ts +26 -0
  76. package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
  77. package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
  78. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
  79. package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
  80. package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
  81. package/src/__tests__/provider-connections-backfill.test.ts +138 -0
  82. package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
  83. package/src/__tests__/provider-registry-ollama.test.ts +8 -18
  84. package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
  85. package/src/__tests__/provider-usage-tracking.test.ts +9 -19
  86. package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
  87. package/src/__tests__/published-app-updater.test.ts +22 -16
  88. package/src/__tests__/registry.test.ts +5 -16
  89. package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
  90. package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
  91. package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
  92. package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
  93. package/src/__tests__/reveal-success-registry.test.ts +123 -0
  94. package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
  95. package/src/__tests__/secret-fixtures.ts +9 -0
  96. package/src/__tests__/server-history-render.test.ts +28 -0
  97. package/src/__tests__/skills.test.ts +9 -4
  98. package/src/__tests__/slack-share-routes.test.ts +0 -1
  99. package/src/__tests__/stt-stream-session.test.ts +6 -5
  100. package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
  101. package/src/__tests__/subagent-disposal.test.ts +2 -0
  102. package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
  103. package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
  104. package/src/__tests__/subagent-manager-notify.test.ts +2 -0
  105. package/src/__tests__/subagent-role-registry.test.ts +37 -0
  106. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  107. package/src/__tests__/subagent-terminal-message.test.ts +50 -0
  108. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
  109. package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
  110. package/src/__tests__/telemetry-routes.test.ts +99 -19
  111. package/src/__tests__/tool-audit.test.ts +34 -4
  112. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  113. package/src/__tests__/tool-profiler.test.ts +72 -1
  114. package/src/__tests__/tool-result-spool.test.ts +49 -4
  115. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
  116. package/src/__tests__/ui-channel-variants.test.ts +108 -0
  117. package/src/__tests__/ui-shape-teaching.test.ts +255 -0
  118. package/src/__tests__/usage-attribution.test.ts +18 -41
  119. package/src/__tests__/user-plugin-loader.test.ts +4 -4
  120. package/src/__tests__/voice-config-update.test.ts +46 -0
  121. package/src/__tests__/voice-session-bridge.test.ts +216 -84
  122. package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
  123. package/src/agent/loop.ts +4 -3
  124. package/src/api/events/open-conversation.test.ts +64 -0
  125. package/src/api/events/open-conversation.ts +33 -0
  126. package/src/api/index.ts +6 -0
  127. package/src/api/responses/conversation-message.ts +5 -0
  128. package/src/apps/app-store.ts +25 -35
  129. package/src/bundler/app-bundler.ts +34 -48
  130. package/src/bundler/app-compiler.ts +39 -4
  131. package/src/bundler/bundle-scanner.ts +13 -0
  132. package/src/bundler/manifest.ts +1 -1
  133. package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
  134. package/src/calls/call-constants.ts +5 -0
  135. package/src/calls/call-controller.ts +100 -32
  136. package/src/calls/call-transport.ts +9 -0
  137. package/src/calls/media-stream-output.ts +107 -4
  138. package/src/calls/media-stream-server.ts +29 -9
  139. package/src/calls/media-stream-stt-session.ts +7 -1
  140. package/src/calls/media-turn-detector.ts +11 -1
  141. package/src/calls/voice-session-bridge.ts +84 -63
  142. package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
  143. package/src/cli/commands/__tests__/notifications.test.ts +24 -3
  144. package/src/cli/commands/config.help.ts +6 -6
  145. package/src/cli/commands/credentials.help.ts +13 -0
  146. package/src/cli/commands/credentials.ts +6 -1
  147. package/src/cli/commands/email.help.ts +7 -0
  148. package/src/cli/commands/email.ts +35 -1
  149. package/src/cli/commands/inference-providers.ts +168 -107
  150. package/src/cli/commands/inference.help.ts +118 -46
  151. package/src/cli/commands/memory/index.help.ts +23 -0
  152. package/src/cli/commands/memory/nodes.ts +146 -0
  153. package/src/cli/commands/notifications.help.ts +10 -10
  154. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
  155. package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
  156. package/src/cli/commands/oauth/connect.test.ts +126 -0
  157. package/src/cli/commands/oauth/connect.ts +29 -6
  158. package/src/cli/commands/oauth/index.help.ts +7 -1
  159. package/src/cli/commands/oauth/status.test.ts +69 -3
  160. package/src/cli/commands/oauth/status.ts +50 -12
  161. package/src/cli/commands/plugins.help.ts +13 -2
  162. package/src/cli/commands/plugins.ts +61 -7
  163. package/src/cli/commands/telemetry.help.ts +13 -0
  164. package/src/cli/commands/telemetry.ts +45 -5
  165. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
  166. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
  167. package/src/cli/lib/bundled-marketplace.json +93 -36
  168. package/src/cli/lib/inspect-plugin.ts +5 -1
  169. package/src/cli/lib/install-from-github.ts +68 -4
  170. package/src/cli/lib/plugin-catalog-local.ts +6 -2
  171. package/src/cli/lib/plugin-fingerprint.ts +3 -3
  172. package/src/cli/lib/upgrade-plugin.ts +236 -35
  173. package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
  174. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
  175. package/src/config/__tests__/profile-materialization.test.ts +1 -88
  176. package/src/config/bundled-skills/AGENTS.md +3 -30
  177. package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
  178. package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
  179. package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
  180. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  181. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
  182. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  183. package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
  184. package/src/config/bundled-skills/settings/TOOLS.json +3 -1
  185. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
  186. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
  187. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  188. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  189. package/src/config/call-site-defaults.ts +3 -3
  190. package/src/config/feature-flag-registry.json +24 -39
  191. package/src/config/llm-resolver.ts +88 -475
  192. package/src/config/profile-materialization.ts +11 -11
  193. package/src/config/schema.ts +93 -127
  194. package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
  195. package/src/config/schemas/__tests__/stt.test.ts +31 -3
  196. package/src/config/schemas/live-voice.ts +10 -4
  197. package/src/config/schemas/llm.ts +52 -15
  198. package/src/config/schemas/memory-lifecycle.ts +1 -1
  199. package/src/config/schemas/memory-retrospective.ts +8 -0
  200. package/src/config/schemas/memory-v2.ts +2 -2
  201. package/src/config/schemas/memory-v3.ts +1 -1
  202. package/src/config/schemas/services.ts +6 -3
  203. package/src/config/schemas/stt.ts +38 -21
  204. package/src/config/schemas/tts.ts +13 -18
  205. package/src/config/skills.ts +31 -21
  206. package/src/context/compactor.ts +44 -7
  207. package/src/context/post-turn-tool-result-truncation.ts +4 -2
  208. package/src/context/tool-result-spool.ts +26 -5
  209. package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
  210. package/src/conversations/message-consolidation.ts +22 -2
  211. package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
  212. package/src/daemon/app-source-watcher.ts +17 -23
  213. package/src/daemon/chat-credential-redaction.ts +1365 -0
  214. package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
  215. package/src/daemon/conversation-agent-loop.ts +71 -31
  216. package/src/daemon/conversation-error.ts +36 -14
  217. package/src/daemon/conversation-process.ts +22 -0
  218. package/src/daemon/conversation-store.ts +35 -0
  219. package/src/daemon/conversation-surfaces.ts +25 -25
  220. package/src/daemon/conversation-tool-setup.ts +33 -7
  221. package/src/daemon/conversation.ts +55 -5
  222. package/src/daemon/handlers/shared.ts +33 -2
  223. package/src/daemon/lifecycle.ts +4 -4
  224. package/src/daemon/message-types/conversations.ts +6 -17
  225. package/src/daemon/providers-setup.ts +8 -0
  226. package/src/daemon/tool-setup-types.ts +7 -1
  227. package/src/daemon/wake-conversation-ops.ts +10 -1
  228. package/src/hooks/types.ts +9 -0
  229. package/src/ipc/__tests__/email-ipc.test.ts +90 -0
  230. package/src/ipc/gateway-client.test.ts +59 -0
  231. package/src/ipc/gateway-client.ts +70 -27
  232. package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
  233. package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
  234. package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
  235. package/src/live-voice/__tests__/protocol.test.ts +122 -0
  236. package/src/live-voice/live-voice-session.ts +443 -40
  237. package/src/live-voice/protocol.ts +143 -1
  238. package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
  239. package/src/monitoring/plugin-source-watch.ts +3 -62
  240. package/src/notifications/README.md +1 -1
  241. package/src/permissions/checker.ts +8 -4
  242. package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
  243. package/src/persistence/conversation-crud.ts +104 -2
  244. package/src/persistence/db-init.ts +14 -3
  245. package/src/persistence/job-handlers/cleanup.ts +15 -7
  246. package/src/persistence/llm-request-log-store.ts +88 -52
  247. package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
  248. package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
  249. package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
  250. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
  251. package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
  252. package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
  253. package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
  254. package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
  255. package/src/persistence/migrations/helpers/relocation.ts +44 -1
  256. package/src/persistence/migrations/run-migrations.ts +25 -1
  257. package/src/persistence/schema/infrastructure.ts +9 -0
  258. package/src/persistence/schema/memory-core.ts +3 -0
  259. package/src/persistence/schema/memory-injection.ts +2 -0
  260. package/src/persistence/steps.ts +36 -0
  261. package/src/platform/client.test.ts +1 -44
  262. package/src/platform/client.ts +10 -20
  263. package/src/platform/consent-cache.test.ts +89 -23
  264. package/src/platform/consent-cache.ts +71 -33
  265. package/src/plugin-api/constants.ts +12 -0
  266. package/src/plugin-api/conversation-turn.ts +37 -14
  267. package/src/plugin-api/index.ts +11 -1
  268. package/src/plugin-api/resolve-credential.ts +75 -0
  269. package/src/plugin-api/vision-support.test.ts +8 -19
  270. package/src/plugin-api/vision-support.ts +26 -17
  271. package/src/plugins/collect-source-versions.ts +77 -0
  272. package/src/plugins/defaults/compaction/compact.ts +6 -0
  273. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
  275. package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
  276. package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
  277. package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
  278. package/src/plugins/defaults/index.ts +8 -1
  279. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
  280. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
  281. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
  282. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
  283. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
  284. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
  285. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
  286. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
  287. package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
  288. package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
  289. package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
  290. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
  291. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
  292. package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
  293. package/src/plugins/defaults/memory/graph/store.ts +114 -0
  294. package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
  295. package/src/plugins/defaults/memory/graph/tools.ts +47 -13
  296. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
  297. package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
  298. package/src/plugins/defaults/memory/memory-db.ts +3 -2
  299. package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
  300. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
  301. package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
  302. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
  303. package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
  304. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
  305. package/src/plugins/defaults/memory/path-containment.ts +21 -0
  306. package/src/plugins/defaults/memory/prompt-override.ts +51 -13
  307. package/src/plugins/defaults/memory/tools.test.ts +34 -0
  308. package/src/plugins/defaults/memory/tools.ts +12 -2
  309. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
  310. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
  311. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
  312. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
  313. package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
  314. package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
  315. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
  316. package/src/plugins/defaults/memory/v2/migration.ts +46 -16
  317. package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
  318. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
  319. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
  320. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
  321. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
  322. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
  323. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
  324. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
  325. package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
  326. package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
  327. package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
  328. package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
  329. package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
  330. package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
  331. package/src/plugins/defaults/memory/v3/prune.ts +17 -11
  332. package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
  333. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
  334. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
  335. package/src/plugins/external-plugin-loader.ts +15 -15
  336. package/src/plugins/mtime-cache.ts +47 -0
  337. package/src/plugins/pipeline.ts +9 -1
  338. package/src/plugins/plugin-execution-context.ts +44 -0
  339. package/src/plugins/plugin-tree-walk.ts +31 -24
  340. package/src/plugins/source-fingerprint.ts +3 -4
  341. package/src/prompts/normalize-onboarding.ts +12 -0
  342. package/src/prompts/persona-resolver.ts +8 -0
  343. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
  344. package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
  345. package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
  346. package/src/providers/__tests__/retry-callsite.test.ts +235 -215
  347. package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
  348. package/src/providers/atlascloud/client.ts +10 -49
  349. package/src/providers/baseten/client.ts +43 -0
  350. package/src/providers/call-site-routing.ts +26 -13
  351. package/src/providers/connection-resolution.ts +9 -11
  352. package/src/providers/fetch-provider-catalog.ts +4 -2
  353. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
  354. package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
  355. package/src/providers/inference/adapter-factory.ts +27 -6
  356. package/src/providers/inference/auth.ts +29 -1
  357. package/src/providers/inference/backfill.ts +61 -10
  358. package/src/providers/inference/connection-availability.ts +3 -2
  359. package/src/providers/inference/resolve-auth.ts +9 -1
  360. package/src/providers/model-catalog.ts +37 -0
  361. package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
  362. package/src/providers/openai/api-key-validation.ts +70 -0
  363. package/src/providers/retry.ts +2 -0
  364. package/src/providers/types.ts +11 -4
  365. package/src/providers/vellum-model-routing.test.ts +26 -0
  366. package/src/providers/vellum-model-routing.ts +30 -0
  367. package/src/providers/voice-error-copy.ts +47 -0
  368. package/src/runtime/agent-wake.ts +40 -24
  369. package/src/runtime/for-chat-mint-registry.ts +118 -0
  370. package/src/runtime/reveal-nonce.ts +49 -0
  371. package/src/runtime/reveal-success-registry.ts +306 -0
  372. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
  373. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
  374. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
  375. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
  376. package/src/runtime/routes/app-management-routes.ts +152 -45
  377. package/src/runtime/routes/app-routes.ts +16 -77
  378. package/src/runtime/routes/canned-message-complete.ts +16 -16
  379. package/src/runtime/routes/conversation-management-routes.ts +17 -14
  380. package/src/runtime/routes/conversation-query-routes.ts +54 -6
  381. package/src/runtime/routes/conversation-routes.ts +48 -2
  382. package/src/runtime/routes/credential-routes.ts +116 -3
  383. package/src/runtime/routes/email-routes.ts +17 -1
  384. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
  385. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
  386. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
  387. package/src/runtime/routes/inference-send-routes.ts +1 -1
  388. package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
  389. package/src/runtime/routes/plugins-routes.ts +37 -6
  390. package/src/runtime/routes/publish-routes.ts +15 -18
  391. package/src/runtime/routes/schedule-worker-routes.ts +9 -0
  392. package/src/runtime/routes/secret-routes.ts +10 -0
  393. package/src/runtime/routes/telemetry-routes.ts +149 -45
  394. package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
  395. package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
  396. package/src/schedule/schedule-store.ts +12 -1
  397. package/src/schedule/schedule-timezone.ts +63 -0
  398. package/src/schedule/scheduler.ts +100 -6
  399. package/src/schedule/worker-control.ts +19 -0
  400. package/src/security/auth-fallback-events-store.ts +7 -6
  401. package/src/security/secret-scanner.ts +26 -1
  402. package/src/services/published-app-updater.ts +6 -11
  403. package/src/stt/stt-stream-session.ts +36 -16
  404. package/src/subagent/manager.ts +34 -8
  405. package/src/telemetry/AGENTS.md +30 -1
  406. package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
  407. package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
  408. package/src/telemetry/config-setting-snapshot.ts +44 -10
  409. package/src/telemetry/telemetry-event-sources.test.ts +124 -30
  410. package/src/telemetry/telemetry-event-sources.ts +137 -83
  411. package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
  412. package/src/telemetry/telemetry-events-outbox.ts +60 -9
  413. package/src/telemetry/telemetry-wire-source.json +1 -1
  414. package/src/telemetry/telemetry-wire-validation.ts +39 -2
  415. package/src/telemetry/telemetry-wire.generated.ts +8 -0
  416. package/src/telemetry/tool-audit.ts +15 -9
  417. package/src/telemetry/tool-executed-events-store.test.ts +1 -1
  418. package/src/telemetry/turn-events-store.ts +20 -0
  419. package/src/telemetry/types.ts +45 -12
  420. package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
  421. package/src/telemetry/usage-telemetry-reporter.ts +117 -18
  422. package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
  423. package/src/telemetry/watchdog-direct-emit.ts +11 -6
  424. package/src/tools/apps/executors.ts +11 -36
  425. package/src/tools/executor.ts +14 -1
  426. package/src/tools/host-terminal/host-shell.ts +6 -2
  427. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
  428. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
  429. package/src/tools/network/web-fetch.ts +6 -2
  430. package/src/tools/skills/sandbox-runner.ts +5 -2
  431. package/src/tools/subagent/spawn.ts +7 -11
  432. package/src/tools/terminal/shell.ts +5 -2
  433. package/src/tools/tool-manifest.ts +0 -2
  434. package/src/tools/tool-profiler.ts +37 -6
  435. package/src/tools/ui-surface/channel-variants.ts +101 -0
  436. package/src/tools/ui-surface/definitions.ts +23 -67
  437. package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
  438. package/src/tts/__tests__/provider-adapters.test.ts +18 -0
  439. package/src/tts/provider-catalog.ts +2 -4
  440. package/src/tts/providers/deepgram-provider.ts +10 -1
  441. package/src/types/onboarding-context.ts +8 -0
  442. package/src/usage/attribution.ts +18 -112
  443. package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
  444. package/src/util/provider-error-patterns.ts +7 -1
  445. package/src/util/worker-process.ts +105 -0
  446. package/src/watcher/__tests__/telemetry.test.ts +17 -4
  447. package/src/watcher/telemetry.ts +5 -5
  448. package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
  449. package/src/workspace/migrations/registry.ts +2 -0
  450. package/src/workspace/provider-commit-message-generator.ts +6 -4
  451. package/src/__tests__/app-open-proxy.test.ts +0 -67
  452. package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
  453. package/src/onboarding/onboarding-research-events-store.ts +0 -104
  454. package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
  455. package/src/tools/apps/definitions.ts +0 -73
  456. package/src/tools/apps/open-proxy.ts +0 -43
@@ -1,14 +1,16 @@
1
1
  /**
2
- * Tests for `assistant inference providers connections` CLI arg parsing / IPC
3
- * wiring focused on the openai-compatible `--base-url` / `--model` flags that
4
- * forward to the connection route's `base_url` + `models` fields.
2
+ * Tests for `assistant inference providers` CLI arg parsing / IPC wiring —
3
+ * the provider-first verbs (auth derived from the provider, explicit --auth
4
+ * as an override), the openai-compatible `--base-url` / `--model` flags that
5
+ * forward to the connection route's `base_url` + `models` fields, and the
6
+ * deprecated `providers connections` alias.
5
7
  */
6
8
 
7
9
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
8
10
 
9
11
  import { Command } from "commander";
10
12
 
11
- let lastIpcCall: { method: string; params?: any } | null = null;
13
+ let ipcCalls: { method: string; params?: any }[] = [];
12
14
  let mockIpcResult: { ok: boolean; result?: unknown; error?: string } = {
13
15
  ok: true,
14
16
  result: {},
@@ -16,7 +18,7 @@ let mockIpcResult: { ok: boolean; result?: unknown; error?: string } = {
16
18
 
17
19
  mock.module("../../../ipc/cli-client.js", () => ({
18
20
  cliIpcCall: async (method: string, params?: Record<string, unknown>) => {
19
- lastIpcCall = { method, params };
21
+ ipcCalls.push({ method, params });
20
22
  return mockIpcResult;
21
23
  },
22
24
  }));
@@ -40,8 +42,12 @@ const CONNECTION_RESULT = {
40
42
  updatedAt: Date.now(),
41
43
  };
42
44
 
45
+ function lastIpcCall(): { method: string; params?: any } | null {
46
+ return ipcCalls[ipcCalls.length - 1] ?? null;
47
+ }
48
+
43
49
  beforeEach(() => {
44
- lastIpcCall = null;
50
+ ipcCalls = [];
45
51
  mockIpcResult = { ok: true, result: CONNECTION_RESULT };
46
52
  process.exitCode = 0;
47
53
  });
@@ -80,11 +86,74 @@ async function run(
80
86
  return { stdout, exitCode };
81
87
  }
82
88
 
83
- describe("providers connections create — openai-compatible", () => {
89
+ describe("providers create — derived auth", () => {
90
+ test("derives api_key auth from --credential for a keyed provider", async () => {
91
+ await run([
92
+ "providers",
93
+ "create",
94
+ "anthropic-personal",
95
+ "--provider",
96
+ "anthropic",
97
+ "--credential",
98
+ "credential/anthropic/api_key",
99
+ ]);
100
+ expect(lastIpcCall()?.method).toBe("inference_provider_connections_create");
101
+ expect(lastIpcCall()?.params?.body).toEqual({
102
+ name: "anthropic-personal",
103
+ provider: "anthropic",
104
+ auth: { type: "api_key", credential: "credential/anthropic/api_key" },
105
+ });
106
+ });
107
+
108
+ test("derives none auth for a keyless provider (ollama)", async () => {
109
+ await run([
110
+ "providers",
111
+ "create",
112
+ "ollama-personal",
113
+ "--provider",
114
+ "ollama",
115
+ ]);
116
+ expect(lastIpcCall()?.params?.body).toEqual({
117
+ name: "ollama-personal",
118
+ provider: "ollama",
119
+ auth: { type: "none" },
120
+ });
121
+ });
122
+
123
+ test("rejects a keyed provider without --credential before calling the daemon", async () => {
124
+ const { exitCode } = await run([
125
+ "providers",
126
+ "create",
127
+ "anthropic-personal",
128
+ "--provider",
129
+ "anthropic",
130
+ ]);
131
+ expect(exitCode).toBe(1);
132
+ expect(lastIpcCall()).toBeNull();
133
+ });
134
+
135
+ test("an explicit --auth override wins over derivation", async () => {
136
+ await run([
137
+ "providers",
138
+ "create",
139
+ "managed-anthropic",
140
+ "--provider",
141
+ "anthropic",
142
+ "--auth",
143
+ "platform",
144
+ ]);
145
+ expect(lastIpcCall()?.params?.body).toEqual({
146
+ name: "managed-anthropic",
147
+ provider: "anthropic",
148
+ auth: { type: "platform" },
149
+ });
150
+ });
151
+ });
152
+
153
+ describe("providers create — openai-compatible", () => {
84
154
  test("forwards base_url and collected --model list to the route", async () => {
85
155
  await run([
86
156
  "providers",
87
- "connections",
88
157
  "create",
89
158
  "local-llm",
90
159
  "--provider",
@@ -98,8 +167,8 @@ describe("providers connections create — openai-compatible", () => {
98
167
  "--model",
99
168
  "model-b",
100
169
  ]);
101
- expect(lastIpcCall?.method).toBe("inference_provider_connections_create");
102
- expect(lastIpcCall?.params?.body).toEqual({
170
+ expect(lastIpcCall()?.method).toBe("inference_provider_connections_create");
171
+ expect(lastIpcCall()?.params?.body).toEqual({
103
172
  name: "local-llm",
104
173
  provider: "openai-compatible",
105
174
  auth: { type: "none" },
@@ -108,10 +177,49 @@ describe("providers connections create — openai-compatible", () => {
108
177
  });
109
178
  });
110
179
 
180
+ test("openai-compatible without --credential derives none auth (local endpoints)", async () => {
181
+ await run([
182
+ "providers",
183
+ "create",
184
+ "local-llm",
185
+ "--provider",
186
+ "openai-compatible",
187
+ "--base-url",
188
+ "http://localhost:1234/v1",
189
+ "--model",
190
+ "model-a",
191
+ ]);
192
+ expect(lastIpcCall()?.params?.body).toEqual({
193
+ name: "local-llm",
194
+ provider: "openai-compatible",
195
+ auth: { type: "none" },
196
+ base_url: "http://localhost:1234/v1",
197
+ models: [{ id: "model-a" }],
198
+ });
199
+ });
200
+
201
+ test("openai-compatible with --credential derives api_key auth", async () => {
202
+ await run([
203
+ "providers",
204
+ "create",
205
+ "hosted-llm",
206
+ "--provider",
207
+ "openai-compatible",
208
+ "--credential",
209
+ "credential/hosted/key",
210
+ "--base-url",
211
+ "https://api.example.com/v1",
212
+ "--model",
213
+ "model-a",
214
+ ]);
215
+ expect(lastIpcCall()?.params?.body).toMatchObject({
216
+ auth: { type: "api_key", credential: "credential/hosted/key" },
217
+ });
218
+ });
219
+
111
220
  test("rejects openai-compatible without --base-url before calling the daemon", async () => {
112
221
  const { exitCode } = await run([
113
222
  "providers",
114
- "connections",
115
223
  "create",
116
224
  "local-llm",
117
225
  "--provider",
@@ -122,47 +230,81 @@ describe("providers connections create — openai-compatible", () => {
122
230
  "model-a",
123
231
  ]);
124
232
  expect(exitCode).toBe(1);
125
- expect(lastIpcCall).toBeNull();
233
+ expect(lastIpcCall()).toBeNull();
126
234
  });
235
+ });
127
236
 
128
- test("omits base_url/models for a standard provider", async () => {
237
+ describe("providers update", () => {
238
+ test("a bare --credential rotates via derived api_key auth", async () => {
239
+ mockIpcResult = {
240
+ ok: true,
241
+ result: {
242
+ ...CONNECTION_RESULT,
243
+ name: "anthropic-personal",
244
+ provider: "anthropic",
245
+ auth: { type: "api_key", credential: "credential/anthropic/old_key" },
246
+ },
247
+ };
129
248
  await run([
130
249
  "providers",
131
- "connections",
132
- "create",
250
+ "update",
133
251
  "anthropic-personal",
134
- "--provider",
135
- "anthropic",
136
- "--auth",
137
- "api_key",
138
252
  "--credential",
139
- "credential/anthropic/api_key",
253
+ "credential/anthropic/new_key",
140
254
  ]);
141
- expect(lastIpcCall?.params?.body).toEqual({
142
- name: "anthropic-personal",
143
- provider: "anthropic",
144
- auth: { type: "api_key", credential: "credential/anthropic/api_key" },
255
+ expect(ipcCalls.map((c) => c.method)).toEqual([
256
+ "inference_provider_connections_get",
257
+ "inference_provider_connections_update",
258
+ ]);
259
+ expect(lastIpcCall()?.params).toEqual({
260
+ pathParams: { name: "anthropic-personal" },
261
+ body: {
262
+ auth: { type: "api_key", credential: "credential/anthropic/new_key" },
263
+ },
145
264
  });
146
265
  });
147
- });
148
266
 
149
- describe("providers connections update openai-compatible", () => {
150
- test("forwards base_url and models alongside auth", async () => {
151
- mockIpcResult = { ok: true, result: CONNECTION_RESULT };
267
+ test("a bare --credential refuses to rotate subscription auth", async () => {
268
+ mockIpcResult = {
269
+ ok: true,
270
+ result: {
271
+ ...CONNECTION_RESULT,
272
+ name: "chatgpt-subscription",
273
+ provider: "openai",
274
+ auth: {
275
+ type: "oauth_subscription",
276
+ credential: "credential/chatgpt/access_token",
277
+ },
278
+ },
279
+ };
280
+ const { exitCode } = await run([
281
+ "providers",
282
+ "update",
283
+ "chatgpt-subscription",
284
+ "--credential",
285
+ "credential/other",
286
+ ]);
287
+ expect(exitCode).toBe(1);
288
+ expect(ipcCalls.map((c) => c.method)).toEqual([
289
+ "inference_provider_connections_get",
290
+ ]);
291
+ });
292
+
293
+ test("with no auth flags, re-sends the stored auth (GET first)", async () => {
152
294
  await run([
153
295
  "providers",
154
- "connections",
155
296
  "update",
156
297
  "local-llm",
157
- "--auth",
158
- "none",
159
298
  "--base-url",
160
299
  "http://localhost:5678/v1",
161
300
  "--model",
162
301
  "model-c",
163
302
  ]);
164
- expect(lastIpcCall?.method).toBe("inference_provider_connections_update");
165
- expect(lastIpcCall?.params).toEqual({
303
+ expect(ipcCalls.map((c) => c.method)).toEqual([
304
+ "inference_provider_connections_get",
305
+ "inference_provider_connections_update",
306
+ ]);
307
+ expect(lastIpcCall()?.params).toEqual({
166
308
  pathParams: { name: "local-llm" },
167
309
  body: {
168
310
  auth: { type: "none" },
@@ -171,4 +313,99 @@ describe("providers connections update — openai-compatible", () => {
171
313
  },
172
314
  });
173
315
  });
316
+
317
+ test("an explicit --auth override forwards verbatim", async () => {
318
+ await run([
319
+ "providers",
320
+ "update",
321
+ "local-llm",
322
+ "--auth",
323
+ "none",
324
+ "--base-url",
325
+ "http://localhost:5678/v1",
326
+ ]);
327
+ expect(ipcCalls.map((c) => c.method)).toEqual([
328
+ "inference_provider_connections_update",
329
+ ]);
330
+ expect(lastIpcCall()?.params?.body).toEqual({
331
+ auth: { type: "none" },
332
+ base_url: "http://localhost:5678/v1",
333
+ });
334
+ });
335
+ });
336
+
337
+ describe("providers list output", () => {
338
+ test("shows providers without auth details", async () => {
339
+ mockIpcResult = {
340
+ ok: true,
341
+ result: {
342
+ connections: [
343
+ {
344
+ name: "vellum",
345
+ provider: "vellum",
346
+ auth: { type: "platform" },
347
+ },
348
+ {
349
+ name: "anthropic-personal",
350
+ provider: "anthropic",
351
+ auth: { type: "api_key", credential: "credential/anthropic/x" },
352
+ },
353
+ ],
354
+ },
355
+ };
356
+ const { stdout } = await run(["providers", "list"]);
357
+ expect(stdout).toContain("vellum provider=vellum");
358
+ expect(stdout).toContain("anthropic-personal provider=anthropic");
359
+ expect(stdout).not.toContain("auth=");
360
+ expect(stdout).not.toContain("api_key");
361
+ });
362
+
363
+ test("--json output keeps the full wire shape including auth", async () => {
364
+ mockIpcResult = {
365
+ ok: true,
366
+ result: {
367
+ connections: [
368
+ {
369
+ name: "anthropic-personal",
370
+ provider: "anthropic",
371
+ auth: { type: "api_key", credential: "credential/anthropic/x" },
372
+ },
373
+ ],
374
+ },
375
+ };
376
+ const { stdout } = await run(["providers", "list", "--json"]);
377
+ const parsed = JSON.parse(stdout);
378
+ expect(parsed.connections[0].auth).toEqual({
379
+ type: "api_key",
380
+ credential: "credential/anthropic/x",
381
+ });
382
+ });
383
+ });
384
+
385
+ describe("deprecated providers connections alias", () => {
386
+ test("connections create still forwards to the same route", async () => {
387
+ await run([
388
+ "providers",
389
+ "connections",
390
+ "create",
391
+ "anthropic-personal",
392
+ "--provider",
393
+ "anthropic",
394
+ "--credential",
395
+ "credential/anthropic/api_key",
396
+ ]);
397
+ expect(lastIpcCall()?.method).toBe("inference_provider_connections_create");
398
+ expect(lastIpcCall()?.params?.body).toEqual({
399
+ name: "anthropic-personal",
400
+ provider: "anthropic",
401
+ auth: { type: "api_key", credential: "credential/anthropic/api_key" },
402
+ });
403
+ });
404
+
405
+ test("connections list forwards to the same route", async () => {
406
+ mockIpcResult = { ok: true, result: { connections: [] } };
407
+ const { stdout } = await run(["providers", "connections", "list"]);
408
+ expect(lastIpcCall()?.method).toBe("inference_provider_connections_list");
409
+ expect(stdout).toContain("No providers found.");
410
+ });
174
411
  });
@@ -29,9 +29,15 @@ let ipcResponse: {
29
29
  };
30
30
 
31
31
  const exitCodeFromIpcResult = (r: { statusCode?: number }): number => {
32
- if (r.statusCode === undefined) return 10;
33
- if (r.statusCode >= 500) return 3;
34
- if (r.statusCode >= 400) return 2;
32
+ if (r.statusCode === undefined) {
33
+ return 10;
34
+ }
35
+ if (r.statusCode >= 500) {
36
+ return 3;
37
+ }
38
+ if (r.statusCode >= 400) {
39
+ return 2;
40
+ }
35
41
  return 1;
36
42
  };
37
43
 
@@ -518,6 +524,21 @@ describe("notifications list", () => {
518
524
  expect(ipcCalls[0].method).toBe("list_home_feed");
519
525
  });
520
526
 
527
+ test("list help disambiguates Vellum notifications from email inboxes", async () => {
528
+ const { stdout, exitCode } = await runRawCommand([
529
+ "notifications",
530
+ "list",
531
+ "--help",
532
+ ]);
533
+
534
+ expect(exitCode).toBe(0);
535
+ const normalizedHelp = stdout.replace(/\s+/g, " ");
536
+ expect(normalizedHelp).toContain("Vellum Home feed");
537
+ expect(normalizedHelp).toContain("does not read email inboxes");
538
+ expect(normalizedHelp).toContain("Gmail");
539
+ expect(normalizedHelp).toContain("Outlook");
540
+ });
541
+
521
542
  test("list returns items from IPC", async () => {
522
543
  ipcResponse = {
523
544
  ok: true,
@@ -19,9 +19,9 @@ and "assistant keys set <provider> <key>" to view and manage API keys.
19
19
 
20
20
  Examples:
21
21
  $ assistant config list
22
- $ assistant config get llm.default.provider
22
+ $ assistant config get llm.defaultProvider.provider
23
23
  $ assistant config schema services
24
- $ assistant config set llm.default.provider anthropic
24
+ $ assistant config set llm.defaultProvider.provider anthropic
25
25
  $ assistant config set calls.enabled true`,
26
26
  subcommands: [
27
27
  {
@@ -31,7 +31,7 @@ Examples:
31
31
  "Set a config value (supports dotted paths like calls.enabled)",
32
32
  helpText: `
33
33
  Arguments:
34
- key Dotted path to the config key (e.g. llm.default.provider,
34
+ key Dotted path to the config key (e.g. llm.defaultProvider.provider,
35
35
  calls.enabled, twilio.accountSid). Intermediate objects are created
36
36
  automatically.
37
37
  value The value to store. Parsed as JSON first (so "true" becomes boolean
@@ -46,7 +46,7 @@ explicit null is preserved.
46
46
  To manage API keys, use "assistant keys set <provider> <key>" instead.
47
47
 
48
48
  Examples:
49
- $ assistant config set llm.default.provider anthropic
49
+ $ assistant config set llm.defaultProvider.provider anthropic
50
50
  $ assistant config set calls.enabled true`,
51
51
  },
52
52
  {
@@ -55,7 +55,7 @@ Examples:
55
55
  description: "Get a config value (supports dotted paths)",
56
56
  helpText: `
57
57
  Arguments:
58
- key Dotted path to the config key (e.g. llm.default.provider,
58
+ key Dotted path to the config key (e.g. llm.defaultProvider.provider,
59
59
  calls.enabled)
60
60
 
61
61
  Fetches the full config from the assistant and prints the value at the
@@ -65,7 +65,7 @@ values are pretty-printed as indented JSON.
65
65
  To view API keys, use "assistant keys list" instead.
66
66
 
67
67
  Examples:
68
- $ assistant config get llm.default.provider
68
+ $ assistant config get llm.defaultProvider.provider
69
69
  $ assistant config get calls.enabled`,
70
70
  },
71
71
  {
@@ -191,6 +191,11 @@ Examples:
191
191
  flags: "--field <field>",
192
192
  description: "Field name",
193
193
  },
194
+ {
195
+ flags: "--for-chat",
196
+ description:
197
+ "Print a chat-safe reveal chip token instead of the plaintext",
198
+ },
194
199
  ],
195
200
  helpText: `
196
201
  Arguments:
@@ -204,10 +209,18 @@ captured with shell substitution.
204
209
  Use --service and --field to look up by service/field, or pass a UUID as a
205
210
  positional argument. One of the two forms is required.
206
211
 
212
+ With --for-chat, the plaintext is never printed: the command outputs the
213
+ credential's redaction chip token instead. Paste that token into a chat
214
+ reply to show the credential as a click-to-reveal chip — use it whenever
215
+ the goal is to SHOW a credential to the user in conversation rather than
216
+ to pipe its value into another tool. Requires the chat-credential-reveal
217
+ feature flag.
218
+
207
219
  Examples:
208
220
  $ assistant credentials reveal --service twilio --field auth_token
209
221
  $ assistant credentials reveal 7a3b1c2d-4e5f-6789-abcd-ef0123456789
210
222
  $ assistant credentials reveal --json --service twilio --field account_sid
223
+ $ assistant credentials reveal --for-chat --service twilio --field auth_token
211
224
  $ export TWILIO_TOKEN=$(assistant credentials reveal --service twilio --field auth_token)`,
212
225
  },
213
226
  {
@@ -359,7 +359,7 @@ export function registerCredentialsCommand(program: Command): void {
359
359
  subcommand(credential, "reveal").action(
360
360
  async (
361
361
  id: string | undefined,
362
- opts: { service?: string; field?: string },
362
+ opts: { service?: string; field?: string; forChat?: boolean },
363
363
  cmd: Command,
364
364
  ) => {
365
365
  if (!opts.service && !opts.field && !id) {
@@ -376,6 +376,11 @@ export function registerCredentialsCommand(program: Command): void {
376
376
  service: opts.service,
377
377
  field: opts.field,
378
378
  id,
379
+ ...(opts.forChat ? { forChat: true } : {}),
380
+ // Conversation-bound authority scope for the daemon's chat
381
+ // redaction seams (set by the shell tools; absent outside a
382
+ // conversation's tool shell, where no authority should exist).
383
+ revealNonce: process.env.__REVEAL_NONCE,
379
384
  },
380
385
  });
381
386
 
@@ -94,6 +94,10 @@ Examples:
94
94
  { flags: "--html <path>", description: "HTML body file (optional)" },
95
95
  { flags: "--cc <address>", description: "CC recipient (repeatable)" },
96
96
  { flags: "--bcc <address>", description: "BCC recipient (repeatable)" },
97
+ {
98
+ flags: "--attach <path>",
99
+ description: "File to attach (repeatable)",
100
+ },
97
101
  {
98
102
  flags: "--reply-to <email_id>",
99
103
  description:
@@ -127,6 +131,9 @@ Examples:
127
131
  $ assistant email send user@example.com -b "Thanks!" --reply-to 019d96e4-e5d2-7201-890e-04a21e8f95bb
128
132
  ✓ Sent to user@example.com (delivery_id: ghi789)
129
133
 
134
+ $ assistant email send user@example.com -s "Report" -b "Attached" --attach report.pdf --attach data.csv
135
+ ✓ Sent to user@example.com (delivery_id: jkl012)
136
+
130
137
  $ assistant email send user@example.com -s "Hello" -b "Hi" --json
131
138
  {"delivery_id":"abc123","status":"accepted"}`,
132
139
  },
@@ -14,6 +14,7 @@ import {
14
14
  cliIpcCallStream,
15
15
  exitFromIpcResult,
16
16
  } from "../../ipc/cli-client.js";
17
+ import { guessMimeType } from "../../util/mime-type.js";
17
18
  import { readStdinSync } from "../../util/read-stdin.js";
18
19
  import { applyCommandHelp, subcommand } from "../lib/cli-command-help.js";
19
20
  import { registerCommand } from "../lib/register-command.js";
@@ -402,7 +403,11 @@ Examples:
402
403
  // imperatively to the declaratively-registered options.
403
404
  const send = subcommand(email, "send");
404
405
  const collect = (val: string, prev: string[]) => [...prev, val];
405
- for (const flags of ["--cc <address>", "--bcc <address>"]) {
406
+ for (const flags of [
407
+ "--cc <address>",
408
+ "--bcc <address>",
409
+ "--attach <path>",
410
+ ]) {
406
411
  const option = send.options.find((o) => o.flags === flags);
407
412
  if (!option) {
408
413
  throw new Error(
@@ -422,6 +427,7 @@ Examples:
422
427
  html?: string;
423
428
  cc?: string[];
424
429
  bcc?: string[];
430
+ attach?: string[];
425
431
  replyTo?: string;
426
432
  },
427
433
  cmd: Command,
@@ -472,6 +478,31 @@ Examples:
472
478
  }
473
479
  }
474
480
 
481
+ // Read attachments and base64-encode their content for the JSON
482
+ // wire to the platform proxy.
483
+ let attachments:
484
+ | { filename: string; content_type: string; content: string }[]
485
+ | undefined;
486
+ if (opts.attach && opts.attach.length > 0) {
487
+ attachments = [];
488
+ for (const path of opts.attach) {
489
+ try {
490
+ const data = readFileSync(path);
491
+ attachments.push({
492
+ filename: basename(path),
493
+ content_type: guessMimeType(path),
494
+ content: data.toString("base64"),
495
+ });
496
+ } catch (err) {
497
+ log.error(
498
+ `Failed to read --attach ${path}: ${err instanceof Error ? err.message : String(err)}`,
499
+ );
500
+ process.exitCode = 1;
501
+ return;
502
+ }
503
+ }
504
+ }
505
+
475
506
  const params: Record<string, unknown> = { to, text };
476
507
  if (opts.subject) {
477
508
  params.subject = opts.subject;
@@ -485,6 +516,9 @@ Examples:
485
516
  if (opts.bcc && opts.bcc.length > 0) {
486
517
  params.bcc = opts.bcc;
487
518
  }
519
+ if (attachments && attachments.length > 0) {
520
+ params.attachments = attachments;
521
+ }
488
522
  if (opts.replyTo) {
489
523
  params.reply_to = opts.replyTo;
490
524
  }