@vellumai/assistant 0.11.1 → 0.11.2-dev.202608042227.b54139c

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 (514) hide show
  1. package/Dockerfile +1 -3
  2. package/README.md +1 -1
  3. package/eslint.config.mjs +28 -8
  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__/stripe-currency.test.ts +37 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  7. package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
  8. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
  9. package/node_modules/@vellumai/environments/src/index.ts +17 -6
  10. package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
  11. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
  13. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  14. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  15. package/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
  16. package/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  17. package/node_modules/@vellumai/slack-text/src/index.test.ts +48 -0
  18. package/node_modules/@vellumai/slack-text/src/index.ts +41 -8
  19. package/openapi.yaml +442 -8
  20. package/package.json +1 -1
  21. package/src/__tests__/agent-image-optimize.test.ts +4 -4
  22. package/src/__tests__/agent-loop-resume-interrupted.test.ts +223 -0
  23. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
  24. package/src/__tests__/answered-question-persistence.test.ts +240 -0
  25. package/src/__tests__/assistant-feature-flags-integration.test.ts +10 -0
  26. package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
  27. package/src/__tests__/attachments-store.test.ts +130 -68
  28. package/src/__tests__/attachments.test.ts +36 -36
  29. package/src/__tests__/byok-default-profile-ensure.test.ts +43 -0
  30. package/src/__tests__/cli-logger-boundary-guard.test.ts +87 -0
  31. package/src/__tests__/compaction-events.test.ts +139 -2
  32. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  33. package/src/__tests__/compactor-truncation-pairing.test.ts +368 -0
  34. package/src/__tests__/config-loader-backfill.test.ts +35 -3
  35. package/src/__tests__/config-schema.test.ts +1 -0
  36. package/src/__tests__/consult-deadline.test.ts +65 -0
  37. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +30 -0
  38. package/src/__tests__/conversation-agent-loop.test.ts +255 -8
  39. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
  40. package/src/__tests__/conversation-disk-view.test.ts +4 -4
  41. package/src/__tests__/conversation-error.test.ts +211 -4
  42. package/src/__tests__/conversation-fork-crud.test.ts +5 -1
  43. package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
  44. package/src/__tests__/conversation-options-turn-scoped-transport.test.ts +64 -0
  45. package/src/__tests__/conversation-queue.test.ts +255 -1
  46. package/src/__tests__/conversation-retry-route.test.ts +46 -7
  47. package/src/__tests__/conversation-slash.test.ts +4 -2
  48. package/src/__tests__/conversation-store.test.ts +26 -10
  49. package/src/__tests__/conversation-summarize-route.test.ts +7 -1
  50. package/src/__tests__/conversation-summarize-up-to.test.ts +71 -5
  51. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +10 -0
  52. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +969 -0
  53. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  54. package/src/__tests__/cu-unified-flow.test.ts +75 -11
  55. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  56. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  57. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  58. package/src/__tests__/disk-usage.test.ts +35 -20
  59. package/src/__tests__/document-create-dedupe.test.ts +2 -1
  60. package/src/__tests__/document-find-replace.test.ts +2 -1
  61. package/src/__tests__/document-tool-security.test.ts +2 -1
  62. package/src/__tests__/document-update-default-surface.test.ts +2 -1
  63. package/src/__tests__/document-workspace-file.test.ts +467 -0
  64. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  65. package/src/__tests__/emit-signal-routing-intent.test.ts +290 -49
  66. package/src/__tests__/file-list-tool.test.ts +12 -10
  67. package/src/__tests__/file-ops-service.test.ts +76 -40
  68. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  69. package/src/__tests__/filesystem-tools.test.ts +82 -66
  70. package/src/__tests__/guardian-card-withdrawal.test.ts +91 -3
  71. package/src/__tests__/history-repair.test.ts +39 -0
  72. package/src/__tests__/http-user-message-parity.test.ts +66 -0
  73. package/src/__tests__/identity-routes.test.ts +13 -13
  74. package/src/__tests__/image-conversion.test.ts +29 -26
  75. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  76. package/src/__tests__/list-messages-attachments.test.ts +139 -28
  77. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  78. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  79. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  80. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  81. package/src/__tests__/list-messages-provider-error.test.ts +143 -0
  82. package/src/__tests__/list-messages-queued.test.ts +6 -6
  83. package/src/__tests__/list-messages-system-card.test.ts +100 -0
  84. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  85. package/src/__tests__/llm-resolver.test.ts +19 -9
  86. package/src/__tests__/llm-usage-store.test.ts +55 -0
  87. package/src/__tests__/managed-profile-guard.test.ts +23 -0
  88. package/src/__tests__/migration-export-http.test.ts +1 -1
  89. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  90. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  91. package/src/__tests__/migration-validate-http.test.ts +1 -1
  92. package/src/__tests__/notification-platform-adapter.test.ts +130 -2
  93. package/src/__tests__/notification-telegram-adapter.test.ts +6 -0
  94. package/src/__tests__/notification-vellum-adapter.test.ts +45 -0
  95. package/src/__tests__/persist-media-references.test.ts +2 -2
  96. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  97. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  98. package/src/__tests__/plugin-api-model-profiles.test.ts +10 -1
  99. package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -0
  100. package/src/__tests__/profiler-routes.test.ts +13 -13
  101. package/src/__tests__/provider-error-scenarios.test.ts +140 -0
  102. package/src/__tests__/provider-send-message-override-profile.test.ts +95 -0
  103. package/src/__tests__/run-conversation-turn-persistence.test.ts +66 -3
  104. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  105. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +209 -0
  106. package/src/__tests__/server-history-render.test.ts +97 -7
  107. package/src/__tests__/size-guard.test.ts +8 -8
  108. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  109. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  110. package/src/__tests__/skills-install-staging.test.ts +15 -6
  111. package/src/__tests__/skills.test.ts +27 -0
  112. package/src/__tests__/slack-channels-routes.test.ts +0 -2
  113. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  114. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  115. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  116. package/src/__tests__/slack-share-routes.test.ts +0 -3
  117. package/src/__tests__/slack-users-routes.test.ts +0 -2
  118. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  119. package/src/__tests__/subagent-disposal.test.ts +10 -0
  120. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  121. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  122. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  123. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  124. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  125. package/src/__tests__/subagent-persistence.test.ts +141 -0
  126. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  127. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  128. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  129. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  130. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  131. package/src/__tests__/subagent-tool-gate-mode.test.ts +215 -0
  132. package/src/__tests__/subagent-tools.test.ts +1945 -97
  133. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  134. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  135. package/src/__tests__/tool-preview-lifecycle.test.ts +58 -0
  136. package/src/__tests__/tool-result-spool.test.ts +5 -4
  137. package/src/__tests__/tools-audio-read.test.ts +10 -10
  138. package/src/__tests__/tools-get-route.test.ts +85 -12
  139. package/src/__tests__/tools-list-cli.test.ts +171 -0
  140. package/src/__tests__/turn-boundary-resolution.test.ts +53 -0
  141. package/src/__tests__/turn-events-store.test.ts +26 -0
  142. package/src/__tests__/ui-visual-surface.test.ts +695 -0
  143. package/src/__tests__/unified-turn-context-visible-app.test.ts +99 -0
  144. package/src/__tests__/visible-app-context.test.ts +189 -0
  145. package/src/__tests__/workspace-git-service.test.ts +173 -33
  146. package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +157 -0
  147. package/src/__tests__/workspace-migration-138-backfill-home-feed-titles.test.ts +373 -0
  148. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +137 -0
  149. package/src/agent/attachments.ts +26 -24
  150. package/src/agent/history-repair/history-repair.ts +8 -0
  151. package/src/agent/image-optimize.ts +6 -6
  152. package/src/agent/loop.ts +57 -16
  153. package/src/agent/message-types.ts +3 -3
  154. package/src/api/events/context-window-usage.ts +31 -0
  155. package/src/api/events/notification-intent.ts +8 -0
  156. package/src/api/events/question-answered.ts +53 -0
  157. package/src/api/events/tool-result.ts +7 -0
  158. package/src/api/events/ui-surface-pending.ts +35 -0
  159. package/src/api/index.ts +20 -0
  160. package/src/api/responses/conversation-message.ts +36 -4
  161. package/src/api/surfaces.ts +90 -1
  162. package/src/approvals/guardian-card-withdrawal.ts +66 -31
  163. package/src/approvals/guardian-decision-primitive.ts +4 -0
  164. package/src/calls/__tests__/call-setup-router.test.ts +156 -26
  165. package/src/calls/__tests__/voice-session-bridge.test.ts +201 -12
  166. package/src/calls/call-setup-router.ts +80 -36
  167. package/src/calls/voice-session-bridge.ts +173 -26
  168. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  169. package/src/cli/commands/inference.help.ts +3 -3
  170. package/src/cli/commands/mcp.help.ts +4 -2
  171. package/src/cli/commands/notifications.help.ts +3 -2
  172. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +42 -128
  173. package/src/cli/commands/platform/__tests__/credits.test.ts +9 -78
  174. package/src/cli/commands/platform/__tests__/helpers.ts +90 -0
  175. package/src/cli/commands/platform/__tests__/invoices.test.ts +238 -0
  176. package/src/cli/commands/platform/__tests__/plans.test.ts +9 -88
  177. package/src/cli/commands/platform/__tests__/status.test.ts +12 -87
  178. package/src/cli/commands/platform/__tests__/subscription.test.ts +9 -86
  179. package/src/cli/commands/platform/index.help.ts +92 -0
  180. package/src/cli/commands/platform/index.ts +7 -0
  181. package/src/cli/commands/platform/invoices.ts +132 -0
  182. package/src/cli/commands/tools.help.ts +4 -2
  183. package/src/cli/commands/tools.ts +38 -0
  184. package/src/cli/commands/usage.help.ts +1 -1
  185. package/src/cli/lib/list-installed-plugins.ts +2 -1
  186. package/src/config/__tests__/default-profile-catalog.test.ts +7 -10
  187. package/src/config/__tests__/deployment-context-defaults.test.ts +27 -5
  188. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  189. package/src/config/assistant-feature-flags.ts +7 -2
  190. package/src/config/bundled-skills/AGENTS.md +1 -1
  191. package/src/config/bundled-skills/app-builder/SKILL.md +3 -2
  192. package/src/config/bundled-skills/media-processing/SKILL.md +1 -1
  193. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -1
  194. package/src/config/bundled-skills/media-processing/__tests__/media-analysis-default-model.test.ts +177 -0
  195. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +4 -3
  196. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -1
  197. package/src/config/bundled-skills/media-processing/services/media-analysis-model.ts +12 -0
  198. package/src/config/bundled-skills/subagent/SKILL.md +55 -22
  199. package/src/config/bundled-skills/subagent/TOOLS.json +15 -14
  200. package/src/config/bundled-skills/visualize/SKILL.md +163 -0
  201. package/src/config/call-site-defaults.ts +3 -2
  202. package/src/config/default-profile-catalog.ts +75 -70
  203. package/src/config/default-profile-names.ts +13 -28
  204. package/src/config/env-registry.ts +1 -0
  205. package/src/config/feature-flag-registry.json +32 -8
  206. package/src/config/llm-resolver.ts +25 -8
  207. package/src/config/loader.ts +18 -11
  208. package/src/config/profile-tool-support.ts +110 -0
  209. package/src/config/schemas/llm.ts +1 -9
  210. package/src/config/schemas/memory-retrospective.ts +9 -0
  211. package/src/config/schemas/monitoring.ts +28 -2
  212. package/src/config/schemas/workspace-git.ts +15 -0
  213. package/src/config/seed-inference-profiles.ts +19 -5
  214. package/src/context/compactor.ts +45 -8
  215. package/src/context/post-turn-tool-result-truncation.ts +2 -2
  216. package/src/conversations/__tests__/message-consolidation.test.ts +54 -0
  217. package/src/conversations/message-consolidation.ts +17 -15
  218. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  219. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  220. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +182 -0
  221. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +181 -0
  222. package/src/daemon/conversation-agent-loop-handlers.ts +204 -64
  223. package/src/daemon/conversation-agent-loop.ts +115 -23
  224. package/src/daemon/conversation-attachments.ts +1 -1
  225. package/src/daemon/conversation-error.ts +169 -48
  226. package/src/daemon/conversation-lifecycle.ts +119 -17
  227. package/src/daemon/conversation-messaging.ts +118 -30
  228. package/src/daemon/conversation-process.ts +91 -64
  229. package/src/daemon/conversation-runtime-assembly.ts +57 -0
  230. package/src/daemon/conversation-store.ts +36 -1
  231. package/src/daemon/conversation-surface-state.ts +9 -0
  232. package/src/daemon/conversation-surfaces.ts +476 -108
  233. package/src/daemon/conversation-tool-setup.ts +54 -2
  234. package/src/daemon/conversation-turn-finalize.ts +76 -18
  235. package/src/daemon/conversation.ts +151 -29
  236. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  237. package/src/daemon/disk-pressure-guard.ts +3 -3
  238. package/src/daemon/handlers/shared.ts +12 -0
  239. package/src/daemon/handlers/skills.ts +1 -1
  240. package/src/daemon/install-assistant-command.ts +322 -0
  241. package/src/daemon/lifecycle.ts +12 -3
  242. package/src/daemon/message-types/conversations.ts +8 -0
  243. package/src/daemon/message-types/surfaces.ts +3 -0
  244. package/src/daemon/persist-media-references.ts +23 -14
  245. package/src/daemon/process-message.ts +6 -6
  246. package/src/daemon/tool-setup-types.ts +31 -2
  247. package/src/documents/document-store.ts +247 -10
  248. package/src/home/__tests__/feed-types.test.ts +43 -8
  249. package/src/home/__tests__/feed-writer.test.ts +59 -0
  250. package/src/home/feed-types.ts +34 -7
  251. package/src/home/feed-writer.ts +15 -6
  252. package/src/live-voice/__tests__/activity-label.test.ts +95 -0
  253. package/src/live-voice/__tests__/live-activity-reporter.test.ts +86 -5
  254. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +310 -25
  255. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  256. package/src/live-voice/__tests__/live-voice-events.test.ts +4 -4
  257. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  258. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +8 -4
  259. package/src/live-voice/__tests__/live-voice-vad.test.ts +44 -16
  260. package/src/live-voice/activity-label.ts +169 -0
  261. package/src/live-voice/live-activity-reporter.ts +35 -6
  262. package/src/live-voice/live-voice-archive.ts +13 -13
  263. package/src/live-voice/live-voice-session.ts +288 -41
  264. package/src/live-voice/protocol.ts +35 -0
  265. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +84 -2
  266. package/src/messaging/providers/slack/adapter.ts +86 -19
  267. package/src/messaging/providers/slack/api.test.ts +85 -1
  268. package/src/messaging/providers/slack/api.ts +121 -288
  269. package/src/messaging/providers/slack/client.ts +20 -251
  270. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  271. package/src/messaging/providers/slack/mention-source.ts +287 -0
  272. package/src/messaging/providers/slack/send.test.ts +4 -9
  273. package/src/messaging/providers/slack/send.ts +1 -1
  274. package/src/messaging/providers/slack/types.ts +5 -0
  275. package/src/messaging/providers/slack/web-api-transport.test.ts +181 -0
  276. package/src/messaging/providers/slack/web-api-transport.ts +367 -0
  277. package/src/messaging/providers/slack/withdraw.ts +6 -14
  278. package/src/messaging/providers/telegram-bot/send.test.ts +31 -1
  279. package/src/messaging/providers/telegram-bot/send.ts +23 -2
  280. package/src/messaging/providers/telegram-bot/withdraw.test.ts +152 -0
  281. package/src/messaging/providers/telegram-bot/withdraw.ts +166 -0
  282. package/src/monitoring/__tests__/db-integrity-sample.test.ts +22 -5
  283. package/src/monitoring/__tests__/file-descriptors.test.ts +144 -0
  284. package/src/monitoring/db-integrity-sample.ts +6 -1
  285. package/src/monitoring/file-descriptors.ts +262 -0
  286. package/src/monitoring/process-memory.ts +4 -11
  287. package/src/monitoring/resource-sampler.ts +26 -5
  288. package/src/monitoring/worker.ts +12 -0
  289. package/src/notifications/__tests__/assistant-reply-producer.test.ts +740 -0
  290. package/src/notifications/__tests__/broadcaster.test.ts +347 -7
  291. package/src/notifications/__tests__/copy-composer.test.ts +53 -3
  292. package/src/notifications/__tests__/decision-engine.test.ts +349 -29
  293. package/src/notifications/__tests__/deterministic-checks.test.ts +21 -0
  294. package/src/notifications/__tests__/edit-notification.test.ts +330 -0
  295. package/src/notifications/__tests__/guardian-delivery-recorder.test.ts +71 -0
  296. package/src/notifications/__tests__/home-feed-side-effect.test.ts +170 -12
  297. package/src/notifications/adapters/macos.ts +3 -0
  298. package/src/notifications/adapters/platform.ts +90 -14
  299. package/src/notifications/adapters/telegram.ts +6 -4
  300. package/src/notifications/assistant-reply-producer.ts +219 -0
  301. package/src/notifications/broadcaster.ts +523 -317
  302. package/src/notifications/copy-composer.ts +27 -6
  303. package/src/notifications/decision-engine.ts +154 -77
  304. package/src/notifications/deterministic-checks.ts +6 -7
  305. package/src/notifications/edit-notification.ts +8 -4
  306. package/src/notifications/emit-signal.ts +49 -16
  307. package/src/notifications/guardian-delivery-recorder.ts +8 -2
  308. package/src/notifications/home-feed-side-effect.ts +43 -6
  309. package/src/notifications/notification-utils.ts +39 -4
  310. package/src/notifications/signal.ts +10 -0
  311. package/src/notifications/types.ts +17 -0
  312. package/src/permissions/question-prompter.test.ts +4 -0
  313. package/src/permissions/question-prompter.ts +21 -4
  314. package/src/persistence/attachments-store.ts +15 -15
  315. package/src/persistence/bookmark-crud.ts +18 -9
  316. package/src/persistence/conversation-attention-store.ts +26 -0
  317. package/src/persistence/conversation-bootstrap.ts +17 -0
  318. package/src/persistence/conversation-crud.ts +89 -32
  319. package/src/persistence/conversation-queries.ts +30 -15
  320. package/src/persistence/conversation-title-service.ts +5 -170
  321. package/src/persistence/conversation-types.ts +192 -1
  322. package/src/persistence/db-init.ts +14 -1
  323. package/src/persistence/db-maintenance.ts +5 -4
  324. package/src/persistence/embeddings/__tests__/plugin-index-qdrant-init.test.ts +219 -0
  325. package/src/persistence/embeddings/__tests__/plugin-index.test.ts +22 -0
  326. package/src/persistence/embeddings/__tests__/worker-script-version.test.ts +76 -0
  327. package/src/persistence/embeddings/embedding-local.ts +2 -1
  328. package/src/persistence/embeddings/embedding-runtime-manager.ts +29 -5
  329. package/src/persistence/embeddings/plugin-index.ts +84 -12
  330. package/src/persistence/llm-usage-store.ts +22 -0
  331. package/src/persistence/migrations/360-add-document-workspace-path.test.ts +110 -0
  332. package/src/persistence/migrations/360-add-document-workspace-path.ts +39 -0
  333. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  334. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  335. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  336. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  337. package/src/persistence/planner-statistics.ts +14 -0
  338. package/src/persistence/schema/conversations.ts +22 -0
  339. package/src/persistence/schema/documents.ts +26 -11
  340. package/src/persistence/steps.ts +19 -0
  341. package/src/persistence/subagent-store.ts +148 -6
  342. package/src/platform/client.test.ts +172 -2
  343. package/src/platform/client.ts +178 -55
  344. package/src/plugin-api/conversation-turn.ts +13 -0
  345. package/src/plugin-api/model-profiles.test.ts +6 -2
  346. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  347. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  348. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  349. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  350. package/src/plugins/defaults/index.ts +1 -1
  351. package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +34 -0
  352. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +22 -0
  353. package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +11 -0
  354. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +199 -0
  355. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +98 -1
  356. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +105 -1
  357. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +24 -2
  358. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +524 -0
  359. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1 -1
  360. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +9 -4
  361. package/src/plugins/defaults/memory/host-utils.ts +5 -0
  362. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +105 -1
  363. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +64 -5
  364. package/src/plugins/defaults/memory/memory-retrospective-job.ts +36 -1
  365. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +12 -3
  366. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +1 -0
  367. package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +195 -1
  368. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +1 -1
  369. package/src/plugins/defaults/memory/substrate/skill-store.ts +167 -29
  370. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  371. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +131 -0
  372. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1 -0
  373. package/src/plugins/defaults/memory/v2/activation-log-store.ts +4 -0
  374. package/src/plugins/defaults/memory/v2/injection.ts +48 -3
  375. package/src/plugins/defaults/memory/v2/rerank-local.ts +6 -2
  376. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -1
  377. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +1 -1
  378. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  379. package/src/plugins/defaults/turn-context/unified-turn-context.ts +26 -0
  380. package/src/plugins/types.ts +17 -0
  381. package/src/prompts/templates/system-sections.ts +2 -2
  382. package/src/providers/__tests__/dispatch-connection-routing.test.ts +43 -2
  383. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  384. package/src/providers/__tests__/vellum-connection-routing.test.ts +5 -10
  385. package/src/providers/__tests__/vellum-mismatch-routing.test.ts +8 -0
  386. package/src/providers/anthropic/client.ts +6 -4
  387. package/src/providers/call-site-routing.ts +77 -14
  388. package/src/providers/connection-resolution.ts +42 -2
  389. package/src/providers/gemini/client.ts +5 -5
  390. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +127 -1
  391. package/src/providers/inference/adapter-factory.ts +71 -12
  392. package/src/providers/media-resolve.ts +21 -11
  393. package/src/providers/model-catalog.ts +0 -11
  394. package/src/providers/model-intents.ts +11 -0
  395. package/src/providers/openai/__tests__/orphan-tool-result-guard.test.ts +478 -0
  396. package/src/providers/openai/chat-completions-provider.ts +50 -34
  397. package/src/providers/openai/orphaned-tool-result.ts +79 -0
  398. package/src/providers/openai/responses-provider.ts +53 -27
  399. package/src/providers/registry.ts +8 -0
  400. package/src/providers/retry.ts +110 -17
  401. package/src/providers/types.ts +8 -1
  402. package/src/providers/vellum-model-routing.ts +6 -7
  403. package/src/runtime/AGENTS.md +2 -0
  404. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  405. package/src/runtime/agent-wake.ts +132 -9
  406. package/src/runtime/channel-approval-types.ts +25 -0
  407. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +2 -2
  408. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +11 -0
  409. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +121 -9
  410. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  411. package/src/runtime/routes/__tests__/platform-invoice-routes.test.ts +392 -0
  412. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  413. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +7 -0
  414. package/src/runtime/routes/__tests__/workspace-commit-routes.test.ts +63 -0
  415. package/src/runtime/routes/archive-utils.ts +16 -12
  416. package/src/runtime/routes/attachment-routes.ts +13 -6
  417. package/src/runtime/routes/consolidation-routes.ts +1 -1
  418. package/src/runtime/routes/conversation-management-routes.ts +18 -6
  419. package/src/runtime/routes/conversation-query-routes.ts +14 -23
  420. package/src/runtime/routes/conversation-routes.ts +297 -181
  421. package/src/runtime/routes/credential-routes.ts +1 -5
  422. package/src/runtime/routes/documents-routes.ts +207 -12
  423. package/src/runtime/routes/identity-routes.ts +9 -99
  424. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  425. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +31 -1
  426. package/src/runtime/routes/inbound-stages/admission-policy.ts +18 -0
  427. package/src/runtime/routes/inference-profiles-routes.ts +1 -1
  428. package/src/runtime/routes/inference-provider-connection-routes.ts +52 -19
  429. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  430. package/src/runtime/routes/log-export-routes.ts +1 -1
  431. package/src/runtime/routes/notification-routes.ts +4 -1
  432. package/src/runtime/routes/platform-routes.ts +238 -3
  433. package/src/runtime/routes/playground/guard.ts +1 -2
  434. package/src/runtime/routes/profiler-routes.ts +4 -2
  435. package/src/runtime/routes/question-routes.ts +28 -10
  436. package/src/runtime/routes/secret-routes.ts +8 -2
  437. package/src/runtime/routes/settings-routes.ts +41 -13
  438. package/src/runtime/routes/slack-channel-routes.ts +2 -4
  439. package/src/runtime/routes/workspace-commit-routes.ts +49 -2
  440. package/src/runtime/routes/workspace-routes.ts +11 -12
  441. package/src/runtime/routes/workspace-utils.ts +49 -2
  442. package/src/runtime/services/conversation-serializer.ts +2 -4
  443. package/src/skills/catalog-install.ts +20 -7
  444. package/src/skills/skillssh-registry.ts +1 -1
  445. package/src/subagent/__tests__/consult-context-gating.test.ts +98 -0
  446. package/src/subagent/__tests__/consult-context-skills.test.ts +82 -0
  447. package/src/subagent/__tests__/consult-context.test.ts +84 -0
  448. package/src/subagent/__tests__/consult-prompt.test.ts +61 -0
  449. package/src/subagent/consult-context.ts +410 -0
  450. package/src/subagent/consult-prompt.ts +41 -6
  451. package/src/subagent/consult-transcript.ts +1 -1
  452. package/src/subagent/manager.ts +288 -46
  453. package/src/subagent/progress-events.ts +35 -0
  454. package/src/subagent/role-resolution.ts +88 -0
  455. package/src/subagent/types.ts +303 -67
  456. package/src/subagent/validate-allowlists.ts +3 -4
  457. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  458. package/src/telemetry/telemetry-event-sources.ts +13 -0
  459. package/src/telemetry/telemetry-wire-source.json +1 -1
  460. package/src/telemetry/telemetry-wire.generated.ts +3 -0
  461. package/src/telemetry/turn-events-store.ts +30 -1
  462. package/src/telemetry/types.ts +44 -0
  463. package/src/telemetry/usage-telemetry-reporter.test.ts +52 -0
  464. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  465. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  466. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  467. package/src/tools/browser/browser-execution.ts +1 -1
  468. package/src/tools/browser/pinned-tabs.ts +3 -1
  469. package/src/tools/executor.ts +7 -6
  470. package/src/tools/filesystem/edit.ts +1 -1
  471. package/src/tools/filesystem/list.ts +1 -1
  472. package/src/tools/filesystem/read.ts +1 -1
  473. package/src/tools/filesystem/search.ts +23 -21
  474. package/src/tools/filesystem/write.ts +4 -1
  475. package/src/tools/host-filesystem/edit.ts +1 -1
  476. package/src/tools/host-filesystem/read.ts +1 -1
  477. package/src/tools/host-filesystem/write.ts +4 -1
  478. package/src/tools/permission-checker.ts +8 -3
  479. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  480. package/src/tools/shared/filesystem/file-ops-service.ts +140 -113
  481. package/src/tools/shared/filesystem/image-read.ts +12 -12
  482. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  483. package/src/tools/shared/input-misuse.ts +72 -0
  484. package/src/tools/skills/skill-tool-factory.ts +14 -1
  485. package/src/tools/subagent/consult-deadline.ts +12 -7
  486. package/src/tools/subagent/read.ts +66 -4
  487. package/src/tools/subagent/spawn.ts +541 -51
  488. package/src/tools/terminal/safe-env.ts +1 -0
  489. package/src/tools/types.ts +9 -0
  490. package/src/tools/ui-surface/definitions.ts +39 -1
  491. package/src/tools/ui-surface/surface-shape-docs.ts +38 -4
  492. package/src/tools/ui-surface/visual-validation.ts +789 -0
  493. package/src/tools/workflows/run-workflow.test.ts +1 -0
  494. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  495. package/src/usage/subagent-attribution.ts +108 -0
  496. package/src/util/__tests__/short-title.test.ts +229 -0
  497. package/src/util/__tests__/worker-compute.test.ts +65 -0
  498. package/src/util/abort-reasons.ts +16 -0
  499. package/src/util/cgroup-cpu.ts +93 -0
  500. package/src/util/disk-usage.ts +17 -13
  501. package/src/util/errors.ts +27 -0
  502. package/src/util/image-conversion.ts +20 -13
  503. package/src/util/process-tree.ts +19 -0
  504. package/src/util/short-title.ts +189 -0
  505. package/src/util/worker-compute.ts +83 -0
  506. package/src/util/worker-process.ts +7 -1
  507. package/src/workspace/byok-default-profile-ensure.ts +25 -15
  508. package/src/workspace/git-service.ts +89 -39
  509. package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +131 -0
  510. package/src/workspace/migrations/138-backfill-home-feed-titles.ts +179 -0
  511. package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +92 -0
  512. package/src/workspace/migrations/registry.ts +6 -0
  513. package/src/daemon/install-symlink.ts +0 -207
  514. package/src/plugins/defaults/memory/substrate/constants.ts +0 -8
package/Dockerfile CHANGED
@@ -22,9 +22,7 @@ ENV PATH="/root/.bun/bin:${PATH}"
22
22
  # Note that we don't need source code to resolve cross-workspace dependencies.
23
23
  COPY package.json bun.lock ./
24
24
  COPY patches ./patches
25
- COPY clients/docs/package.json ./clients/docs/
26
- COPY clients/macos/package.json ./clients/macos/
27
- COPY clients/web/package.json ./clients/web/
25
+ COPY --parents clients/*/package.json ./
28
26
  COPY cli/package.json ./cli/
29
27
  COPY gateway/package.json ./gateway/
30
28
  COPY credential-executor/package.json ./credential-executor/
package/README.md CHANGED
@@ -28,7 +28,7 @@ For assistant architecture deep dives, see [`ARCHITECTURE.md`](ARCHITECTURE.md)
28
28
 
29
29
  ```bash
30
30
  cd assistant
31
- bun install
31
+ bun install # installs the whole workspace
32
32
  cp .env.example .env
33
33
  # Edit .env with your API keys
34
34
  ```
package/eslint.config.mjs CHANGED
@@ -49,14 +49,29 @@ const eslintConfig = defineConfig([
49
49
  "@typescript-eslint/no-explicit-any": "off",
50
50
  },
51
51
  },
52
- // Managed-column profile resolution (`getEffectiveProfile(s)`) resolves
53
- // default profiles against the vellum column only, ignoring
54
- // `llm.defaultProvider`; on a BYO install that is not the body that
55
- // dispatches. Runtime code must use `resolveDefaultProfileForProvider` /
56
- // `getEffectiveProfilesForProvider` instead. The allowlist below is the
57
- // full set of intentional managed-column consumers: the catalog itself,
58
- // hatch-time seeding (writes managed stubs by design), and write-path
59
- // validation.
52
+ // Two unrelated import bans share one `no-restricted-imports` entry on
53
+ // purpose: flat config replaces rule options rather than merging them, so a
54
+ // second block setting the same rule over overlapping files would silently
55
+ // drop the first one's patterns.
56
+ //
57
+ // 1. Managed-column profile resolution (`getEffectiveProfile(s)`) resolves
58
+ // default profiles against the vellum column only, ignoring
59
+ // `llm.defaultProvider`; on a BYO install that is not the body that
60
+ // dispatches. Runtime code must use `resolveDefaultProfileForProvider` /
61
+ // `getEffectiveProfilesForProvider` instead. The allowlist below is the
62
+ // full set of intentional managed-column consumers: the catalog itself,
63
+ // hatch-time seeding (writes managed stubs by design), and write-path
64
+ // validation.
65
+ //
66
+ // 2. `cli/logger` is the plain-stdout writer for short-lived `assistant …`
67
+ // invocations. It has no level filtering and no log-file routing, so a
68
+ // daemon-side module reaching for it writes debug output straight to a
69
+ // stdout the daemon may not own. Daemon code uses `getLogger()` from
70
+ // `util/logger.js`. The pattern matches on the import specifier, so
71
+ // CLI-internal files (which reach their logger relatively, as
72
+ // `../logger.js`) are unaffected. The companion guard test
73
+ // `src/__tests__/cli-logger-boundary-guard.test.ts` enforces the same
74
+ // boundary by resolved path, independent of how a specifier is spelled.
60
75
  {
61
76
  files: ["src/**/*.ts"],
62
77
  ignores: [
@@ -77,6 +92,11 @@ const eslintConfig = defineConfig([
77
92
  message:
78
93
  "Managed-column resolution ignores llm.defaultProvider. Use resolveDefaultProfileForProvider / getEffectiveProfilesForProvider with the parsed config's llm.defaultProvider ?? null.",
79
94
  },
95
+ {
96
+ group: ["**/cli/logger.js"],
97
+ message:
98
+ "cli/logger writes unfiltered plain text to stdout and is for src/cli/ only. Daemon and shared modules must use getLogger() from util/logger.js so output is level-filtered and routed to the log file. Within src/cli/, import the logger relatively (../logger.js).",
99
+ },
80
100
  ],
81
101
  },
82
102
  ],
@@ -19,6 +19,7 @@
19
19
  "./attachment-naming": "./src/attachment-naming.ts",
20
20
  "./redacted-credential": "./src/redacted-credential.ts",
21
21
  "./secret-detection": "./src/secret-detection.ts",
22
+ "./stripe-currency": "./src/stripe-currency.ts",
22
23
  "./error": "./src/error.ts"
23
24
  },
24
25
  "scripts": {
@@ -0,0 +1,37 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ STRIPE_THREE_DECIMAL_CURRENCIES,
5
+ STRIPE_ZERO_DECIMAL_CURRENCIES,
6
+ stripeScaleDigits,
7
+ } from "../stripe-currency.js";
8
+
9
+ describe("stripeScaleDigits", () => {
10
+ test("zero-decimal currencies scale to 0 digits", () => {
11
+ expect(stripeScaleDigits("JPY")).toBe(0);
12
+ expect(stripeScaleDigits("KRW")).toBe(0);
13
+ });
14
+
15
+ test("three-decimal currencies scale to 3 digits", () => {
16
+ expect(stripeScaleDigits("BHD")).toBe(3);
17
+ expect(stripeScaleDigits("KWD")).toBe(3);
18
+ });
19
+
20
+ test("everything else scales to 2 digits", () => {
21
+ expect(stripeScaleDigits("USD")).toBe(2);
22
+ expect(stripeScaleDigits("EUR")).toBe(2);
23
+ expect(stripeScaleDigits("XYZ")).toBe(2);
24
+ });
25
+
26
+ test("Stripe's charge-side two-decimal special cases stay at 2 digits", () => {
27
+ for (const code of ["ISK", "HUF", "TWD", "UGX"]) {
28
+ expect(stripeScaleDigits(code)).toBe(2);
29
+ }
30
+ });
31
+
32
+ test("the currency sets do not overlap", () => {
33
+ for (const code of STRIPE_ZERO_DECIMAL_CURRENCIES) {
34
+ expect(STRIPE_THREE_DECIMAL_CURRENCIES.has(code)).toBe(false);
35
+ }
36
+ });
37
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Stripe amount scaling rules for charges and invoices.
3
+ *
4
+ * These sets follow Stripe's amount scaling rules
5
+ * (https://docs.stripe.com/currencies), not ISO 4217 metadata: divide the
6
+ * minor-unit integer by 100 for most currencies, by 1 for the zero-decimal
7
+ * set (e.g. JPY, KRW), and by 1000 for the three-decimal set (e.g. BHD).
8
+ * ISK, HUF, TWD, and UGX are deliberately absent from the zero-decimal set:
9
+ * Stripe charges and invoices them as two-decimal amounts and treats them
10
+ * as zero-decimal only for payouts, per Stripe's currency docs.
11
+ *
12
+ * Only the scaling data and digit selection live here; presentation (locale,
13
+ * symbol vs code display, fallbacks for unknown codes) belongs to each
14
+ * consumer.
15
+ */
16
+ export const STRIPE_ZERO_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([
17
+ "BIF",
18
+ "CLP",
19
+ "DJF",
20
+ "GNF",
21
+ "JPY",
22
+ "KMF",
23
+ "KRW",
24
+ "MGA",
25
+ "PYG",
26
+ "RWF",
27
+ "VND",
28
+ "VUV",
29
+ "XAF",
30
+ "XOF",
31
+ "XPF",
32
+ ]);
33
+
34
+ export const STRIPE_THREE_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([
35
+ "BHD",
36
+ "JOD",
37
+ "KWD",
38
+ "OMR",
39
+ "TND",
40
+ ]);
41
+
42
+ /**
43
+ * Fraction digits Stripe uses when charging or invoicing in the given
44
+ * currency. Expects an uppercase ISO 4217 code; unknown codes get the
45
+ * two-decimal default.
46
+ */
47
+ export function stripeScaleDigits(currencyCode: string): number {
48
+ if (STRIPE_ZERO_DECIMAL_CURRENCIES.has(currencyCode)) {
49
+ return 0;
50
+ }
51
+ if (STRIPE_THREE_DECIMAL_CURRENCIES.has(currencyCode)) {
52
+ return 3;
53
+ }
54
+ return 2;
55
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Tests for reading an install layout: telling a repo checkout from an
3
+ * installed package, and locating the `assistant` command that ships with an
4
+ * install.
5
+ */
6
+
7
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
+
12
+ import { findAssistantCommand, isRepoCheckoutPath } from "../index.js";
13
+
14
+ let root: string;
15
+
16
+ beforeEach(() => {
17
+ root = mkdtempSync(join(tmpdir(), "install-layout-"));
18
+ });
19
+
20
+ afterEach(() => {
21
+ rmSync(root, { recursive: true, force: true });
22
+ });
23
+
24
+ /** Create `<nodeModulesDir>/.bin/assistant` and return its path. */
25
+ function seedCommand(nodeModulesDir: string): string {
26
+ const binDir = join(nodeModulesDir, ".bin");
27
+ mkdirSync(binDir, { recursive: true });
28
+ const command = join(binDir, "assistant");
29
+ writeFileSync(command, "#!/usr/bin/env bun\n");
30
+ return command;
31
+ }
32
+
33
+ describe("isRepoCheckoutPath", () => {
34
+ test("an installed package is not a checkout", () => {
35
+ expect(
36
+ isRepoCheckoutPath(
37
+ "/Users/x/Library/Application Support/@vellumai/macos/cli/latest/node_modules/@vellumai/assistant/src/index.ts",
38
+ ),
39
+ ).toBe(false);
40
+ });
41
+
42
+ test("a repo checkout is", () => {
43
+ expect(
44
+ isRepoCheckoutPath("/Users/x/dev/vellum/assistant/src/index.ts"),
45
+ ).toBe(true);
46
+ });
47
+
48
+ test("a directory merely named node_modules-ish is not enough", () => {
49
+ expect(
50
+ isRepoCheckoutPath("/Users/x/node_modules_backup/a/src/index.ts"),
51
+ ).toBe(true);
52
+ });
53
+ });
54
+
55
+ describe("findAssistantCommand", () => {
56
+ test("finds the command shipped beside an installed package", () => {
57
+ const nodeModules = join(root, "cli", "latest", "node_modules");
58
+ const command = seedCommand(nodeModules);
59
+ const path = join(nodeModules, "@vellumai", "assistant", "src", "index.ts");
60
+
61
+ expect(findAssistantCommand(path)).toBe(command);
62
+ });
63
+
64
+ test("prefers a nested install over a hoisted one", () => {
65
+ const outer = join(root, "node_modules");
66
+ const outerCommand = seedCommand(outer);
67
+ const inner = join(outer, "vellum", "node_modules");
68
+ const innerCommand = seedCommand(inner);
69
+ const path = join(inner, "@vellumai", "assistant", "src", "index.ts");
70
+
71
+ expect(findAssistantCommand(path)).toBe(innerCommand);
72
+ expect(innerCommand).not.toBe(outerCommand);
73
+ });
74
+
75
+ test("falls back to a hoisted install when the nested one has no command", () => {
76
+ const outer = join(root, "node_modules");
77
+ const outerCommand = seedCommand(outer);
78
+ const inner = join(outer, "vellum", "node_modules");
79
+ mkdirSync(inner, { recursive: true });
80
+ const path = join(inner, "@vellumai", "assistant", "src", "index.ts");
81
+
82
+ expect(findAssistantCommand(path)).toBe(outerCommand);
83
+ });
84
+
85
+ test("returns null for a repo checkout", () => {
86
+ expect(
87
+ findAssistantCommand(join(root, "assistant", "src", "index.ts")),
88
+ ).toBeNull();
89
+ });
90
+
91
+ test("returns null when the install ships no assistant command", () => {
92
+ const nodeModules = join(root, "node_modules");
93
+ mkdirSync(join(nodeModules, ".bin"), { recursive: true });
94
+ const path = join(nodeModules, "@vellumai", "assistant", "src", "index.ts");
95
+
96
+ expect(findAssistantCommand(path)).toBeNull();
97
+ });
98
+ });
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Package boundary tests for @vellumai/environments.
3
3
  *
4
- * This package is the lowest layer of the shared-packages hierarchy: pure
5
- * environment types and constants with no runtime dependencies. It must
6
- * stay a leaf so any consumer (CLI, assistant, local-mode host) can depend
7
- * on it without dragging in a dependency tree.
4
+ * This package is the lowest layer of the shared-packages hierarchy:
5
+ * environment types, constants, and small helpers over node builtins, with no
6
+ * runtime dependencies. It must stay a leaf so any consumer (CLI, assistant,
7
+ * local-mode host) can depend on it without dragging in a dependency tree.
8
8
  *
9
9
  * Enforces that the package:
10
10
  * 1. Imports only node builtins and its own relative modules — no `@vellumai/*`
@@ -79,7 +79,7 @@ describe("package boundary", () => {
79
79
  throw new Error(
80
80
  `Found ${violations.length} forbidden import(s) in @vellumai/environments:\n` +
81
81
  violations.map((v) => ` - ${v}`).join("\n") +
82
- "\n\n@vellumai/environments is a pure types/constants leaf and must\n" +
82
+ "\n\n@vellumai/environments is a dependency-free leaf and must\n" +
83
83
  "import only node builtins and its own relative modules.",
84
84
  );
85
85
  }
@@ -1,11 +1,22 @@
1
1
  /**
2
- * @vellumai/environments the single source of truth for Vellum's known
3
- * deployment environments (names, platform/web URLs, per-service port
4
- * blocks). Consumed by the CLI, the assistant daemon, and the local-mode
5
- * host library so the environment list is defined exactly once on the TS
6
- * side. The Swift client mirrors the same set in `VellumEnvironment.swift`.
2
+ * @vellumai/environments: the single source of truth for how a Vellum install
3
+ * is laid out and which deployment environment it belongs to.
7
4
  *
8
- * Intentionally free of runtime dependencies: pure types and constants only.
5
+ * Two things live here:
6
+ *
7
+ * - The known deployment environments (names, platform/web URLs, per-service
8
+ * port blocks). The Swift client mirrors the same set in
9
+ * `VellumEnvironment.swift`.
10
+ * - Install layout: whether a runtime is a repo checkout or an installed
11
+ * package, and where the `assistant` command it ships lives.
12
+ *
13
+ * Consumed by the CLI, the assistant daemon, and the local-mode host library
14
+ * so each answer is defined exactly once on the TS side.
15
+ *
16
+ * This is the lowest layer of the shared-packages hierarchy and stays a leaf:
17
+ * types, constants, and small helpers over node builtins, with no runtime
18
+ * dependencies of its own. See `__tests__/package-boundary.test.ts`.
9
19
  */
10
20
  export * from "./types.js";
11
21
  export * from "./seeds.js";
22
+ export * from "./install-layout.js";
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Reading the layout a Vellum runtime is installed in.
3
+ *
4
+ * The daemon is started either from a developer's repo checkout or from an
5
+ * installed npm package (`<install>/node_modules/@vellumai/assistant/src/
6
+ * index.ts`, which is what the desktop app runs). The CLI needs the layout to
7
+ * decide whether a launch is a dev run and what to put on the daemon's PATH;
8
+ * the daemon needs it to decide what to install as the `assistant` command.
9
+ * Both ask the same two questions, so they ask them here.
10
+ */
11
+
12
+ import { existsSync } from "node:fs";
13
+ import { join, sep } from "node:path";
14
+
15
+ const NODE_MODULES_SEGMENT = `${sep}node_modules${sep}`;
16
+
17
+ /**
18
+ * Whether `path` sits in a developer's repo checkout rather than inside an
19
+ * installed package.
20
+ */
21
+ export function isRepoCheckoutPath(path: string): boolean {
22
+ return !path.includes(NODE_MODULES_SEGMENT);
23
+ }
24
+
25
+ /**
26
+ * The `assistant` command shipped with the install that contains `path`, or
27
+ * null when there is none (a repo checkout, or an install whose dependency
28
+ * graph omits the package declaring the bin).
29
+ *
30
+ * Searches innermost `node_modules` outward, since a nested install shadows a
31
+ * hoisted one.
32
+ */
33
+ export function findAssistantCommand(path: string): string | null {
34
+ let index = path.lastIndexOf(NODE_MODULES_SEGMENT);
35
+
36
+ while (index !== -1) {
37
+ const nodeModulesDir = path.slice(
38
+ 0,
39
+ index + NODE_MODULES_SEGMENT.length - 1,
40
+ );
41
+ const command = join(nodeModulesDir, ".bin", "assistant");
42
+ if (existsSync(command)) {
43
+ return command;
44
+ }
45
+ index = path.lastIndexOf(NODE_MODULES_SEGMENT, index - 1);
46
+ }
47
+
48
+ return null;
49
+ }
@@ -19,6 +19,7 @@
19
19
  "./attachment-naming": "./src/attachment-naming.ts",
20
20
  "./redacted-credential": "./src/redacted-credential.ts",
21
21
  "./secret-detection": "./src/secret-detection.ts",
22
+ "./stripe-currency": "./src/stripe-currency.ts",
22
23
  "./error": "./src/error.ts"
23
24
  },
24
25
  "scripts": {
@@ -0,0 +1,37 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ STRIPE_THREE_DECIMAL_CURRENCIES,
5
+ STRIPE_ZERO_DECIMAL_CURRENCIES,
6
+ stripeScaleDigits,
7
+ } from "../stripe-currency.js";
8
+
9
+ describe("stripeScaleDigits", () => {
10
+ test("zero-decimal currencies scale to 0 digits", () => {
11
+ expect(stripeScaleDigits("JPY")).toBe(0);
12
+ expect(stripeScaleDigits("KRW")).toBe(0);
13
+ });
14
+
15
+ test("three-decimal currencies scale to 3 digits", () => {
16
+ expect(stripeScaleDigits("BHD")).toBe(3);
17
+ expect(stripeScaleDigits("KWD")).toBe(3);
18
+ });
19
+
20
+ test("everything else scales to 2 digits", () => {
21
+ expect(stripeScaleDigits("USD")).toBe(2);
22
+ expect(stripeScaleDigits("EUR")).toBe(2);
23
+ expect(stripeScaleDigits("XYZ")).toBe(2);
24
+ });
25
+
26
+ test("Stripe's charge-side two-decimal special cases stay at 2 digits", () => {
27
+ for (const code of ["ISK", "HUF", "TWD", "UGX"]) {
28
+ expect(stripeScaleDigits(code)).toBe(2);
29
+ }
30
+ });
31
+
32
+ test("the currency sets do not overlap", () => {
33
+ for (const code of STRIPE_ZERO_DECIMAL_CURRENCIES) {
34
+ expect(STRIPE_THREE_DECIMAL_CURRENCIES.has(code)).toBe(false);
35
+ }
36
+ });
37
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Stripe amount scaling rules for charges and invoices.
3
+ *
4
+ * These sets follow Stripe's amount scaling rules
5
+ * (https://docs.stripe.com/currencies), not ISO 4217 metadata: divide the
6
+ * minor-unit integer by 100 for most currencies, by 1 for the zero-decimal
7
+ * set (e.g. JPY, KRW), and by 1000 for the three-decimal set (e.g. BHD).
8
+ * ISK, HUF, TWD, and UGX are deliberately absent from the zero-decimal set:
9
+ * Stripe charges and invoices them as two-decimal amounts and treats them
10
+ * as zero-decimal only for payouts, per Stripe's currency docs.
11
+ *
12
+ * Only the scaling data and digit selection live here; presentation (locale,
13
+ * symbol vs code display, fallbacks for unknown codes) belongs to each
14
+ * consumer.
15
+ */
16
+ export const STRIPE_ZERO_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([
17
+ "BIF",
18
+ "CLP",
19
+ "DJF",
20
+ "GNF",
21
+ "JPY",
22
+ "KMF",
23
+ "KRW",
24
+ "MGA",
25
+ "PYG",
26
+ "RWF",
27
+ "VND",
28
+ "VUV",
29
+ "XAF",
30
+ "XOF",
31
+ "XPF",
32
+ ]);
33
+
34
+ export const STRIPE_THREE_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([
35
+ "BHD",
36
+ "JOD",
37
+ "KWD",
38
+ "OMR",
39
+ "TND",
40
+ ]);
41
+
42
+ /**
43
+ * Fraction digits Stripe uses when charging or invoicing in the given
44
+ * currency. Expects an uppercase ISO 4217 code; unknown codes get the
45
+ * two-decimal default.
46
+ */
47
+ export function stripeScaleDigits(currencyCode: string): number {
48
+ if (STRIPE_ZERO_DECIMAL_CURRENCIES.has(currencyCode)) {
49
+ return 0;
50
+ }
51
+ if (STRIPE_THREE_DECIMAL_CURRENCIES.has(currencyCode)) {
52
+ return 3;
53
+ }
54
+ return 2;
55
+ }
@@ -19,6 +19,7 @@
19
19
  "./attachment-naming": "./src/attachment-naming.ts",
20
20
  "./redacted-credential": "./src/redacted-credential.ts",
21
21
  "./secret-detection": "./src/secret-detection.ts",
22
+ "./stripe-currency": "./src/stripe-currency.ts",
22
23
  "./error": "./src/error.ts"
23
24
  },
24
25
  "scripts": {
@@ -0,0 +1,37 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ STRIPE_THREE_DECIMAL_CURRENCIES,
5
+ STRIPE_ZERO_DECIMAL_CURRENCIES,
6
+ stripeScaleDigits,
7
+ } from "../stripe-currency.js";
8
+
9
+ describe("stripeScaleDigits", () => {
10
+ test("zero-decimal currencies scale to 0 digits", () => {
11
+ expect(stripeScaleDigits("JPY")).toBe(0);
12
+ expect(stripeScaleDigits("KRW")).toBe(0);
13
+ });
14
+
15
+ test("three-decimal currencies scale to 3 digits", () => {
16
+ expect(stripeScaleDigits("BHD")).toBe(3);
17
+ expect(stripeScaleDigits("KWD")).toBe(3);
18
+ });
19
+
20
+ test("everything else scales to 2 digits", () => {
21
+ expect(stripeScaleDigits("USD")).toBe(2);
22
+ expect(stripeScaleDigits("EUR")).toBe(2);
23
+ expect(stripeScaleDigits("XYZ")).toBe(2);
24
+ });
25
+
26
+ test("Stripe's charge-side two-decimal special cases stay at 2 digits", () => {
27
+ for (const code of ["ISK", "HUF", "TWD", "UGX"]) {
28
+ expect(stripeScaleDigits(code)).toBe(2);
29
+ }
30
+ });
31
+
32
+ test("the currency sets do not overlap", () => {
33
+ for (const code of STRIPE_ZERO_DECIMAL_CURRENCIES) {
34
+ expect(STRIPE_THREE_DECIMAL_CURRENCIES.has(code)).toBe(false);
35
+ }
36
+ });
37
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Stripe amount scaling rules for charges and invoices.
3
+ *
4
+ * These sets follow Stripe's amount scaling rules
5
+ * (https://docs.stripe.com/currencies), not ISO 4217 metadata: divide the
6
+ * minor-unit integer by 100 for most currencies, by 1 for the zero-decimal
7
+ * set (e.g. JPY, KRW), and by 1000 for the three-decimal set (e.g. BHD).
8
+ * ISK, HUF, TWD, and UGX are deliberately absent from the zero-decimal set:
9
+ * Stripe charges and invoices them as two-decimal amounts and treats them
10
+ * as zero-decimal only for payouts, per Stripe's currency docs.
11
+ *
12
+ * Only the scaling data and digit selection live here; presentation (locale,
13
+ * symbol vs code display, fallbacks for unknown codes) belongs to each
14
+ * consumer.
15
+ */
16
+ export const STRIPE_ZERO_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([
17
+ "BIF",
18
+ "CLP",
19
+ "DJF",
20
+ "GNF",
21
+ "JPY",
22
+ "KMF",
23
+ "KRW",
24
+ "MGA",
25
+ "PYG",
26
+ "RWF",
27
+ "VND",
28
+ "VUV",
29
+ "XAF",
30
+ "XOF",
31
+ "XPF",
32
+ ]);
33
+
34
+ export const STRIPE_THREE_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([
35
+ "BHD",
36
+ "JOD",
37
+ "KWD",
38
+ "OMR",
39
+ "TND",
40
+ ]);
41
+
42
+ /**
43
+ * Fraction digits Stripe uses when charging or invoicing in the given
44
+ * currency. Expects an uppercase ISO 4217 code; unknown codes get the
45
+ * two-decimal default.
46
+ */
47
+ export function stripeScaleDigits(currencyCode: string): number {
48
+ if (STRIPE_ZERO_DECIMAL_CURRENCIES.has(currencyCode)) {
49
+ return 0;
50
+ }
51
+ if (STRIPE_THREE_DECIMAL_CURRENCIES.has(currencyCode)) {
52
+ return 3;
53
+ }
54
+ return 2;
55
+ }
@@ -14,6 +14,36 @@ describe("extractSlackUserMentionIds", () => {
14
14
  extractSlackUserMentionIds("<@U123> hi <@W456> and <@U123> again"),
15
15
  ).toEqual(["U123", "W456"]);
16
16
  });
17
+
18
+ test("includes pipe-form user mention IDs", () => {
19
+ expect(extractSlackUserMentionIds("<@U123|jane> and <@W456|>")).toEqual([
20
+ "U123",
21
+ "W456",
22
+ ]);
23
+ });
24
+ });
25
+
26
+ describe("buildSlackUserLabelMap", () => {
27
+ test("skips pipe-form mentions with usable embedded labels, queues the rest", async () => {
28
+ const requested: string[] = [];
29
+ const labels = await buildSlackUserLabelMap(
30
+ ["<@U123|jane> <@U456|> <@U789|U789> <@U999>"],
31
+ async (id) => {
32
+ requested.push(id);
33
+ return `name-${id}`;
34
+ },
35
+ );
36
+
37
+ // Usable embedded label: rendered from the token, no lookup.
38
+ expect(requested).not.toContain("U123");
39
+ // Empty or ID-shaped embedded labels still need resolution.
40
+ expect(requested.sort()).toEqual(["U456", "U789", "U999"]);
41
+ expect(labels).toEqual({
42
+ U456: "name-U456",
43
+ U789: "name-U789",
44
+ U999: "name-U999",
45
+ });
46
+ });
17
47
  });
18
48
 
19
49
  describe("extractSlackChannelReferenceIds", () => {
@@ -52,6 +82,24 @@ describe("renderSlackTextForModel", () => {
52
82
  ).toBe("hello @unknown-user");
53
83
  });
54
84
 
85
+ test("prefers embedded pipe-form user labels over lookups", () => {
86
+ expect(renderSlackTextForModel("hi <@U123|jane>")).toBe("hi @jane");
87
+ expect(
88
+ renderSlackTextForModel("hi <@U123|jane>", {
89
+ userLabels: { U123: "Jane Doe" },
90
+ }),
91
+ ).toBe("hi @jane");
92
+ });
93
+
94
+ test("falls back past ID-shaped embedded user labels to resolved ones", () => {
95
+ expect(
96
+ renderSlackTextForModel("hi <@U123|U123>", {
97
+ userLabels: { U123: "Jane Doe" },
98
+ }),
99
+ ).toBe("hi @Jane Doe");
100
+ expect(renderSlackTextForModel("hi <@U123|U123>")).toBe("hi @unknown-user");
101
+ });
102
+
55
103
  test("renders channel references with labels and fallbacks", () => {
56
104
  expect(
57
105
  renderSlackTextForModel("<#C123|general> <#C456>", {