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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +8 -0
  3. package/docs/activation-funnel-telemetry.md +13 -7
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  7. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  9. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  12. package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  13. package/openapi.yaml +530 -107
  14. package/package.json +1 -1
  15. package/scripts/generate-openapi.ts +8 -0
  16. package/src/__tests__/activation-early-marking.test.ts +6 -5
  17. package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
  18. package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
  19. package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
  20. package/src/__tests__/app-bundler.test.ts +4 -12
  21. package/src/__tests__/app-executors.test.ts +2 -49
  22. package/src/__tests__/app-routes-csp.test.ts +114 -146
  23. package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
  24. package/src/__tests__/build-persisted-content.test.ts +96 -0
  25. package/src/__tests__/bundle-scanner.test.ts +27 -1
  26. package/src/__tests__/call-controller.test.ts +291 -0
  27. package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
  28. package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
  29. package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
  30. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  31. package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
  32. package/src/__tests__/config-loader-backfill.test.ts +9 -4
  33. package/src/__tests__/config-schema-cmd.test.ts +10 -11
  34. package/src/__tests__/config-schema.test.ts +190 -257
  35. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
  37. package/src/__tests__/conversation-agent-loop.test.ts +22 -9
  38. package/src/__tests__/conversation-error.test.ts +31 -0
  39. package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
  40. package/src/__tests__/conversation-process-callsite.test.ts +12 -19
  41. package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
  42. package/src/__tests__/conversation-summarize-route.test.ts +36 -44
  43. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  44. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
  45. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
  46. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
  47. package/src/__tests__/conversation-usage.test.ts +4 -12
  48. package/src/__tests__/credential-routes.test.ts +250 -0
  49. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  50. package/src/__tests__/db-migration-rollback.test.ts +22 -0
  51. package/src/__tests__/empty-response-hook.test.ts +186 -1
  52. package/src/__tests__/external-plugin-loader.test.ts +11 -5
  53. package/src/__tests__/heartbeat-service.test.ts +0 -28
  54. package/src/__tests__/host-shell-tool.test.ts +2 -0
  55. package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
  56. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
  57. package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
  58. package/src/__tests__/invite-routes-http.test.ts +12 -16
  59. package/src/__tests__/list-all-apps.test.ts +0 -4
  60. package/src/__tests__/llm-context-resolution.test.ts +32 -56
  61. package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
  62. package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
  63. package/src/__tests__/llm-resolver.test.ts +342 -602
  64. package/src/__tests__/llm-schema.test.ts +79 -37
  65. package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
  66. package/src/__tests__/media-stream-output.test.ts +259 -3
  67. package/src/__tests__/media-stream-server-integration.test.ts +22 -1
  68. package/src/__tests__/media-stream-stt-session.test.ts +47 -0
  69. package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
  70. package/src/__tests__/memory-recall-log-store.test.ts +47 -13
  71. package/src/__tests__/mock-gateway-ipc.ts +46 -1
  72. package/src/__tests__/mtime-cache.test.ts +61 -0
  73. package/src/__tests__/navigate-settings-tab.test.ts +2 -0
  74. package/src/__tests__/normalize-onboarding.test.ts +33 -0
  75. package/src/__tests__/onboarding-persona-write.test.ts +26 -0
  76. package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
  77. package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
  78. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
  79. package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
  80. package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
  81. package/src/__tests__/provider-connections-backfill.test.ts +138 -0
  82. package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
  83. package/src/__tests__/provider-registry-ollama.test.ts +8 -18
  84. package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
  85. package/src/__tests__/provider-usage-tracking.test.ts +9 -19
  86. package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
  87. package/src/__tests__/published-app-updater.test.ts +22 -16
  88. package/src/__tests__/registry.test.ts +5 -16
  89. package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
  90. package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
  91. package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
  92. package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
  93. package/src/__tests__/reveal-success-registry.test.ts +123 -0
  94. package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
  95. package/src/__tests__/secret-fixtures.ts +9 -0
  96. package/src/__tests__/server-history-render.test.ts +28 -0
  97. package/src/__tests__/skills.test.ts +9 -4
  98. package/src/__tests__/slack-share-routes.test.ts +0 -1
  99. package/src/__tests__/stt-stream-session.test.ts +6 -5
  100. package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
  101. package/src/__tests__/subagent-disposal.test.ts +2 -0
  102. package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
  103. package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
  104. package/src/__tests__/subagent-manager-notify.test.ts +2 -0
  105. package/src/__tests__/subagent-role-registry.test.ts +37 -0
  106. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  107. package/src/__tests__/subagent-terminal-message.test.ts +50 -0
  108. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
  109. package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
  110. package/src/__tests__/telemetry-routes.test.ts +99 -19
  111. package/src/__tests__/tool-audit.test.ts +34 -4
  112. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  113. package/src/__tests__/tool-profiler.test.ts +72 -1
  114. package/src/__tests__/tool-result-spool.test.ts +49 -4
  115. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
  116. package/src/__tests__/ui-channel-variants.test.ts +108 -0
  117. package/src/__tests__/ui-shape-teaching.test.ts +255 -0
  118. package/src/__tests__/usage-attribution.test.ts +18 -41
  119. package/src/__tests__/user-plugin-loader.test.ts +4 -4
  120. package/src/__tests__/voice-config-update.test.ts +46 -0
  121. package/src/__tests__/voice-session-bridge.test.ts +216 -84
  122. package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
  123. package/src/agent/loop.ts +4 -3
  124. package/src/api/events/open-conversation.test.ts +64 -0
  125. package/src/api/events/open-conversation.ts +33 -0
  126. package/src/api/index.ts +6 -0
  127. package/src/api/responses/conversation-message.ts +5 -0
  128. package/src/apps/app-store.ts +25 -35
  129. package/src/bundler/app-bundler.ts +34 -48
  130. package/src/bundler/app-compiler.ts +39 -4
  131. package/src/bundler/bundle-scanner.ts +13 -0
  132. package/src/bundler/manifest.ts +1 -1
  133. package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
  134. package/src/calls/call-constants.ts +5 -0
  135. package/src/calls/call-controller.ts +100 -32
  136. package/src/calls/call-transport.ts +9 -0
  137. package/src/calls/media-stream-output.ts +107 -4
  138. package/src/calls/media-stream-server.ts +29 -9
  139. package/src/calls/media-stream-stt-session.ts +7 -1
  140. package/src/calls/media-turn-detector.ts +11 -1
  141. package/src/calls/voice-session-bridge.ts +84 -63
  142. package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
  143. package/src/cli/commands/__tests__/notifications.test.ts +24 -3
  144. package/src/cli/commands/config.help.ts +6 -6
  145. package/src/cli/commands/credentials.help.ts +13 -0
  146. package/src/cli/commands/credentials.ts +6 -1
  147. package/src/cli/commands/email.help.ts +7 -0
  148. package/src/cli/commands/email.ts +35 -1
  149. package/src/cli/commands/inference-providers.ts +168 -107
  150. package/src/cli/commands/inference.help.ts +118 -46
  151. package/src/cli/commands/memory/index.help.ts +23 -0
  152. package/src/cli/commands/memory/nodes.ts +146 -0
  153. package/src/cli/commands/notifications.help.ts +10 -10
  154. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
  155. package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
  156. package/src/cli/commands/oauth/connect.test.ts +126 -0
  157. package/src/cli/commands/oauth/connect.ts +29 -6
  158. package/src/cli/commands/oauth/index.help.ts +7 -1
  159. package/src/cli/commands/oauth/status.test.ts +69 -3
  160. package/src/cli/commands/oauth/status.ts +50 -12
  161. package/src/cli/commands/plugins.help.ts +13 -2
  162. package/src/cli/commands/plugins.ts +61 -7
  163. package/src/cli/commands/telemetry.help.ts +13 -0
  164. package/src/cli/commands/telemetry.ts +45 -5
  165. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
  166. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
  167. package/src/cli/lib/bundled-marketplace.json +93 -36
  168. package/src/cli/lib/inspect-plugin.ts +5 -1
  169. package/src/cli/lib/install-from-github.ts +68 -4
  170. package/src/cli/lib/plugin-catalog-local.ts +6 -2
  171. package/src/cli/lib/plugin-fingerprint.ts +3 -3
  172. package/src/cli/lib/upgrade-plugin.ts +236 -35
  173. package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
  174. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
  175. package/src/config/__tests__/profile-materialization.test.ts +1 -88
  176. package/src/config/bundled-skills/AGENTS.md +3 -30
  177. package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
  178. package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
  179. package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
  180. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  181. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
  182. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  183. package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
  184. package/src/config/bundled-skills/settings/TOOLS.json +3 -1
  185. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
  186. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
  187. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  188. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  189. package/src/config/call-site-defaults.ts +3 -3
  190. package/src/config/feature-flag-registry.json +24 -39
  191. package/src/config/llm-resolver.ts +88 -475
  192. package/src/config/profile-materialization.ts +11 -11
  193. package/src/config/schema.ts +93 -127
  194. package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
  195. package/src/config/schemas/__tests__/stt.test.ts +31 -3
  196. package/src/config/schemas/live-voice.ts +10 -4
  197. package/src/config/schemas/llm.ts +52 -15
  198. package/src/config/schemas/memory-lifecycle.ts +1 -1
  199. package/src/config/schemas/memory-retrospective.ts +8 -0
  200. package/src/config/schemas/memory-v2.ts +2 -2
  201. package/src/config/schemas/memory-v3.ts +1 -1
  202. package/src/config/schemas/services.ts +6 -3
  203. package/src/config/schemas/stt.ts +38 -21
  204. package/src/config/schemas/tts.ts +13 -18
  205. package/src/config/skills.ts +31 -21
  206. package/src/context/compactor.ts +44 -7
  207. package/src/context/post-turn-tool-result-truncation.ts +4 -2
  208. package/src/context/tool-result-spool.ts +26 -5
  209. package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
  210. package/src/conversations/message-consolidation.ts +22 -2
  211. package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
  212. package/src/daemon/app-source-watcher.ts +17 -23
  213. package/src/daemon/chat-credential-redaction.ts +1365 -0
  214. package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
  215. package/src/daemon/conversation-agent-loop.ts +71 -31
  216. package/src/daemon/conversation-error.ts +36 -14
  217. package/src/daemon/conversation-process.ts +22 -0
  218. package/src/daemon/conversation-store.ts +35 -0
  219. package/src/daemon/conversation-surfaces.ts +25 -25
  220. package/src/daemon/conversation-tool-setup.ts +33 -7
  221. package/src/daemon/conversation.ts +55 -5
  222. package/src/daemon/handlers/shared.ts +33 -2
  223. package/src/daemon/lifecycle.ts +4 -4
  224. package/src/daemon/message-types/conversations.ts +6 -17
  225. package/src/daemon/providers-setup.ts +8 -0
  226. package/src/daemon/tool-setup-types.ts +7 -1
  227. package/src/daemon/wake-conversation-ops.ts +10 -1
  228. package/src/hooks/types.ts +9 -0
  229. package/src/ipc/__tests__/email-ipc.test.ts +90 -0
  230. package/src/ipc/gateway-client.test.ts +59 -0
  231. package/src/ipc/gateway-client.ts +70 -27
  232. package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
  233. package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
  234. package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
  235. package/src/live-voice/__tests__/protocol.test.ts +122 -0
  236. package/src/live-voice/live-voice-session.ts +443 -40
  237. package/src/live-voice/protocol.ts +143 -1
  238. package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
  239. package/src/monitoring/plugin-source-watch.ts +3 -62
  240. package/src/notifications/README.md +1 -1
  241. package/src/permissions/checker.ts +8 -4
  242. package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
  243. package/src/persistence/conversation-crud.ts +104 -2
  244. package/src/persistence/db-init.ts +14 -3
  245. package/src/persistence/job-handlers/cleanup.ts +15 -7
  246. package/src/persistence/llm-request-log-store.ts +88 -52
  247. package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
  248. package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
  249. package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
  250. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
  251. package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
  252. package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
  253. package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
  254. package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
  255. package/src/persistence/migrations/helpers/relocation.ts +44 -1
  256. package/src/persistence/migrations/run-migrations.ts +25 -1
  257. package/src/persistence/schema/infrastructure.ts +9 -0
  258. package/src/persistence/schema/memory-core.ts +3 -0
  259. package/src/persistence/schema/memory-injection.ts +2 -0
  260. package/src/persistence/steps.ts +36 -0
  261. package/src/platform/client.test.ts +1 -44
  262. package/src/platform/client.ts +10 -20
  263. package/src/platform/consent-cache.test.ts +89 -23
  264. package/src/platform/consent-cache.ts +71 -33
  265. package/src/plugin-api/constants.ts +12 -0
  266. package/src/plugin-api/conversation-turn.ts +37 -14
  267. package/src/plugin-api/index.ts +11 -1
  268. package/src/plugin-api/resolve-credential.ts +75 -0
  269. package/src/plugin-api/vision-support.test.ts +8 -19
  270. package/src/plugin-api/vision-support.ts +26 -17
  271. package/src/plugins/collect-source-versions.ts +77 -0
  272. package/src/plugins/defaults/compaction/compact.ts +6 -0
  273. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
  275. package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
  276. package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
  277. package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
  278. package/src/plugins/defaults/index.ts +8 -1
  279. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
  280. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
  281. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
  282. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
  283. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
  284. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
  285. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
  286. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
  287. package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
  288. package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
  289. package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
  290. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
  291. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
  292. package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
  293. package/src/plugins/defaults/memory/graph/store.ts +114 -0
  294. package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
  295. package/src/plugins/defaults/memory/graph/tools.ts +47 -13
  296. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
  297. package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
  298. package/src/plugins/defaults/memory/memory-db.ts +3 -2
  299. package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
  300. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
  301. package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
  302. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
  303. package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
  304. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
  305. package/src/plugins/defaults/memory/path-containment.ts +21 -0
  306. package/src/plugins/defaults/memory/prompt-override.ts +51 -13
  307. package/src/plugins/defaults/memory/tools.test.ts +34 -0
  308. package/src/plugins/defaults/memory/tools.ts +12 -2
  309. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
  310. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
  311. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
  312. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
  313. package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
  314. package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
  315. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
  316. package/src/plugins/defaults/memory/v2/migration.ts +46 -16
  317. package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
  318. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
  319. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
  320. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
  321. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
  322. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
  323. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
  324. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
  325. package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
  326. package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
  327. package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
  328. package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
  329. package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
  330. package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
  331. package/src/plugins/defaults/memory/v3/prune.ts +17 -11
  332. package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
  333. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
  334. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
  335. package/src/plugins/external-plugin-loader.ts +15 -15
  336. package/src/plugins/mtime-cache.ts +47 -0
  337. package/src/plugins/pipeline.ts +9 -1
  338. package/src/plugins/plugin-execution-context.ts +44 -0
  339. package/src/plugins/plugin-tree-walk.ts +31 -24
  340. package/src/plugins/source-fingerprint.ts +3 -4
  341. package/src/prompts/normalize-onboarding.ts +12 -0
  342. package/src/prompts/persona-resolver.ts +8 -0
  343. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
  344. package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
  345. package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
  346. package/src/providers/__tests__/retry-callsite.test.ts +235 -215
  347. package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
  348. package/src/providers/atlascloud/client.ts +10 -49
  349. package/src/providers/baseten/client.ts +43 -0
  350. package/src/providers/call-site-routing.ts +26 -13
  351. package/src/providers/connection-resolution.ts +9 -11
  352. package/src/providers/fetch-provider-catalog.ts +4 -2
  353. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
  354. package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
  355. package/src/providers/inference/adapter-factory.ts +27 -6
  356. package/src/providers/inference/auth.ts +29 -1
  357. package/src/providers/inference/backfill.ts +61 -10
  358. package/src/providers/inference/connection-availability.ts +3 -2
  359. package/src/providers/inference/resolve-auth.ts +9 -1
  360. package/src/providers/model-catalog.ts +37 -0
  361. package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
  362. package/src/providers/openai/api-key-validation.ts +70 -0
  363. package/src/providers/retry.ts +2 -0
  364. package/src/providers/types.ts +11 -4
  365. package/src/providers/vellum-model-routing.test.ts +26 -0
  366. package/src/providers/vellum-model-routing.ts +30 -0
  367. package/src/providers/voice-error-copy.ts +47 -0
  368. package/src/runtime/agent-wake.ts +40 -24
  369. package/src/runtime/for-chat-mint-registry.ts +118 -0
  370. package/src/runtime/reveal-nonce.ts +49 -0
  371. package/src/runtime/reveal-success-registry.ts +306 -0
  372. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
  373. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
  374. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
  375. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
  376. package/src/runtime/routes/app-management-routes.ts +152 -45
  377. package/src/runtime/routes/app-routes.ts +16 -77
  378. package/src/runtime/routes/canned-message-complete.ts +16 -16
  379. package/src/runtime/routes/conversation-management-routes.ts +17 -14
  380. package/src/runtime/routes/conversation-query-routes.ts +54 -6
  381. package/src/runtime/routes/conversation-routes.ts +48 -2
  382. package/src/runtime/routes/credential-routes.ts +116 -3
  383. package/src/runtime/routes/email-routes.ts +17 -1
  384. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
  385. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
  386. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
  387. package/src/runtime/routes/inference-send-routes.ts +1 -1
  388. package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
  389. package/src/runtime/routes/plugins-routes.ts +37 -6
  390. package/src/runtime/routes/publish-routes.ts +15 -18
  391. package/src/runtime/routes/schedule-worker-routes.ts +9 -0
  392. package/src/runtime/routes/secret-routes.ts +10 -0
  393. package/src/runtime/routes/telemetry-routes.ts +149 -45
  394. package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
  395. package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
  396. package/src/schedule/schedule-store.ts +12 -1
  397. package/src/schedule/schedule-timezone.ts +63 -0
  398. package/src/schedule/scheduler.ts +100 -6
  399. package/src/schedule/worker-control.ts +19 -0
  400. package/src/security/auth-fallback-events-store.ts +7 -6
  401. package/src/security/secret-scanner.ts +26 -1
  402. package/src/services/published-app-updater.ts +6 -11
  403. package/src/stt/stt-stream-session.ts +36 -16
  404. package/src/subagent/manager.ts +34 -8
  405. package/src/telemetry/AGENTS.md +30 -1
  406. package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
  407. package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
  408. package/src/telemetry/config-setting-snapshot.ts +44 -10
  409. package/src/telemetry/telemetry-event-sources.test.ts +124 -30
  410. package/src/telemetry/telemetry-event-sources.ts +137 -83
  411. package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
  412. package/src/telemetry/telemetry-events-outbox.ts +60 -9
  413. package/src/telemetry/telemetry-wire-source.json +1 -1
  414. package/src/telemetry/telemetry-wire-validation.ts +39 -2
  415. package/src/telemetry/telemetry-wire.generated.ts +8 -0
  416. package/src/telemetry/tool-audit.ts +15 -9
  417. package/src/telemetry/tool-executed-events-store.test.ts +1 -1
  418. package/src/telemetry/turn-events-store.ts +20 -0
  419. package/src/telemetry/types.ts +45 -12
  420. package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
  421. package/src/telemetry/usage-telemetry-reporter.ts +117 -18
  422. package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
  423. package/src/telemetry/watchdog-direct-emit.ts +11 -6
  424. package/src/tools/apps/executors.ts +11 -36
  425. package/src/tools/executor.ts +14 -1
  426. package/src/tools/host-terminal/host-shell.ts +6 -2
  427. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
  428. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
  429. package/src/tools/network/web-fetch.ts +6 -2
  430. package/src/tools/skills/sandbox-runner.ts +5 -2
  431. package/src/tools/subagent/spawn.ts +7 -11
  432. package/src/tools/terminal/shell.ts +5 -2
  433. package/src/tools/tool-manifest.ts +0 -2
  434. package/src/tools/tool-profiler.ts +37 -6
  435. package/src/tools/ui-surface/channel-variants.ts +101 -0
  436. package/src/tools/ui-surface/definitions.ts +23 -67
  437. package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
  438. package/src/tts/__tests__/provider-adapters.test.ts +18 -0
  439. package/src/tts/provider-catalog.ts +2 -4
  440. package/src/tts/providers/deepgram-provider.ts +10 -1
  441. package/src/types/onboarding-context.ts +8 -0
  442. package/src/usage/attribution.ts +18 -112
  443. package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
  444. package/src/util/provider-error-patterns.ts +7 -1
  445. package/src/util/worker-process.ts +105 -0
  446. package/src/watcher/__tests__/telemetry.test.ts +17 -4
  447. package/src/watcher/telemetry.ts +5 -5
  448. package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
  449. package/src/workspace/migrations/registry.ts +2 -0
  450. package/src/workspace/provider-commit-message-generator.ts +6 -4
  451. package/src/__tests__/app-open-proxy.test.ts +0 -67
  452. package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
  453. package/src/onboarding/onboarding-research-events-store.ts +0 -104
  454. package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
  455. package/src/tools/apps/definitions.ts +0 -73
  456. package/src/tools/apps/open-proxy.ts +0 -43
@@ -10,6 +10,7 @@ import {
10
10
  } from "./__tests__/outbox-test-harness.js";
11
11
  import {
12
12
  deleteTelemetryOutboxEvents,
13
+ deleteTelemetryOutboxEventsBefore,
13
14
  discardPendingTelemetryOutboxEvents,
14
15
  insertTelemetryOutboxEvent,
15
16
  insertTelemetryOutboxEvents,
@@ -290,7 +291,7 @@ describe("telemetry-events-outbox", () => {
290
291
  );
291
292
  });
292
293
 
293
- test("recordTelemetryEvent honors the share_analytics opt-out", () => {
294
+ test("recordTelemetryEvent honors a confirmed share_analytics opt-out", () => {
294
295
  setShareAnalytics(false);
295
296
  expect(
296
297
  recordTelemetryEvent("watchdog", {
@@ -302,6 +303,19 @@ describe("telemetry-events-outbox", () => {
302
303
  expect(queryTelemetryOutboxBatch("watchdog", 10)).toEqual([]);
303
304
  });
304
305
 
306
+ test("recordTelemetryEvent records while consent is unknown (cold cache)", () => {
307
+ setShareAnalytics("unknown");
308
+ const recorded = recordTelemetryEvent("watchdog", {
309
+ check_name: "c",
310
+ value: null,
311
+ detail: null,
312
+ });
313
+ expect(recorded).not.toBeNull();
314
+ expect(queryTelemetryOutboxBatch("watchdog", 10).map((r) => r.id)).toEqual([
315
+ recorded!.id,
316
+ ]);
317
+ });
318
+
305
319
  test("recordTelemetryEvent returns null when the telemetry DB is unavailable", () => {
306
320
  withTelemetryDbUnavailable(() => {
307
321
  expect(
@@ -315,6 +329,37 @@ describe("telemetry-events-outbox", () => {
315
329
  expect(queryTelemetryOutboxBatch("watchdog", 10)).toEqual([]);
316
330
  });
317
331
 
332
+ test("prune deletes rows strictly older than the cutoff across every name and returns the count", () => {
333
+ insert("evt-old-life", 1000, "lifecycle");
334
+ insert("evt-old-watch", 1500, "watchdog");
335
+ insert("evt-at-cutoff", 2000, "lifecycle");
336
+ insert("evt-fresh", 3000, "lifecycle");
337
+
338
+ expect(deleteTelemetryOutboxEventsBefore(2000)).toBe(2);
339
+
340
+ // Strictly-before semantics: the row AT the cutoff is retained.
341
+ expect(allIds()).toEqual(["evt-at-cutoff", "evt-fresh"]);
342
+ expect(queryTelemetryOutboxBatch("watchdog", 10)).toEqual([]);
343
+ });
344
+
345
+ test("prune with nothing expired deletes nothing and returns 0", () => {
346
+ insert("evt-1", 5000);
347
+
348
+ expect(deleteTelemetryOutboxEventsBefore(5000)).toBe(0);
349
+
350
+ expect(allIds()).toEqual(["evt-1"]);
351
+ });
352
+
353
+ test("prune returns 0 when the telemetry DB is unavailable", () => {
354
+ insert("evt-1", 1000);
355
+
356
+ withTelemetryDbUnavailable(() => {
357
+ expect(deleteTelemetryOutboxEventsBefore(2000)).toBe(0);
358
+ });
359
+
360
+ expect(allIds()).toEqual(["evt-1"]);
361
+ });
362
+
318
363
  test("discards all pending rows for one name only", () => {
319
364
  insert("evt-1", 1000, "lifecycle");
320
365
  insert("evt-2", 2000, "lifecycle");
@@ -9,9 +9,9 @@
9
9
  import { asc, eq, inArray } from "drizzle-orm";
10
10
  import { v4 as uuid } from "uuid";
11
11
 
12
- import { getTelemetryDb } from "../persistence/db-connection.js";
12
+ import { getSqliteFrom, getTelemetryDb } from "../persistence/db-connection.js";
13
13
  import { telemetryEvents } from "../persistence/schema/index.js";
14
- import { getCachedShareAnalytics } from "../platform/consent-cache.js";
14
+ import { getRawShareAnalytics } from "../platform/consent-cache.js";
15
15
  import { APP_VERSION } from "../version.js";
16
16
  import type {
17
17
  OutboxTelemetryEventName,
@@ -23,6 +23,14 @@ import type {
23
23
  /** Ids per DELETE chunk — stays under SQLite's bound-variable limit. */
24
24
  const DELETE_CHUNK_SIZE = 500;
25
25
 
26
+ /**
27
+ * Max age of a pending outbox row. The reporter prunes older rows at the
28
+ * start of every flush cycle, in every consent state — this is what bounds
29
+ * the unknown-consent buffering (a permanently-unknown state never resolves,
30
+ * and a row this stale is worthless telemetry anyway).
31
+ */
32
+ export const OUTBOX_MAX_ROW_AGE_MS = 30 * 24 * 60 * 60 * 1000;
33
+
26
34
  /** One pending outbox row; `payload` is the wire `TelemetryEvent` JSON. */
27
35
  export interface TelemetryOutboxRow {
28
36
  id: string;
@@ -82,19 +90,25 @@ export function insertTelemetryOutboxEvent(
82
90
  /**
83
91
  * Lower-level record escape hatch: for payloads that need the record-time
84
92
  * `(id, createdAt)` inside type-specific fields (onboarding's activation
85
- * `daemon_event_id` override and `completed_at`). Gates on usage-data
86
- * consent, generates the outbox row identity, builds the wire payload via
87
- * `buildEvent` (which owns all stamping), and inserts. Returns the generated
88
- * row identity, or null when usage data collection is disabled (the event is
89
- * dropped to honor the opt-out) or the telemetry DB is unavailable (degraded
90
- * mode). Prefer `recordTelemetryEvent` when the payload doesn't need them.
93
+ * `daemon_event_id` override and `completed_at`). Drops only on a confirmed
94
+ * `share_analytics` opt-out the record-time drop is a privacy courtesy for
95
+ * known opt-outs. While consent is unknown (cold cache, no platform session)
96
+ * the event is recorded: dropping on an unresolved state would permanently
97
+ * destroy data, and consent is enforced again at flush time. Unknown-state
98
+ * buffering is bounded the reporter prunes rows older than
99
+ * {@link OUTBOX_MAX_ROW_AGE_MS} each flush cycle. Generates the
100
+ * outbox row identity, builds the wire payload via `buildEvent` (which owns
101
+ * all stamping), and inserts. Returns the generated row identity, or null
102
+ * when dropped for the opt-out or when the telemetry DB is unavailable
103
+ * (degraded mode). Prefer `recordTelemetryEvent` when the payload doesn't
104
+ * need them.
91
105
  */
92
106
  export function recordTelemetryOutboxEvent(
93
107
  name: string,
94
108
  buildEvent: (id: string, createdAt: number) => TelemetryEvent,
95
109
  opts?: { conversationId?: string | null },
96
110
  ): { id: string; createdAt: number } | null {
97
- if (!getCachedShareAnalytics()) {
111
+ if (getRawShareAnalytics() === false) {
98
112
  return null;
99
113
  }
100
114
  const id = uuid();
@@ -176,6 +190,25 @@ export function deleteTelemetryOutboxEvents(ids: string[]): void {
176
190
  }
177
191
  }
178
192
 
193
+ /**
194
+ * Delete rows recorded before `cutoffCreatedAt`, across every event name
195
+ * (age-bound prune). Returns the deleted row count; 0 when the telemetry DB
196
+ * is unavailable.
197
+ */
198
+ export function deleteTelemetryOutboxEventsBefore(
199
+ cutoffCreatedAt: number,
200
+ ): number {
201
+ const db = getTelemetryDb();
202
+ if (!db) {
203
+ return 0;
204
+ }
205
+ // Raw statement: drizzle's bun-sqlite `.run()` is typed void, and the
206
+ // prune's only output is the changed-row count.
207
+ return getSqliteFrom(db)
208
+ .prepare("DELETE FROM telemetry_events WHERE created_at < ?")
209
+ .run(cutoffCreatedAt).changes;
210
+ }
211
+
179
212
  /** Drop all pending rows for one event name (telemetry opt-out). */
180
213
  export function discardPendingTelemetryOutboxEvents(name: string): void {
181
214
  const db = getTelemetryDb();
@@ -184,3 +217,21 @@ export function discardPendingTelemetryOutboxEvents(name: string): void {
184
217
  }
185
218
  db.delete(telemetryEvents).where(eq(telemetryEvents.name, name)).run();
186
219
  }
220
+
221
+ /**
222
+ * Distinct event names with at least one pending row in the outbox. Used by the
223
+ * orphan-drain source to find rows whose type is no longer in the wire contract
224
+ * (e.g. recorded before the platform removed/renamed a type) so they can be
225
+ * flushed instead of stranded. Empty when the telemetry DB is unavailable.
226
+ */
227
+ export function queryDistinctOutboxEventNames(): string[] {
228
+ const db = getTelemetryDb();
229
+ if (!db) {
230
+ return [];
231
+ }
232
+ return db
233
+ .selectDistinct({ name: telemetryEvents.name })
234
+ .from(telemetryEvents)
235
+ .all()
236
+ .map((row) => row.name);
237
+ }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "sourceRepo": "vellum-ai/vellum-assistant-platform",
3
- "sourceSha": "701c9110672aa6448798b972c93f1b7d34f56dd6"
3
+ "sourceSha": "d14fd61263565016fa675fb99bfa2371d78f8ff4"
4
4
  }
@@ -14,7 +14,7 @@
14
14
  * events.
15
15
  */
16
16
 
17
- import type { z } from "zod";
17
+ import { z } from "zod";
18
18
 
19
19
  import type { getLogger } from "../util/logger.js";
20
20
  import { telemetryEventSchema } from "./telemetry-wire.generated.js";
@@ -26,13 +26,24 @@ type Logger = ReturnType<typeof getLogger>;
26
26
  * discriminated union (`.options` + each member's `type` literal), so a new
27
27
  * generated event type is validated with zero hand edits here.
28
28
  */
29
- const wireSchemaByType: ReadonlyMap<string, z.ZodType> = new Map(
29
+ const wireSchemaByType: ReadonlyMap<string, z.ZodObject> = new Map(
30
30
  telemetryEventSchema.options.map((option) => [
31
31
  option.shape.type.value,
32
32
  option,
33
33
  ]),
34
34
  );
35
35
 
36
+ /**
37
+ * Base fields stamped by the daemon at record time, never supplied by a client.
38
+ * Stripped when deriving the client-facing `fields` schema for a wire type.
39
+ */
40
+ const TELEMETRY_BASE_FIELD_KEYS = {
41
+ type: true,
42
+ daemon_event_id: true,
43
+ recorded_at: true,
44
+ assistant_version: true,
45
+ } as const;
46
+
36
47
  /**
37
48
  * Event types already warned about as absent from the wire contract.
38
49
  * Unknown-type warnings are rate-limited to once per process per type —
@@ -46,6 +57,32 @@ export function resetUnknownTypeWarningsForTests(): void {
46
57
  warnedUnknownTypes.clear();
47
58
  }
48
59
 
60
+ /**
61
+ * Per-event-type wire schema for one `type` discriminant, or undefined when the
62
+ * platform contract has no serializer for it. Lets the client-ingest boundary
63
+ * (`POST /v1/telemetry/ingest`) reject a malformed payload up front with the
64
+ * same schema pre-flush validation would have logged a silent drop for.
65
+ */
66
+ export function getWireSchemaForType(type: string): z.ZodObject | undefined {
67
+ return wireSchemaByType.get(type);
68
+ }
69
+
70
+ /**
71
+ * Client-facing `fields` schema for a wire type: the wire object minus the
72
+ * daemon-stamped base fields. Rebuilt from `.shape` because `.omit()` rejects
73
+ * the refined wire schemas; this drops the claims/suggestions byte-bound
74
+ * superRefines, which aren't expressible in the request type anyway — the
75
+ * handler still validates the assembled event against the full wire schema
76
+ * ({@link getWireSchemaForType}) for those bounds. Undefined when the platform
77
+ * contract has no serializer for `type`.
78
+ */
79
+ export function getWireFieldsSchema(type: string): z.ZodObject | undefined {
80
+ const schema = wireSchemaByType.get(type);
81
+ return schema
82
+ ? z.object(schema.shape).omit(TELEMETRY_BASE_FIELD_KEYS)
83
+ : undefined;
84
+ }
85
+
49
86
  /**
50
87
  * Render a zod issue path for logging without leaking dynamic record keys.
51
88
  *
@@ -332,6 +332,12 @@ export const onboardingResearchTelemetryEventSchema = z
332
332
  assistant_version: z.string().trim().min(1).max(64).nullable().optional(),
333
333
  conversation_id: z.string().trim().min(1).max(64).nullable().optional(),
334
334
  status: z.string().trim().min(1).max(32),
335
+ self_reported_occupation: z.string().max(256).nullable().optional(),
336
+ self_reported_hobbies: z
337
+ .array(z.string().trim().min(1).max(128))
338
+ .max(32)
339
+ .optional(),
340
+ self_reported_timezone: z.string().max(64).nullable().optional(),
335
341
  claims: z.array(jsonValueSchema).max(20),
336
342
  claim_count: z.number().int().min(0),
337
343
  claims_confident: z.number().int().min(0),
@@ -427,6 +433,8 @@ export type TelemetryIngestRequest = z.infer<
427
433
 
428
434
  export const telemetryIngestResponseSchema = z.object({
429
435
  accepted: z.number().int(),
436
+ persisted: z.number().int(),
437
+ dropped: z.record(z.string(), jsonValueSchema),
430
438
  });
431
439
  export type TelemetryIngestResponse = z.infer<
432
440
  typeof telemetryIngestResponseSchema
@@ -14,16 +14,19 @@
14
14
  * - `logToolFailure` emits the operator-facing failure log.
15
15
  *
16
16
  * The telemetry-only columns (payload sizes + model attribution) are the
17
- * single write-time privacy gate for `tool_executed` telemetry: when usage
18
- * data collection is disabled they persist as NULL, which the projection's
19
- * `arg_bytes IS NOT NULL` filter excludes permanently. The audit fields
17
+ * single write-time privacy gate for `tool_executed` telemetry: on a confirmed
18
+ * `share_analytics` opt-out they persist as NULL, which the projection's
19
+ * `arg_bytes IS NOT NULL` filter excludes permanently. An unknown consent
20
+ * state (cold cache) populates the columns — NULLing them would destroy the
21
+ * data irreversibly, and consent is enforced again at flush time and platform
22
+ * ingest, so opted-out rows never leave the device. The audit fields
20
23
  * themselves (tool name, decision, redacted input/result previews, duration)
21
24
  * are unaffected — `tool_invocations` is a local always-on audit log.
22
25
  */
23
26
 
24
27
  import { isAllowDecision, type UserDecision } from "../permissions/types.js";
25
28
  import { recordLifecycleEvent } from "../persistence/lifecycle-events-store.js";
26
- import { getCachedShareAnalytics } from "../platform/consent-cache.js";
29
+ import { getRawShareAnalytics } from "../platform/consent-cache.js";
27
30
  import { redactJsonStringLeaves } from "../security/redact-json.js";
28
31
  import { redactSensitiveFields } from "../security/redaction.js";
29
32
  import { redactSecrets } from "../security/secret-scanner.js";
@@ -257,17 +260,20 @@ const NULL_TELEMETRY_COLUMNS: TelemetryColumns = {
257
260
  };
258
261
 
259
262
  /**
260
- * Telemetry-only columns (payload sizes + model attribution). When usage data
261
- * collection is disabled the columns persist as NULL, which the projection's
262
- * `arg_bytes IS NOT NULL` filter excludes permanently the same mechanism
263
- * that excludes legacy pre-migration rows (see tool-executed-events-store.ts).
263
+ * Telemetry-only columns (payload sizes + model attribution). NULLed only on a
264
+ * confirmed `share_analytics` opt-out the projection's `arg_bytes IS NOT
265
+ * NULL` filter excludes NULL rows permanently (the same mechanism that
266
+ * excludes legacy pre-migration rows, see tool-executed-events-store.ts), so
267
+ * an unknown consent state (cold cache) must populate the columns rather than
268
+ * destroy them. Consent is enforced again at flush time and platform ingest,
269
+ * so opted-out rows never ship.
264
270
  */
265
271
  function telemetryColumns(
266
272
  attribution: UsageAttributionSnapshot | null,
267
273
  rawInput: string,
268
274
  resultBytes: number,
269
275
  ): TelemetryColumns {
270
- if (!getCachedShareAnalytics()) {
276
+ if (getRawShareAnalytics() === false) {
271
277
  return NULL_TELEMETRY_COLUMNS;
272
278
  }
273
279
  return {
@@ -5,7 +5,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
5
5
  let shareAnalytics = true;
6
6
 
7
7
  mock.module("../platform/consent-cache.js", () => ({
8
- getCachedShareAnalytics: () => shareAnalytics,
8
+ getRawShareAnalytics: () => shareAnalytics,
9
9
  }));
10
10
 
11
11
  import {
@@ -55,6 +55,21 @@ export interface TurnEvent {
55
55
  * and should never appear on a user-message row.
56
56
  */
57
57
  channelId: string | null;
58
+ /**
59
+ * Send-source tag for messages the UI sent on the user's behalf
60
+ * (`"nav_redirect"` — a navigation shortcut redirected the user into
61
+ * chat with a pre-filled message). Sourced from
62
+ * `messages.metadata.userMessageSource`, stamped by `handleSendMessage`
63
+ * when the request body carries `source`. Null for hand-typed messages
64
+ * and rows predating the field. Lets activation-funnel analytics
65
+ * separate UI-initiated turns from organic ones.
66
+ *
67
+ * Daemon-side projection only for now: the platform's turn serializer
68
+ * does not yet accept a `source` wire field, so `turnSource` must not
69
+ * emit it until the platform serializer lands and the wire sync PR
70
+ * updates `telemetry-wire.generated.ts` (see `src/telemetry/AGENTS.md`).
71
+ */
72
+ source: string | null;
58
73
  /**
59
74
  * Flexible client metadata stashed under `messages.metadata.client` by
60
75
  * the HTTP header middleware. Carries optional `browserFamily`,
@@ -160,6 +175,11 @@ export function queryUnreportedTurnEvents(
160
175
  >`json_extract(${messages.metadata}, '$.userMessageChannel')`.as(
161
176
  "channel_id",
162
177
  ),
178
+ source: sql<
179
+ string | null
180
+ >`json_extract(${messages.metadata}, '$.userMessageSource')`.as(
181
+ "source",
182
+ ),
163
183
  clientMetadata: sql<
164
184
  string | null
165
185
  >`json_extract(${messages.metadata}, '$.client')`.as("client_metadata"),
@@ -1,6 +1,7 @@
1
1
  import type { LLMCallSite } from "../config/schemas/llm.js";
2
2
  import type { UsageAttributionProfileSource } from "../usage/types.js";
3
3
  import type * as wire from "./telemetry-wire.generated.js";
4
+ import { telemetryEventSchema } from "./telemetry-wire.generated.js";
4
5
  import type { TurnOutcome } from "./turn-outcome.js";
5
6
 
6
7
  /** Base fields present on every telemetry event. */
@@ -464,8 +465,8 @@ export interface OnboardingResearchSuggestion {
464
465
  * settled result during onboarding. Client-orchestrated: the web client
465
466
  * knows exactly when the turn completes and what it produced (claims,
466
467
  * suggestions, plugin picks), and reports it once via
467
- * `POST /v1/telemetry/onboarding-research` — the daemon never detects this
468
- * turn on its own.
468
+ * `POST /v1/telemetry/ingest` (as a client-reportable type) — the daemon
469
+ * never detects this turn on its own.
469
470
  *
470
471
  * Carries both the raw claim/suggestion text (+ source URLs) and structural
471
472
  * counts by confidence tier, so downstream consumers can aggregate cheaply
@@ -475,6 +476,14 @@ export interface OnboardingResearchTelemetryEvent extends TelemetryEventBase {
475
476
  type: "onboarding_research";
476
477
  conversation_id: string | null;
477
478
  status: "done" | "error";
479
+ /**
480
+ * The onboarding-form values the turn was run ON (its INPUT), as distinct
481
+ * from the inferred `claims` below (its OUTPUT). Excludes the user's name by
482
+ * design. Optional — an older web client omits them.
483
+ */
484
+ self_reported_occupation?: string;
485
+ self_reported_hobbies?: string[];
486
+ self_reported_timezone?: string;
478
487
  claims: OnboardingResearchClaim[];
479
488
  claim_count: number;
480
489
  claims_confident: number;
@@ -664,18 +673,42 @@ type _extensionsDontCollide = AssertNoWireCollision<
664
673
  * change once shipped. The watermark-flushed types (`llm_usage`, `turn`,
665
674
  * `tool_executed`) live on their own tables and are deliberately excluded.
666
675
  */
667
- export const OUTBOX_TELEMETRY_EVENT_NAMES = [
668
- "lifecycle",
669
- "onboarding",
670
- "auth_fallback",
671
- "skill_loaded",
672
- "watchdog",
673
- "config_setting",
674
- "onboarding_research",
676
+ /**
677
+ * Types NOT on the generic `telemetry_events` outbox — the high-volume events
678
+ * flushed from their own SQLite tables by a watermark source
679
+ * (`telemetry-event-sources.ts`). This is the ONLY hand-maintained partition
680
+ * fact; every other wire event type is outbox-backed by default. Add a name
681
+ * here only when a new type gets its own dedicated table.
682
+ */
683
+ export const WATERMARK_TELEMETRY_EVENT_NAMES = [
684
+ "llm_usage",
685
+ "turn",
686
+ "tool_executed",
675
687
  ] as const;
676
688
 
677
- export type OutboxTelemetryEventName =
678
- (typeof OUTBOX_TELEMETRY_EVENT_NAMES)[number];
689
+ export type WatermarkTelemetryEventName =
690
+ (typeof WATERMARK_TELEMETRY_EVENT_NAMES)[number];
691
+
692
+ /**
693
+ * Event names backed by the `telemetry_events` outbox: every wire event type
694
+ * that is not watermark-flushed. Derived from the generated wire contract, so a
695
+ * new event type added on the platform side flows onto the outbox — and gets a
696
+ * flush source (`telemetry-event-sources.ts`) and a fully-typed
697
+ * `recordTelemetryEvent` call — with NO edit here. Each name doubles as the
698
+ * wire `type` discriminant and the flush-group key.
699
+ */
700
+ export type OutboxTelemetryEventName = Exclude<
701
+ keyof wire.WireEventMap,
702
+ WatermarkTelemetryEventName
703
+ >;
704
+
705
+ export const OUTBOX_TELEMETRY_EVENT_NAMES: readonly OutboxTelemetryEventName[] =
706
+ telemetryEventSchema.options
707
+ .map((option) => option.shape.type.value)
708
+ .filter(
709
+ (name): name is OutboxTelemetryEventName =>
710
+ !(WATERMARK_TELEMETRY_EVENT_NAMES as readonly string[]).includes(name),
711
+ );
679
712
 
680
713
  /** Wire event type for one outbox event name. */
681
714
  export type OutboxTelemetryEventOf<N extends OutboxTelemetryEventName> =