@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/openapi.yaml CHANGED
@@ -3,7 +3,7 @@
3
3
  openapi: 3.1.0
4
4
  info:
5
5
  title: Vellum Assistant API
6
- version: 0.11.1
6
+ version: 0.11.2
7
7
  description: Auto-generated OpenAPI specification for the Vellum Assistant runtime HTTP server.
8
8
  servers:
9
9
  - url: http://127.0.0.1:7821
@@ -699,6 +699,52 @@ paths:
699
699
  required:
700
700
  - ok
701
701
  additionalProperties: false
702
+ /v1/admin/workspace-compact-history:
703
+ post:
704
+ operationId: admin_workspacecompacthistory_post
705
+ summary: Compact workspace git history
706
+ description:
707
+ Squash workspace git history older than the retention window into a single base commit and prune reclaimed
708
+ objects. By default acts only when an oversized blob is reclaimable; with force, the squash runs
709
+ unconditionally.
710
+ tags:
711
+ - admin
712
+ requestBody:
713
+ required: true
714
+ content:
715
+ application/json:
716
+ schema:
717
+ type: object
718
+ properties:
719
+ force:
720
+ description: Squash aged history even when no oversized blob is reclaimable
721
+ type: boolean
722
+ retentionDays:
723
+ description: Retention window override in days (default 7)
724
+ type: integer
725
+ exclusiveMinimum: 0
726
+ maximum: 9007199254740991
727
+ responses:
728
+ "200":
729
+ description: Successful response
730
+ content:
731
+ application/json:
732
+ schema:
733
+ type: object
734
+ properties:
735
+ rewrote:
736
+ type: boolean
737
+ squashedCommits:
738
+ type: number
739
+ keptCommits:
740
+ type: number
741
+ retryAfterMs:
742
+ type: number
743
+ required:
744
+ - rewrote
745
+ - squashedCommits
746
+ - keptCommits
747
+ additionalProperties: false
702
748
  /v1/apps:
703
749
  get:
704
750
  operationId: apps_get
@@ -10665,6 +10711,11 @@ paths:
10665
10711
  type: number
10666
10712
  updatedAt:
10667
10713
  type: number
10714
+ workspacePath:
10715
+ anyOf:
10716
+ - type: string
10717
+ - type: "null"
10718
+ description: Workspace-relative file this document is bound to, or null
10668
10719
  required:
10669
10720
  - success
10670
10721
  - surfaceId
@@ -10674,6 +10725,7 @@ paths:
10674
10725
  - wordCount
10675
10726
  - createdAt
10676
10727
  - updatedAt
10728
+ - workspacePath
10677
10729
  additionalProperties: false
10678
10730
  /v1/documents/{id}/comments:
10679
10731
  get:
@@ -11091,6 +11143,74 @@ paths:
11091
11143
  schema:
11092
11144
  type: string
11093
11145
  format: binary
11146
+ /v1/documents/for-workspace-file:
11147
+ post:
11148
+ operationId: documents_forworkspacefile_post
11149
+ summary: Get or create the document for a workspace markdown file
11150
+ description:
11151
+ "Return the document bound to a workspace markdown file, creating it on first open. The file is the source
11152
+ of truth at open time: stored content that has drifted from the file is refreshed from disk before the document
11153
+ is returned."
11154
+ tags:
11155
+ - documents
11156
+ requestBody:
11157
+ required: true
11158
+ content:
11159
+ application/json:
11160
+ schema:
11161
+ type: object
11162
+ properties:
11163
+ path:
11164
+ type: string
11165
+ description: Workspace-relative path to a .md/.markdown file
11166
+ conversationId:
11167
+ type: string
11168
+ description: Conversation the document is opened from
11169
+ required:
11170
+ - path
11171
+ - conversationId
11172
+ responses:
11173
+ "200":
11174
+ description: Successful response
11175
+ content:
11176
+ application/json:
11177
+ schema:
11178
+ type: object
11179
+ properties:
11180
+ success:
11181
+ type: boolean
11182
+ surfaceId:
11183
+ type: string
11184
+ conversationId:
11185
+ type: string
11186
+ title:
11187
+ type: string
11188
+ content:
11189
+ type: string
11190
+ wordCount:
11191
+ type: number
11192
+ createdAt:
11193
+ type: number
11194
+ updatedAt:
11195
+ type: number
11196
+ workspacePath:
11197
+ anyOf:
11198
+ - type: string
11199
+ - type: "null"
11200
+ description: Workspace-relative file this document is bound to, or null
11201
+ required:
11202
+ - success
11203
+ - surfaceId
11204
+ - conversationId
11205
+ - title
11206
+ - content
11207
+ - wordCount
11208
+ - createdAt
11209
+ - updatedAt
11210
+ - workspacePath
11211
+ additionalProperties: false
11212
+ "422":
11213
+ description: Path is not a markdown file
11094
11214
  /v1/domain/register:
11095
11215
  post:
11096
11216
  operationId: domain_register_post
@@ -14633,8 +14753,9 @@ paths:
14633
14753
  summary: Create a provider connection
14634
14754
  description:
14635
14755
  Create a new named provider connection. When auth is omitted it is derived from the provider (keyless
14636
- providers get none, vellum gets platform, everything else needs credential for api_key auth). Fails with 409 if
14637
- a connection with this name already exists.
14756
+ providers get none, vellum gets platform, everything else needs credential for api_key auth). An explicit auth
14757
+ object must agree with the provider; platform auth belongs to vellum and only to vellum. Fails with 409 if a
14758
+ connection with this name already exists.
14638
14759
  tags:
14639
14760
  - inference
14640
14761
  requestBody:
@@ -14743,8 +14864,9 @@ paths:
14743
14864
  summary: Update a provider connection
14744
14865
  description:
14745
14866
  Update an existing connection. Cannot rename or change the provider. Omitting auth keeps the stored auth;
14746
- passing credential alone rotates the key via provider-derived api_key auth. For the Vellum-managed connection
14747
- (vellum) the auth is locked to platform; label remains editable.
14867
+ passing credential alone rotates the key via provider-derived api_key auth. An explicit auth object must agree
14868
+ with the connection's provider; platform auth belongs to vellum and only to vellum. For the Vellum-managed
14869
+ connection (vellum) the auth is locked to platform; label remains editable.
14748
14870
  tags:
14749
14871
  - inference
14750
14872
  parameters:
@@ -19543,6 +19665,14 @@ paths:
19543
19665
  additionalProperties: false
19544
19666
  systemCard:
19545
19667
  type: boolean
19668
+ providerError:
19669
+ type: object
19670
+ properties:
19671
+ code:
19672
+ type: string
19673
+ category:
19674
+ type: string
19675
+ additionalProperties: false
19546
19676
  slackMessage:
19547
19677
  type: object
19548
19678
  properties:
@@ -19709,6 +19839,13 @@ paths:
19709
19839
  Client OS surface ("web" | "ios" | "macos" | "android"), reported separately from `interface`. Drives the
19710
19840
  per-turn `client_os` context only; does not affect transport/host-proxy capabilities.
19711
19841
  type: string
19842
+ visibleAppId:
19843
+ description:
19844
+ 'Id of the app the client currently has open on screen (app viewer or the app-editing split). Drives the
19845
+ per-turn `visible_app:` context line so the assistant can resolve "the app" to what the user is
19846
+ looking at. View state only: it never affects transport, routing, or tool gating, and is omitted
19847
+ whenever no app is in view.'
19848
+ type: string
19712
19849
  clientMessageId:
19713
19850
  type: string
19714
19851
  description:
@@ -19752,6 +19889,16 @@ paths:
19752
19889
  snapshots, emits no echo, and does not supersede pending interactions. Honored on the standard send
19753
19890
  path only — slash-command content bypasses it."
19754
19891
  type: boolean
19892
+ scripted:
19893
+ description:
19894
+ "When true, this turn was auto-sent on the user's behalf rather than typed by them: onboarding research
19895
+ prompts, the personality rewrite message, research corrections, hidden kickoff greetings, the legacy
19896
+ pre-chat bootstrap. Stamped onto the persisted message and forwarded to turn telemetry, where
19897
+ activation metrics exclude it. Send false for a genuine typed message; OMIT the field only if the
19898
+ client genuinely cannot tell, since absent means UNKNOWN and a wrong false is trusted downstream.
19899
+ Independent of `hidden`: a turn can be visible and scripted (the research prompt) or hidden and
19900
+ scripted (the kickoff greeting)."
19901
+ type: boolean
19755
19902
  onboarding:
19756
19903
  type: object
19757
19904
  properties:
@@ -21372,6 +21519,7 @@ paths:
21372
21519
  minLength: 1
21373
21520
  description: Feed item id (notif:<uuid>) or bare uuid
21374
21521
  title:
21522
+ description: New title. An empty value is ignored, never cleared.
21375
21523
  type: string
21376
21524
  body:
21377
21525
  type: string
@@ -22765,6 +22913,145 @@ paths:
22765
22913
  - disconnected
22766
22914
  - previousBaseUrl
22767
22915
  additionalProperties: false
22916
+ /v1/platform/invoices:
22917
+ get:
22918
+ operationId: platform_invoices_get
22919
+ summary: List one page of the organization's Stripe invoices
22920
+ description:
22921
+ Fetches one page of the org's Stripe invoice history (newest first) from the platform billing invoices
22922
+ endpoint. Amounts are in the currency's minor units. When has_more is true, pass the last invoice's id as
22923
+ starting_after to fetch the next page.
22924
+ tags:
22925
+ - platform
22926
+ parameters:
22927
+ - name: starting_after
22928
+ in: query
22929
+ required: false
22930
+ schema:
22931
+ type: string
22932
+ description: "Cursor: return invoices older than the invoice with this id (from the previous page's last entry)."
22933
+ responses:
22934
+ "200":
22935
+ description: Successful response
22936
+ content:
22937
+ application/json:
22938
+ schema:
22939
+ type: object
22940
+ properties:
22941
+ invoices:
22942
+ type: array
22943
+ items:
22944
+ type: object
22945
+ properties:
22946
+ id:
22947
+ type: string
22948
+ number:
22949
+ anyOf:
22950
+ - type: string
22951
+ - type: "null"
22952
+ status:
22953
+ anyOf:
22954
+ - type: string
22955
+ - type: "null"
22956
+ currency:
22957
+ type: string
22958
+ amount_due:
22959
+ type: number
22960
+ amount_paid:
22961
+ type: number
22962
+ amount_remaining:
22963
+ type: number
22964
+ created:
22965
+ type: number
22966
+ hosted_invoice_url:
22967
+ anyOf:
22968
+ - type: string
22969
+ - type: "null"
22970
+ invoice_pdf:
22971
+ anyOf:
22972
+ - type: string
22973
+ - type: "null"
22974
+ required:
22975
+ - id
22976
+ - number
22977
+ - status
22978
+ - currency
22979
+ - amount_due
22980
+ - amount_paid
22981
+ - amount_remaining
22982
+ - created
22983
+ - hosted_invoice_url
22984
+ - invoice_pdf
22985
+ additionalProperties: false
22986
+ has_more:
22987
+ type: boolean
22988
+ required:
22989
+ - invoices
22990
+ - has_more
22991
+ additionalProperties: false
22992
+ /v1/platform/invoices/{id}:
22993
+ get:
22994
+ operationId: platform_invoices_by_id_get
22995
+ summary: Get a single Stripe invoice by ID
22996
+ description:
22997
+ Pages through the org's invoice list from the platform and returns the invoice matching the given Stripe
22998
+ invoice ID (e.g. in_xxx). 404 if no such invoice.
22999
+ tags:
23000
+ - platform
23001
+ parameters:
23002
+ - name: id
23003
+ in: path
23004
+ required: true
23005
+ schema:
23006
+ type: string
23007
+ responses:
23008
+ "200":
23009
+ description: Successful response
23010
+ content:
23011
+ application/json:
23012
+ schema:
23013
+ type: object
23014
+ properties:
23015
+ id:
23016
+ type: string
23017
+ number:
23018
+ anyOf:
23019
+ - type: string
23020
+ - type: "null"
23021
+ status:
23022
+ anyOf:
23023
+ - type: string
23024
+ - type: "null"
23025
+ currency:
23026
+ type: string
23027
+ amount_due:
23028
+ type: number
23029
+ amount_paid:
23030
+ type: number
23031
+ amount_remaining:
23032
+ type: number
23033
+ created:
23034
+ type: number
23035
+ hosted_invoice_url:
23036
+ anyOf:
23037
+ - type: string
23038
+ - type: "null"
23039
+ invoice_pdf:
23040
+ anyOf:
23041
+ - type: string
23042
+ - type: "null"
23043
+ required:
23044
+ - id
23045
+ - number
23046
+ - status
23047
+ - currency
23048
+ - amount_due
23049
+ - amount_paid
23050
+ - amount_remaining
23051
+ - created
23052
+ - hosted_invoice_url
23053
+ - invoice_pdf
23054
+ additionalProperties: false
22768
23055
  /v1/platform/plans:
22769
23056
  get:
22770
23057
  operationId: platform_plans_get
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.11.1",
3
+ "version": "0.11.2-staging.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Cover for the loop's interrupted-call recovery.
3
+ *
4
+ * The reported failure: the model runs several tools, the next call streams for
5
+ * a while and then dies (the upstream killed a generation that blew its decode
6
+ * deadline), and the loop surfaces the error and ends the turn — leaving the
7
+ * task half-done until the user types "continue". These tests assert the loop
8
+ * now carries on by itself, and that it still stops when carrying on would be
9
+ * pointless.
10
+ *
11
+ * The recovery is built into {@link AgentLoop}, not contributed by a plugin, so
12
+ * these run it as the loop's own behavior. The default plugin stack is
13
+ * registered because the loop fires hook chains during a turn regardless.
14
+ */
15
+
16
+ import { beforeEach, describe, expect, test } from "bun:test";
17
+
18
+ import type { AgentEvent } from "../agent/loop.js";
19
+ import { AgentLoop } from "../agent/loop.js";
20
+ import type { LLMCallSite } from "../config/schemas/llm.js";
21
+ import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
22
+ import type {
23
+ Message,
24
+ Provider,
25
+ ProviderResponse,
26
+ SendMessageOptions,
27
+ ToolDefinition,
28
+ } from "../providers/types.js";
29
+ import { ProviderError } from "../util/errors.js";
30
+
31
+ const tools: ToolDefinition[] = [
32
+ {
33
+ name: "read_file",
34
+ description: "Read a file",
35
+ input_schema: { type: "object", properties: { path: { type: "string" } } },
36
+ },
37
+ ];
38
+
39
+ const userMessage: Message = {
40
+ role: "user",
41
+ content: [{ type: "text", text: "finish the course page" }],
42
+ };
43
+
44
+ /** The rejection from the reported turn, thrown from inside a live stream. */
45
+ function midStreamRejection(): ProviderError {
46
+ return new ProviderError(
47
+ "OpenAI-compatible API error (unknown status): litellm.MidStreamFallbackError: " +
48
+ "litellm.APIConnectionError: OpenAIException - Decode wall clock timeout after 600s",
49
+ "openai-compatible",
50
+ );
51
+ }
52
+
53
+ /** A scripted turn: return a response, or stream `thinking` and then throw. */
54
+ type Turn =
55
+ | { kind: "reply"; response: ProviderResponse }
56
+ | { kind: "interrupt"; thinking: string }
57
+ | { kind: "refuse" };
58
+
59
+ function scriptedProvider(turns: Turn[]): {
60
+ provider: Provider;
61
+ callCount: () => number;
62
+ } {
63
+ let index = 0;
64
+ const provider: Provider = {
65
+ name: "openai-compatible",
66
+ async sendMessage(
67
+ _messages: Message[],
68
+ options?: SendMessageOptions,
69
+ ): Promise<ProviderResponse> {
70
+ const turn = turns[Math.min(index, turns.length - 1)]!;
71
+ index++;
72
+ if (turn.kind === "refuse") {
73
+ // Rejected before generating: nothing ever streams.
74
+ throw midStreamRejection();
75
+ }
76
+ if (turn.kind === "interrupt") {
77
+ options?.onEvent?.({ type: "thinking_delta", thinking: turn.thinking });
78
+ throw midStreamRejection();
79
+ }
80
+ for (const block of turn.response.content) {
81
+ if (block.type === "text") {
82
+ options?.onEvent?.({ type: "text_delta", text: block.text });
83
+ }
84
+ }
85
+ return turn.response;
86
+ },
87
+ };
88
+ return { provider, callCount: () => index };
89
+ }
90
+
91
+ function reply(text: string): Turn {
92
+ return {
93
+ kind: "reply",
94
+ response: {
95
+ content: [{ type: "text", text }],
96
+ model: "glm-5.2",
97
+ usage: { inputTokens: 10, outputTokens: 5 },
98
+ stopReason: "end_turn",
99
+ },
100
+ };
101
+ }
102
+
103
+ function callsTool(id: string): Turn {
104
+ return {
105
+ kind: "reply",
106
+ response: {
107
+ content: [
108
+ { type: "tool_use", id, name: "read_file", input: { path: "app.js" } },
109
+ ],
110
+ model: "glm-5.2",
111
+ usage: { inputTokens: 10, outputTokens: 5 },
112
+ stopReason: "tool_use",
113
+ },
114
+ };
115
+ }
116
+
117
+ function runLoop(provider: Provider, callSite: LLMCallSite = "mainAgent") {
118
+ const events: AgentEvent[] = [];
119
+ const loop = new AgentLoop({
120
+ provider,
121
+ systemPrompt: "system",
122
+ conversationId: "conv-resume-e2e",
123
+ tools,
124
+ toolExecutor: async () => ({ content: "file data", isError: false }),
125
+ });
126
+ return loop
127
+ .run({
128
+ requestId: "req-resume-e2e",
129
+ messages: [userMessage],
130
+ callSite,
131
+ onEvent: (event) => {
132
+ events.push(event);
133
+ },
134
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
135
+ })
136
+ .then((result) => ({ ...result, events }));
137
+ }
138
+
139
+ function assistantTextOf(history: Message[]): string {
140
+ return history
141
+ .filter((message) => message.role === "assistant")
142
+ .flatMap((message) => message.content)
143
+ .map((block) => (block.type === "text" ? block.text : ""))
144
+ .join("");
145
+ }
146
+
147
+ describe("AgentLoop — a call interrupted mid-generation", () => {
148
+ beforeEach(() => {
149
+ resetPluginRegistryAndRegisterDefaults();
150
+ });
151
+
152
+ test("carries on instead of ending the turn", async () => {
153
+ const { provider, callCount } = scriptedProvider([
154
+ callsTool("call-1"),
155
+ { kind: "interrupt", thinking: "Now I need to understand the layout" },
156
+ reply("Done — the page is wired up."),
157
+ ]);
158
+
159
+ const { history, events } = await runLoop(provider);
160
+
161
+ // The turn finished on its own: tool call, interrupted call, resumed call.
162
+ expect(callCount()).toBe(3);
163
+ expect(assistantTextOf(history)).toContain("Done — the page is wired up.");
164
+ expect(events.filter((event) => event.type === "error")).toHaveLength(0);
165
+ });
166
+
167
+ test("keeps the tool work the interrupted turn had already done", async () => {
168
+ const { provider } = scriptedProvider([
169
+ callsTool("call-1"),
170
+ { kind: "interrupt", thinking: "reading the file" },
171
+ reply("Summary of the file."),
172
+ ]);
173
+
174
+ const { history } = await runLoop(provider);
175
+
176
+ // The resumed call re-sends the same history, so the completed tool call
177
+ // and its result are still there rather than being replayed or dropped.
178
+ const toolUses = history
179
+ .flatMap((message) => message.content)
180
+ .filter((block) => block.type === "tool_use");
181
+ const toolResults = history
182
+ .flatMap((message) => message.content)
183
+ .filter((block) => block.type === "tool_result");
184
+ expect(toolUses).toHaveLength(1);
185
+ expect(toolResults).toHaveLength(1);
186
+ });
187
+
188
+ test("surfaces the error when the resumed call is interrupted too", async () => {
189
+ const { provider, callCount } = scriptedProvider([
190
+ { kind: "interrupt", thinking: "starting" },
191
+ ]);
192
+
193
+ const { events } = await runLoop(provider);
194
+
195
+ // One resume, then the error stands rather than looping.
196
+ expect(callCount()).toBe(2);
197
+ expect(events.filter((event) => event.type === "error")).toHaveLength(1);
198
+ });
199
+
200
+ test("does not resume a background call site", async () => {
201
+ // A compaction, subagent, or other background call answers to a caller
202
+ // that owns its own failure handling; nobody is sitting there to type
203
+ // "continue" at it.
204
+ const { provider, callCount } = scriptedProvider([
205
+ { kind: "interrupt", thinking: "summarizing" },
206
+ ]);
207
+
208
+ await runLoop(provider, "compactionAgent");
209
+
210
+ expect(callCount()).toBe(1);
211
+ });
212
+
213
+ test("does not resume a request the provider refused outright", async () => {
214
+ // Nothing streamed, so re-sending the identical request would fail the same
215
+ // way; the error surfaces on the first rejection.
216
+ const { provider, callCount } = scriptedProvider([{ kind: "refuse" }]);
217
+
218
+ const { events } = await runLoop(provider);
219
+
220
+ expect(callCount()).toBe(1);
221
+ expect(events.filter((event) => event.type === "error")).toHaveLength(1);
222
+ });
223
+ });
@@ -1092,4 +1092,47 @@ describe("ensureByokDefaultProfiles", () => {
1092
1092
 
1093
1093
  expect(readFileSync(configPath(), "utf-8")).toBe(before);
1094
1094
  });
1095
+
1096
+ // The hatch wrote each copy's model by resolving the cost profile's intent
1097
+ // at hatch time. These are the ids that resolved per provider, pinned as
1098
+ // literals rather than derived from the template: a test that materializes
1099
+ // the template agrees with itself no matter which intent the template names,
1100
+ // and so cannot catch a template whose model comparison has drifted off what
1101
+ // is on disk.
1102
+ test.each([
1103
+ ["openrouter", "anthropic/claude-haiku-4.5"],
1104
+ ["gemini", "gemini-3.1-flash-lite"],
1105
+ ["openai", "gpt-5.6-luna"],
1106
+ ] as const)(
1107
+ "an unedited %s cost copy still converts",
1108
+ (provider, hatchModel) => {
1109
+ writeConfig({
1110
+ llm: {
1111
+ defaultProvider: { provider },
1112
+ activeProfile: "custom-cost-optimized",
1113
+ profiles: {
1114
+ "custom-cost-optimized": {
1115
+ ...(hatchBody("cost-optimized", provider) as Record<
1116
+ string,
1117
+ unknown
1118
+ >),
1119
+ model: hatchModel,
1120
+ },
1121
+ "custom-balanced": hatchBody("balanced", provider),
1122
+ "custom-quality-optimized": hatchBody(
1123
+ "quality-optimized",
1124
+ provider,
1125
+ ),
1126
+ },
1127
+ },
1128
+ });
1129
+
1130
+ ensureByokDefaultProfiles(workspaceDir);
1131
+
1132
+ expect(profiles()["custom-cost-optimized"]).toBeUndefined();
1133
+ expect(profiles()["cost-optimized"]).toBeUndefined();
1134
+ expect(llm().activeProfile).toBe("cost-optimized");
1135
+ expectSecondRunNoop();
1136
+ },
1137
+ );
1095
1138
  });