@vellumai/assistant 0.11.1 → 0.11.2-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) 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/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__/stripe-currency.test.ts +37 -0
  9. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
  12. package/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  13. package/node_modules/@vellumai/slack-text/src/index.test.ts +48 -0
  14. package/node_modules/@vellumai/slack-text/src/index.ts +25 -6
  15. package/openapi.yaml +292 -5
  16. package/package.json +1 -1
  17. package/src/__tests__/agent-loop-resume-interrupted.test.ts +223 -0
  18. package/src/__tests__/byok-default-profile-ensure.test.ts +43 -0
  19. package/src/__tests__/cli-logger-boundary-guard.test.ts +87 -0
  20. package/src/__tests__/compaction-events.test.ts +139 -2
  21. package/src/__tests__/config-loader-backfill.test.ts +35 -3
  22. package/src/__tests__/config-schema.test.ts +1 -0
  23. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +30 -0
  24. package/src/__tests__/conversation-agent-loop.test.ts +180 -7
  25. package/src/__tests__/conversation-error.test.ts +211 -4
  26. package/src/__tests__/conversation-options-turn-scoped-transport.test.ts +64 -0
  27. package/src/__tests__/conversation-queue.test.ts +126 -0
  28. package/src/__tests__/conversation-retry-route.test.ts +46 -7
  29. package/src/__tests__/conversation-slash.test.ts +4 -2
  30. package/src/__tests__/conversation-summarize-route.test.ts +7 -1
  31. package/src/__tests__/conversation-summarize-up-to.test.ts +71 -5
  32. package/src/__tests__/document-create-dedupe.test.ts +2 -1
  33. package/src/__tests__/document-find-replace.test.ts +2 -1
  34. package/src/__tests__/document-tool-security.test.ts +2 -1
  35. package/src/__tests__/document-update-default-surface.test.ts +2 -1
  36. package/src/__tests__/document-workspace-file.test.ts +467 -0
  37. package/src/__tests__/emit-signal-routing-intent.test.ts +290 -49
  38. package/src/__tests__/guardian-card-withdrawal.test.ts +91 -3
  39. package/src/__tests__/http-user-message-parity.test.ts +66 -0
  40. package/src/__tests__/list-messages-attachments.test.ts +87 -0
  41. package/src/__tests__/list-messages-provider-error.test.ts +143 -0
  42. package/src/__tests__/list-messages-system-card.test.ts +100 -0
  43. package/src/__tests__/llm-resolver.test.ts +19 -9
  44. package/src/__tests__/managed-profile-guard.test.ts +23 -0
  45. package/src/__tests__/notification-platform-adapter.test.ts +130 -2
  46. package/src/__tests__/notification-telegram-adapter.test.ts +6 -0
  47. package/src/__tests__/notification-vellum-adapter.test.ts +45 -0
  48. package/src/__tests__/plugin-api-model-profiles.test.ts +10 -1
  49. package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -0
  50. package/src/__tests__/provider-error-scenarios.test.ts +140 -0
  51. package/src/__tests__/provider-send-message-override-profile.test.ts +95 -0
  52. package/src/__tests__/run-conversation-turn-persistence.test.ts +66 -3
  53. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +209 -0
  54. package/src/__tests__/skills.test.ts +27 -0
  55. package/src/__tests__/slack-channels-routes.test.ts +0 -2
  56. package/src/__tests__/slack-share-routes.test.ts +0 -3
  57. package/src/__tests__/slack-users-routes.test.ts +0 -2
  58. package/src/__tests__/subagent-tools.test.ts +11 -0
  59. package/src/__tests__/tool-preview-lifecycle.test.ts +58 -0
  60. package/src/__tests__/tool-result-spool.test.ts +5 -4
  61. package/src/__tests__/turn-boundary-resolution.test.ts +53 -0
  62. package/src/__tests__/turn-events-store.test.ts +26 -0
  63. package/src/__tests__/ui-visual-surface.test.ts +695 -0
  64. package/src/__tests__/unified-turn-context-visible-app.test.ts +99 -0
  65. package/src/__tests__/visible-app-context.test.ts +189 -0
  66. package/src/__tests__/workspace-git-service.test.ts +173 -33
  67. package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +157 -0
  68. package/src/__tests__/workspace-migration-138-backfill-home-feed-titles.test.ts +373 -0
  69. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +137 -0
  70. package/src/agent/loop.ts +36 -7
  71. package/src/api/events/context-window-usage.ts +31 -0
  72. package/src/api/events/notification-intent.ts +8 -0
  73. package/src/api/events/ui-surface-pending.ts +35 -0
  74. package/src/api/index.ts +14 -0
  75. package/src/api/responses/conversation-message.ts +25 -4
  76. package/src/api/surfaces.ts +90 -1
  77. package/src/approvals/guardian-card-withdrawal.ts +66 -31
  78. package/src/approvals/guardian-decision-primitive.ts +4 -0
  79. package/src/calls/__tests__/call-setup-router.test.ts +156 -26
  80. package/src/calls/__tests__/voice-session-bridge.test.ts +201 -12
  81. package/src/calls/call-setup-router.ts +80 -36
  82. package/src/calls/voice-session-bridge.ts +173 -26
  83. package/src/cli/commands/inference.help.ts +3 -3
  84. package/src/cli/commands/notifications.help.ts +3 -2
  85. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +42 -128
  86. package/src/cli/commands/platform/__tests__/credits.test.ts +9 -78
  87. package/src/cli/commands/platform/__tests__/helpers.ts +90 -0
  88. package/src/cli/commands/platform/__tests__/invoices.test.ts +238 -0
  89. package/src/cli/commands/platform/__tests__/plans.test.ts +9 -88
  90. package/src/cli/commands/platform/__tests__/status.test.ts +12 -87
  91. package/src/cli/commands/platform/__tests__/subscription.test.ts +9 -86
  92. package/src/cli/commands/platform/index.help.ts +92 -0
  93. package/src/cli/commands/platform/index.ts +7 -0
  94. package/src/cli/commands/platform/invoices.ts +132 -0
  95. package/src/cli/commands/usage.help.ts +1 -1
  96. package/src/cli/lib/list-installed-plugins.ts +2 -1
  97. package/src/config/__tests__/default-profile-catalog.test.ts +7 -10
  98. package/src/config/__tests__/deployment-context-defaults.test.ts +27 -5
  99. package/src/config/assistant-feature-flags.ts +7 -2
  100. package/src/config/bundled-skills/app-builder/SKILL.md +3 -2
  101. package/src/config/bundled-skills/subagent/SKILL.md +3 -1
  102. package/src/config/bundled-skills/subagent/TOOLS.json +3 -3
  103. package/src/config/bundled-skills/visualize/SKILL.md +163 -0
  104. package/src/config/call-site-defaults.ts +3 -2
  105. package/src/config/default-profile-catalog.ts +75 -70
  106. package/src/config/default-profile-names.ts +13 -28
  107. package/src/config/env-registry.ts +1 -0
  108. package/src/config/feature-flag-registry.json +16 -0
  109. package/src/config/llm-resolver.ts +21 -5
  110. package/src/config/loader.ts +18 -11
  111. package/src/config/schemas/llm.ts +1 -9
  112. package/src/config/schemas/memory-retrospective.ts +9 -0
  113. package/src/config/schemas/monitoring.ts +28 -2
  114. package/src/config/schemas/workspace-git.ts +15 -0
  115. package/src/config/seed-inference-profiles.ts +19 -5
  116. package/src/context/post-turn-tool-result-truncation.ts +2 -2
  117. package/src/conversations/__tests__/message-consolidation.test.ts +54 -0
  118. package/src/conversations/message-consolidation.ts +17 -15
  119. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +182 -0
  120. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +181 -0
  121. package/src/daemon/conversation-agent-loop-handlers.ts +90 -7
  122. package/src/daemon/conversation-agent-loop.ts +107 -22
  123. package/src/daemon/conversation-error.ts +169 -48
  124. package/src/daemon/conversation-messaging.ts +87 -4
  125. package/src/daemon/conversation-process.ts +57 -45
  126. package/src/daemon/conversation-runtime-assembly.ts +57 -0
  127. package/src/daemon/conversation-store.ts +36 -1
  128. package/src/daemon/conversation-surfaces.ts +68 -6
  129. package/src/daemon/conversation-turn-finalize.ts +76 -18
  130. package/src/daemon/conversation.ts +122 -27
  131. package/src/daemon/lifecycle.ts +9 -0
  132. package/src/daemon/message-types/conversations.ts +8 -0
  133. package/src/daemon/message-types/surfaces.ts +3 -0
  134. package/src/documents/document-store.ts +247 -10
  135. package/src/home/__tests__/feed-types.test.ts +43 -8
  136. package/src/home/__tests__/feed-writer.test.ts +59 -0
  137. package/src/home/feed-types.ts +34 -7
  138. package/src/home/feed-writer.ts +15 -6
  139. package/src/live-voice/__tests__/activity-label.test.ts +95 -0
  140. package/src/live-voice/__tests__/live-activity-reporter.test.ts +86 -5
  141. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +310 -25
  142. package/src/live-voice/__tests__/live-voice-events.test.ts +4 -4
  143. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +8 -4
  144. package/src/live-voice/__tests__/live-voice-vad.test.ts +9 -1
  145. package/src/live-voice/activity-label.ts +169 -0
  146. package/src/live-voice/live-activity-reporter.ts +35 -6
  147. package/src/live-voice/live-voice-session.ts +282 -41
  148. package/src/live-voice/protocol.ts +35 -0
  149. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +84 -2
  150. package/src/messaging/providers/slack/adapter.ts +86 -19
  151. package/src/messaging/providers/slack/api.test.ts +85 -1
  152. package/src/messaging/providers/slack/api.ts +121 -288
  153. package/src/messaging/providers/slack/client.ts +20 -251
  154. package/src/messaging/providers/slack/send.test.ts +4 -9
  155. package/src/messaging/providers/slack/send.ts +1 -1
  156. package/src/messaging/providers/slack/types.ts +5 -0
  157. package/src/messaging/providers/slack/web-api-transport.test.ts +181 -0
  158. package/src/messaging/providers/slack/web-api-transport.ts +367 -0
  159. package/src/messaging/providers/slack/withdraw.ts +6 -14
  160. package/src/messaging/providers/telegram-bot/send.test.ts +31 -1
  161. package/src/messaging/providers/telegram-bot/send.ts +23 -2
  162. package/src/messaging/providers/telegram-bot/withdraw.test.ts +152 -0
  163. package/src/messaging/providers/telegram-bot/withdraw.ts +166 -0
  164. package/src/monitoring/__tests__/db-integrity-sample.test.ts +18 -4
  165. package/src/monitoring/__tests__/file-descriptors.test.ts +144 -0
  166. package/src/monitoring/file-descriptors.ts +262 -0
  167. package/src/monitoring/process-memory.ts +4 -11
  168. package/src/monitoring/resource-sampler.ts +5 -0
  169. package/src/monitoring/worker.ts +12 -0
  170. package/src/notifications/__tests__/assistant-reply-producer.test.ts +740 -0
  171. package/src/notifications/__tests__/broadcaster.test.ts +347 -7
  172. package/src/notifications/__tests__/copy-composer.test.ts +53 -3
  173. package/src/notifications/__tests__/decision-engine.test.ts +349 -29
  174. package/src/notifications/__tests__/deterministic-checks.test.ts +21 -0
  175. package/src/notifications/__tests__/edit-notification.test.ts +330 -0
  176. package/src/notifications/__tests__/guardian-delivery-recorder.test.ts +71 -0
  177. package/src/notifications/__tests__/home-feed-side-effect.test.ts +170 -12
  178. package/src/notifications/adapters/macos.ts +3 -0
  179. package/src/notifications/adapters/platform.ts +90 -14
  180. package/src/notifications/adapters/telegram.ts +6 -4
  181. package/src/notifications/assistant-reply-producer.ts +219 -0
  182. package/src/notifications/broadcaster.ts +523 -317
  183. package/src/notifications/copy-composer.ts +27 -6
  184. package/src/notifications/decision-engine.ts +154 -77
  185. package/src/notifications/deterministic-checks.ts +6 -7
  186. package/src/notifications/edit-notification.ts +8 -4
  187. package/src/notifications/emit-signal.ts +49 -16
  188. package/src/notifications/guardian-delivery-recorder.ts +8 -2
  189. package/src/notifications/home-feed-side-effect.ts +43 -6
  190. package/src/notifications/notification-utils.ts +39 -4
  191. package/src/notifications/signal.ts +10 -0
  192. package/src/notifications/types.ts +17 -0
  193. package/src/persistence/bookmark-crud.ts +18 -9
  194. package/src/persistence/conversation-attention-store.ts +26 -0
  195. package/src/persistence/conversation-crud.ts +79 -32
  196. package/src/persistence/conversation-queries.ts +30 -15
  197. package/src/persistence/conversation-title-service.ts +5 -170
  198. package/src/persistence/conversation-types.ts +192 -1
  199. package/src/persistence/db-init.ts +14 -1
  200. package/src/persistence/db-maintenance.ts +5 -4
  201. package/src/persistence/embeddings/__tests__/plugin-index-qdrant-init.test.ts +219 -0
  202. package/src/persistence/embeddings/__tests__/plugin-index.test.ts +22 -0
  203. package/src/persistence/embeddings/__tests__/worker-script-version.test.ts +76 -0
  204. package/src/persistence/embeddings/embedding-local.ts +2 -1
  205. package/src/persistence/embeddings/embedding-runtime-manager.ts +29 -5
  206. package/src/persistence/embeddings/plugin-index.ts +84 -12
  207. package/src/persistence/migrations/360-add-document-workspace-path.test.ts +110 -0
  208. package/src/persistence/migrations/360-add-document-workspace-path.ts +39 -0
  209. package/src/persistence/planner-statistics.ts +14 -0
  210. package/src/persistence/schema/documents.ts +26 -11
  211. package/src/persistence/steps.ts +2 -0
  212. package/src/platform/client.test.ts +172 -2
  213. package/src/platform/client.ts +178 -55
  214. package/src/plugin-api/conversation-turn.ts +13 -0
  215. package/src/plugin-api/model-profiles.test.ts +6 -2
  216. package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +34 -0
  217. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +22 -0
  218. package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +11 -0
  219. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +199 -0
  220. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +98 -1
  221. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +105 -1
  222. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +24 -2
  223. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +524 -0
  224. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1 -1
  225. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +9 -4
  226. package/src/plugins/defaults/memory/host-utils.ts +5 -0
  227. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +105 -1
  228. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +64 -5
  229. package/src/plugins/defaults/memory/memory-retrospective-job.ts +36 -1
  230. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +12 -3
  231. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +1 -0
  232. package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +195 -1
  233. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +1 -1
  234. package/src/plugins/defaults/memory/substrate/skill-store.ts +167 -29
  235. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +131 -0
  236. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1 -0
  237. package/src/plugins/defaults/memory/v2/activation-log-store.ts +4 -0
  238. package/src/plugins/defaults/memory/v2/injection.ts +48 -3
  239. package/src/plugins/defaults/memory/v2/rerank-local.ts +6 -2
  240. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -1
  241. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +1 -1
  242. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  243. package/src/plugins/defaults/turn-context/unified-turn-context.ts +26 -0
  244. package/src/plugins/types.ts +17 -0
  245. package/src/prompts/templates/system-sections.ts +2 -2
  246. package/src/providers/__tests__/dispatch-connection-routing.test.ts +43 -2
  247. package/src/providers/__tests__/vellum-mismatch-routing.test.ts +8 -0
  248. package/src/providers/call-site-routing.ts +77 -14
  249. package/src/providers/connection-resolution.ts +42 -2
  250. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +127 -1
  251. package/src/providers/inference/adapter-factory.ts +70 -12
  252. package/src/providers/model-catalog.ts +0 -11
  253. package/src/providers/model-intents.ts +11 -0
  254. package/src/providers/registry.ts +8 -0
  255. package/src/providers/retry.ts +85 -17
  256. package/src/providers/types.ts +8 -1
  257. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  258. package/src/runtime/agent-wake.ts +132 -9
  259. package/src/runtime/channel-approval-types.ts +25 -0
  260. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +2 -2
  261. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +11 -0
  262. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +121 -9
  263. package/src/runtime/routes/__tests__/platform-invoice-routes.test.ts +392 -0
  264. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +7 -0
  265. package/src/runtime/routes/__tests__/workspace-commit-routes.test.ts +63 -0
  266. package/src/runtime/routes/consolidation-routes.ts +1 -1
  267. package/src/runtime/routes/conversation-management-routes.ts +18 -6
  268. package/src/runtime/routes/conversation-query-routes.ts +14 -23
  269. package/src/runtime/routes/conversation-routes.ts +113 -8
  270. package/src/runtime/routes/credential-routes.ts +1 -5
  271. package/src/runtime/routes/documents-routes.ts +207 -12
  272. package/src/runtime/routes/identity-routes.ts +3 -93
  273. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +31 -1
  274. package/src/runtime/routes/inbound-stages/admission-policy.ts +18 -0
  275. package/src/runtime/routes/inference-provider-connection-routes.ts +52 -3
  276. package/src/runtime/routes/notification-routes.ts +4 -1
  277. package/src/runtime/routes/platform-routes.ts +238 -3
  278. package/src/runtime/routes/playground/guard.ts +1 -2
  279. package/src/runtime/routes/slack-channel-routes.ts +2 -4
  280. package/src/runtime/routes/workspace-commit-routes.ts +49 -2
  281. package/src/runtime/routes/workspace-routes.ts +11 -12
  282. package/src/runtime/routes/workspace-utils.ts +49 -2
  283. package/src/runtime/services/conversation-serializer.ts +2 -4
  284. package/src/subagent/__tests__/consult-context-gating.test.ts +98 -0
  285. package/src/subagent/__tests__/consult-context-skills.test.ts +82 -0
  286. package/src/subagent/__tests__/consult-context.test.ts +84 -0
  287. package/src/subagent/__tests__/consult-prompt.test.ts +36 -0
  288. package/src/subagent/consult-context.ts +410 -0
  289. package/src/subagent/consult-prompt.ts +38 -5
  290. package/src/subagent/manager.ts +9 -4
  291. package/src/subagent/types.ts +8 -0
  292. package/src/telemetry/telemetry-event-sources.ts +7 -0
  293. package/src/telemetry/telemetry-wire-source.json +1 -1
  294. package/src/telemetry/telemetry-wire.generated.ts +1 -0
  295. package/src/telemetry/turn-events-store.ts +30 -1
  296. package/src/telemetry/types.ts +24 -0
  297. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  298. package/src/tools/browser/pinned-tabs.ts +3 -1
  299. package/src/tools/subagent/spawn.ts +23 -1
  300. package/src/tools/terminal/safe-env.ts +1 -0
  301. package/src/tools/ui-surface/definitions.ts +39 -1
  302. package/src/tools/ui-surface/surface-shape-docs.ts +38 -4
  303. package/src/tools/ui-surface/visual-validation.ts +787 -0
  304. package/src/tools/workflows/run-workflow.test.ts +1 -0
  305. package/src/util/__tests__/short-title.test.ts +229 -0
  306. package/src/util/__tests__/worker-compute.test.ts +65 -0
  307. package/src/util/cgroup-cpu.ts +93 -0
  308. package/src/util/errors.ts +27 -0
  309. package/src/util/process-tree.ts +19 -0
  310. package/src/util/short-title.ts +189 -0
  311. package/src/util/worker-compute.ts +83 -0
  312. package/src/workspace/byok-default-profile-ensure.ts +25 -15
  313. package/src/workspace/git-service.ts +79 -30
  314. package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +131 -0
  315. package/src/workspace/migrations/138-backfill-home-feed-titles.ts +179 -0
  316. package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +92 -0
  317. package/src/workspace/migrations/registry.ts +6 -0
  318. 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
+ }
@@ -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>", {
@@ -5,7 +5,7 @@ export interface RenderSlackTextOptions {
5
5
  channelFallbackLabel?: string;
6
6
  }
7
7
 
8
- const SLACK_USER_MENTION_RE = /<@([UW][A-Z0-9]+)>/g;
8
+ const SLACK_USER_MENTION_RE = /<@([UW][A-Z0-9]+)(?:\|[^>]*)?>/g;
9
9
  const SLACK_CHANNEL_REFERENCE_RE = /<#([CDG][A-Z0-9]+)(?:\|[^>]*)?>/g;
10
10
 
11
11
  export function extractSlackUserMentionIds(text: string): string[] {
@@ -107,7 +107,14 @@ export async function buildSlackUserLabelMap(
107
107
 
108
108
  for (const text of texts) {
109
109
  if (!text) continue;
110
- for (const id of extractSlackUserMentionIds(text)) {
110
+ for (const match of text.matchAll(SLACK_USER_MENTION_RE)) {
111
+ const id = match[1];
112
+ // A pipe-form mention carrying a usable embedded label renders from
113
+ // that label directly; only queue a lookup when the label is missing,
114
+ // empty, or ID-shaped. Mirrors the channel builder below.
115
+ const [, embeddedLabel] = splitSlackLabel(match[0].slice(1, -1));
116
+ const sanitizedEmbeddedLabel = sanitizeOptionalLabel(embeddedLabel);
117
+ if (sanitizedEmbeddedLabel && sanitizedEmbeddedLabel !== id) continue;
111
118
  if (seen.has(id)) continue;
112
119
  seen.add(id);
113
120
  ids.push(id);
@@ -175,17 +182,29 @@ function renderUserMention(
175
182
  content: string,
176
183
  options: RenderSlackTextOptions,
177
184
  ): string {
178
- const id = content.slice(1);
185
+ const [idWithPrefix, label] = splitSlackLabel(content);
186
+ const id = idWithPrefix.slice(1);
179
187
  if (!isSlackUserId(id)) {
180
188
  return `<${content}>`;
181
189
  }
182
190
 
191
+ // Slack's legacy pipe form (`<@U123|username>`) carries its own label:
192
+ // prefer it over a lookup, mirroring renderChannelReference. The embedded
193
+ // label is Slack-sourced (part of the token), so entities decode before
194
+ // sanitization; the caller-resolved label below is not.
195
+ const embeddedLabel = sanitizeOptionalLabel(
196
+ label === undefined ? undefined : decodeSlackHtmlEntities(label),
197
+ );
198
+ if (embeddedLabel && embeddedLabel !== id) {
199
+ return `@${embeddedLabel}`;
200
+ }
201
+
183
202
  const fallback = sanitizeLabel(options.userFallbackLabel, "unknown-user");
184
- const label = sanitizeLabel(options.userLabels?.[id], fallback);
185
- if (label === id) {
203
+ const resolvedLabel = sanitizeLabel(options.userLabels?.[id], fallback);
204
+ if (resolvedLabel === id) {
186
205
  return `@${fallback}`;
187
206
  }
188
- return `@${label}`;
207
+ return `@${resolvedLabel}`;
189
208
  }
190
209
 
191
210
  function renderChannelReference(