@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
@@ -1318,6 +1318,7 @@ describe("UsageTelemetryReporter", () => {
1318
1318
  outcome?: string | null;
1319
1319
  batchedInto?: string | null;
1320
1320
  failureCode?: string | null;
1321
+ scripted?: boolean | null;
1321
1322
  } = {},
1322
1323
  ) {
1323
1324
  return {
@@ -1329,6 +1330,9 @@ describe("UsageTelemetryReporter", () => {
1329
1330
  interfaceId: "macos",
1330
1331
  channelId: "vellum",
1331
1332
  clientMetadata: null,
1333
+ // Defaults to UNKNOWN so existing cases keep asserting the pre-marker
1334
+ // wire shape; each scripted case opts in explicitly.
1335
+ scripted: null,
1332
1336
  ...overrides,
1333
1337
  };
1334
1338
  }
@@ -1588,6 +1592,50 @@ describe("UsageTelemetryReporter", () => {
1588
1592
  expect("failure_code" in byId["evt-cancelled"]).toBe(false);
1589
1593
  });
1590
1594
 
1595
+ test("the scripted marker rides the turn event with all three states distinct", async () => {
1596
+ // `scripted` is what lets activation metrics exclude auto-sent onboarding
1597
+ // turns for EVERY owner rather than only diagnostics-consenting ones
1598
+ // (ANT-10), so its states must stay distinguishable on the wire. Note
1599
+ // diagnostics consent is OFF here: unlike `trace`, this field must ship
1600
+ // regardless: that independence is the entire point of the field.
1601
+ mockGetCachedShareDiagnostics.mockReturnValue(false);
1602
+ mockQueryUnreportedUsageEvents.mockReturnValue([]);
1603
+ useStatefulCheckpoints();
1604
+ mockQueryUnreportedTurnEvents.mockReturnValue([
1605
+ turnEvent("evt-scripted", 1700000010000, "conv-1", { scripted: true }),
1606
+ turnEvent("evt-typed", 1700000011000, "conv-1", { scripted: false }),
1607
+ turnEvent("evt-unknown", 1700000012000, "conv-2", { scripted: null }),
1608
+ ]);
1609
+ mockIsTurnSettled.mockReturnValue(true);
1610
+ mockFetch.mockImplementation(() =>
1611
+ Promise.resolve(new Response('{"accepted":3}', { status: 200 })),
1612
+ );
1613
+
1614
+ const reporter = makeReporter();
1615
+ await reporter.flush();
1616
+
1617
+ const body = JSON.parse(
1618
+ (mockFetch.mock.calls[0] as [string, RequestInit])[1].body as string,
1619
+ );
1620
+ const byId = Object.fromEntries(
1621
+ body.events.map((e: { daemon_event_id: string }) => [
1622
+ e.daemon_event_id,
1623
+ e,
1624
+ ]),
1625
+ );
1626
+ expect(byId["evt-scripted"].scripted).toBe(true);
1627
+ // The state most at risk: an omit-when-falsy spread would drop this and
1628
+ // silently downgrade a turn we KNOW was typed into "unknown", handing
1629
+ // activation back to the consent-gated classifier this field replaces.
1630
+ expect("scripted" in byId["evt-typed"]).toBe(true);
1631
+ expect(byId["evt-typed"].scripted).toBe(false);
1632
+ // A row predating the marker stays UNKNOWN: the key is absent, so the
1633
+ // wire shape is byte-identical to a pre-scripted turn event and
1634
+ // downstream falls back to the trace classifier rather than being told
1635
+ // something untrue about the turn.
1636
+ expect("scripted" in byId["evt-unknown"]).toBe(false);
1637
+ });
1638
+
1591
1639
  test("an unrecognized outcome value in metadata is dropped from the wire", async () => {
1592
1640
  mockGetCachedShareDiagnostics.mockReturnValue(false);
1593
1641
  mockQueryUnreportedUsageEvents.mockReturnValue([]);
@@ -14,7 +14,9 @@
14
14
  * `host_browser_session_invalidated`.
15
15
  */
16
16
 
17
- import { log } from "../../cli/logger.js";
17
+ import { getLogger } from "../../util/logger.js";
18
+
19
+ const log = getLogger("pinned-tabs");
18
20
 
19
21
  const pinnedTabs = new Map<string, Map<string, string>>();
20
22
 
@@ -10,6 +10,7 @@ import {
10
10
  getMessages,
11
11
  } from "../../persistence/conversation-crud.js";
12
12
  import type { ContentBlock, Message } from "../../providers/types.js";
13
+ import { buildAdvisorContext } from "../../subagent/consult-context.js";
13
14
  import {
14
15
  advisorRequestText,
15
16
  buildAdvisorSystem,
@@ -293,6 +294,23 @@ async function runAdvisorConsult(args: {
293
294
  );
294
295
  const sanitizedMessages = sanitizeConsultTranscript(withInFlight);
295
296
 
297
+ // Situational awareness for the advisor: the parent's live tool set, the
298
+ // full skill catalog, and its workspace. Assembled off the per-turn
299
+ // ToolContext snapshot (trust, channel) so the personal-memory sections
300
+ // are gated exactly like the runtime injectors. Best-effort: a null pack
301
+ // just means the consult runs on transcript + system prompt alone.
302
+ const situationalContext = await buildAdvisorContext({
303
+ conversationId: context.conversationId,
304
+ workingDir: context.workingDir,
305
+ allowedToolNames: context.allowedToolNames,
306
+ trustClass: context.trustClass,
307
+ sourceChannel: context.executionChannel,
308
+ enabledPluginSet: context.enabledPluginSet,
309
+ // The parent's warm per-turn catalog keeps the synchronous on-disk
310
+ // catalog scan out of the consult path.
311
+ skillCatalog: parentConversation.skillProjectionCache?.catalog,
312
+ });
313
+
296
314
  // Default to the stronger advisor profile when the caller did not pin one;
297
315
  // an explicit `inference_profile` wins (already forced upstream).
298
316
  const advisorProfile = getConfig().llm.advisorProfile;
@@ -322,8 +340,12 @@ async function runAdvisorConsult(args: {
322
340
  parentConversationId: context.conversationId,
323
341
  label,
324
342
  // Carry the agent's own objective into the consult request — the
325
- // agent states the task here, and the inherited transcript can be thin.
343
+ // agent states the task here, and the inherited transcript can be
344
+ // thin. The situational pack rides in the model request only
345
+ // (`requestText`), keeping the system prompt minimal and the
346
+ // display-facing `objective` free of bulky internal context.
326
347
  objective: advisorRequestText(objective),
348
+ requestText: advisorRequestText(objective, situationalContext),
327
349
  sendResultToUser: false,
328
350
  role: "advisor",
329
351
  fork: true,
@@ -70,6 +70,7 @@ export const SAFE_ENV_VARS = [
70
70
  "VELLUM_PROFILER_MIN_FREE_MB",
71
71
  "VELLUM_MEMORY_LIMIT",
72
72
  "VELLUM_CPU_LIMIT",
73
+ "VELLUM_ONNX_INTRA_OP_THREADS",
73
74
  "VELLUM_MINIKUBE_STORAGE_SIZE",
74
75
  "VELLUM_BACKUP_DIR",
75
76
  "VELLUM_BACKUP_KEY_PATH",
@@ -7,7 +7,10 @@
7
7
  * handled locally by the daemon.
8
8
  */
9
9
 
10
- import { coerceSurfaceDataRecord } from "../../api/surfaces.js";
10
+ import {
11
+ coerceSurfaceDataRecord,
12
+ normalizeVisualShowData,
13
+ } from "../../api/surfaces.js";
11
14
  import { RiskLevel } from "../../permissions/types.js";
12
15
  import { isWeakOpenModel } from "../../providers/weak-open-model.js";
13
16
  import type {
@@ -22,6 +25,7 @@ import {
22
25
  UI_SHOW_TYPE_DOCS,
23
26
  uiShowTeachingError,
24
27
  } from "./surface-shape-docs.js";
28
+ import { validateVisualHtml } from "./visual-validation.js";
25
29
 
26
30
  // ---------------------------------------------------------------------------
27
31
  // Helpers
@@ -59,6 +63,13 @@ function proxyExecute(toolName: string) {
59
63
  };
60
64
  }
61
65
 
66
+ if (toolName === "ui_show" && input.surface_type === "visual") {
67
+ const visualError = visualTeachingError(input);
68
+ if (visualError !== null) {
69
+ return { content: visualError, isError: true };
70
+ }
71
+ }
72
+
62
73
  if (toolName === "ui_show" && isDynamicPageAppSubstitute(input)) {
63
74
  return {
64
75
  content:
@@ -197,6 +208,33 @@ function isSubstantialInteractiveHtml(input: Record<string, unknown>): boolean {
197
208
  return html.length > 2000 && INTERACTIVE_HTML_RE.test(html);
198
209
  }
199
210
 
211
+ /**
212
+ * Teaching error for a `visual` ui_show whose fragment would not render as
213
+ * intended, or null when it is sound. The checks run before proxying because
214
+ * the sandbox fails silently: an external resource never loads and an
215
+ * unknown `var()` resolves to nothing, so the user sees a blank or unthemed
216
+ * widget while the model believes it rendered.
217
+ */
218
+ function visualTeachingError(input: Record<string, unknown>): string | null {
219
+ const { html } = normalizeVisualShowData(
220
+ input,
221
+ coerceSurfaceDataRecord(input.data),
222
+ );
223
+ if (html.trim().length === 0) {
224
+ return "Error: ui_show visual requires a non-empty HTML fragment in `data.html`. The surface was not displayed because no markup was provided — the user would see a blank box. Resend ui_show with the complete self-contained fragment in `data.html`.";
225
+ }
226
+
227
+ const problems = validateVisualHtml(html);
228
+ if (problems.length === 0) {
229
+ return null;
230
+ }
231
+ return (
232
+ "Error: ui_show visual was not displayed — the fragment does not meet the sandbox contract:\n" +
233
+ problems.map((problem) => `- ${problem}`).join("\n") +
234
+ "\nFix every item above and call ui_show again."
235
+ );
236
+ }
237
+
200
238
  function collectRoutingText(input: Record<string, unknown>): string[] {
201
239
  const values: string[] = [];
202
240
  addString(values, input.title);
@@ -18,6 +18,7 @@
18
18
 
19
19
  import {
20
20
  coerceSurfaceDataRecord,
21
+ describeSurfaceDataStringParseFailure,
21
22
  FileUploadSurfaceDataSchema,
22
23
  normalizeCopyBlockShowData,
23
24
  } from "../../api/surfaces.js";
@@ -66,7 +67,8 @@ interface SurfaceShapeDoc {
66
67
  * Returns a description of what keeps the payload from rendering as intended
67
68
  * — missing load-bearing content, or keys that would be silently dropped —
68
69
  * or null when the payload is fine. Absent for types the daemon normalizes
69
- * leniently (card) or that have bespoke handling (dynamic_page). Guards for
70
+ * leniently (card) or that have bespoke handling (dynamic_page, visual).
71
+ * Guards for
70
72
  * types whose daemon normalizer recovers top-level input fields also receive
71
73
  * the full tool `input`, so the guard accepts exactly what the normalizer
72
74
  * accepts.
@@ -193,6 +195,12 @@ export const SURFACE_SHAPE_DOCS: Record<string, SurfaceShapeDoc> = {
193
195
  shape:
194
196
  "{ html, width?, height?, preview?: { title, subtitle?, description?, icon?, metrics?: [{ label, value }] } } — custom visual HTML for transient surfaces only, never app-like builds",
195
197
  },
198
+ visual: {
199
+ purpose:
200
+ "polished inline diagram/chart/explainer — PREFER this when explaining how something works or compares; load the `visualize` skill first",
201
+ shape:
202
+ "{ html, height? } — one self-contained HTML/SVG fragment (no DOCTYPE/html/head/body, no external resources); every colour comes from the injected design-token CSS variables, so hex/rgb literals and invented `var()` names are rejected. Load the `visualize` skill with `skill_load` for the full contract and the token vocabulary",
203
+ },
196
204
  channel_setup: {
197
205
  purpose: "open the Slack/Telegram/Phone setup panel",
198
206
  shape: '{ channel: "slack" | "telegram" | "phone" }',
@@ -243,12 +251,34 @@ export const UI_SHOW_TYPE_DOCS = [
243
251
  `Other types: ${COLD_SURFACE_INDEX}. Send your best-guess data — if required content is missing, the error returns the exact shape.`,
244
252
  ].join("\n");
245
253
 
254
+ /**
255
+ * Rejection envelope for a `data` argument the model double-encoded as a JSON
256
+ * string that does not parse — most often HTML whose inner double quotes were
257
+ * escaped wrong. The decode failure strands every field, so without this the
258
+ * surface's own shape check fires and blames the first field it misses, sending
259
+ * the model off to fix a fragment that was never the problem.
260
+ */
261
+ function surfaceDataEncodingError(
262
+ surfaceType: string,
263
+ detail: string,
264
+ shape: string,
265
+ ): string {
266
+ return (
267
+ `Error: ui_show ${surfaceType} was not displayed — \`data\` arrived as a JSON-encoded string that could not be parsed: ${detail}. ` +
268
+ "None of its fields could be read, so the surface looked empty. This is an argument-encoding problem, not a problem with the content itself. " +
269
+ `Pass \`data\` as a JSON object rather than a string: ${shape}. ` +
270
+ "If the content is HTML with double quotes inside, use single quotes for the HTML attributes (<rect class='box'>) so there is nothing to escape. " +
271
+ "Resend the same ui_show with `data` as an object."
272
+ );
273
+ }
274
+
246
275
  /**
247
276
  * Teaching error for a ui_show payload that would render nothing, or null
248
277
  * when the payload is displayable. Unknown/missing surface_type gets the
249
- * full type index; a known type missing its load-bearing content gets that
250
- * type's exact shape. dynamic_page emptiness is handled by the bespoke
251
- * model-aware envelopes in `definitions.ts`, not here.
278
+ * full type index; an undecodable JSON-string `data` gets the encoding
279
+ * envelope; a known type missing its load-bearing content gets that type's
280
+ * exact shape. dynamic_page emptiness and the `visual` fragment checks are
281
+ * handled by the bespoke envelopes in `definitions.ts`, not here.
252
282
  */
253
283
  export function uiShowTeachingError(
254
284
  input: Record<string, unknown>,
@@ -265,6 +295,10 @@ export function uiShowTeachingError(
265
295
  return `Error: ui_show was not displayed — ${got}. Valid types: ${SURFACE_TYPE_INDEX}. Resend ui_show with one of these surface_type values; if a type's data is missing required content, the error will include its exact shape.`;
266
296
  }
267
297
  const doc = SURFACE_SHAPE_DOCS[surfaceType]!;
298
+ const parseFailure = describeSurfaceDataStringParseFailure(input.data);
299
+ if (parseFailure !== null) {
300
+ return surfaceDataEncodingError(surfaceType, parseFailure, doc.shape);
301
+ }
268
302
  if (!doc.missingContent) {
269
303
  return null;
270
304
  }