@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2

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 (596) hide show
  1. package/AGENTS.md +9 -3
  2. package/ARCHITECTURE.md +32 -10
  3. package/docs/architecture/memory.md +43 -5
  4. package/docs/architecture/security.md +96 -152
  5. package/docs/architecture/turn-actor.md +70 -0
  6. package/docs/browser-use-architecture-phase2.md +128 -56
  7. package/docs/flux-turn-detection-spike.md +248 -0
  8. package/docs/guardian-request-flow.md +35 -0
  9. package/docs/stt-provider-onboarding.md +3 -1
  10. package/knip.json +3 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
  24. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  25. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  26. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  27. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  28. package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  29. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  30. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  31. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  32. package/openapi.yaml +289 -113
  33. package/package.json +1 -1
  34. package/scripts/voice-ttft-spike.ts +3 -3
  35. package/scripts/write-plugin-api-shim.ts +10 -0
  36. package/src/__tests__/app-compiler.test.ts +38 -3
  37. package/src/__tests__/app-control-flow.test.ts +1 -0
  38. package/src/__tests__/approval-routes-http.test.ts +2 -2
  39. package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
  40. package/src/__tests__/attachments-store.test.ts +21 -12
  41. package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
  42. package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
  43. package/src/__tests__/call-site-routing-provider.test.ts +1 -1
  44. package/src/__tests__/channel-availability-routes.test.ts +14 -1
  45. package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
  46. package/src/__tests__/channel-delivery-store.test.ts +14 -14
  47. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  48. package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
  49. package/src/__tests__/checker.test.ts +20 -314
  50. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  51. package/src/__tests__/compaction-events.test.ts +8 -10
  52. package/src/__tests__/config-loader-backfill.test.ts +3 -3
  53. package/src/__tests__/config-schema.test.ts +25 -10
  54. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  55. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
  56. package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
  57. package/src/__tests__/conversation-agent-loop.test.ts +32 -21
  58. package/src/__tests__/conversation-attachments.test.ts +0 -1
  59. package/src/__tests__/conversation-attention-store.test.ts +63 -0
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
  61. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -0
  63. package/src/__tests__/conversation-fork-referential.test.ts +67 -0
  64. package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
  65. package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
  66. package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
  67. package/src/__tests__/conversation-queue.test.ts +154 -4
  68. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  69. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
  71. package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
  75. package/src/__tests__/conversation-slash-queue.test.ts +3 -0
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
  82. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
  83. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
  85. package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
  86. package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
  87. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
  88. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  89. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  90. package/src/__tests__/credential-prompt-route.test.ts +7 -10
  91. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  92. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  93. package/src/__tests__/custom-profile-ensure.test.ts +5 -1
  94. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  95. package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
  96. package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
  97. package/src/__tests__/document-append-idempotency.test.ts +233 -0
  98. package/src/__tests__/document-sync-tags.test.ts +0 -75
  99. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  100. package/src/__tests__/edit-propagation.test.ts +107 -11
  101. package/src/__tests__/file-ops-service.test.ts +163 -30
  102. package/src/__tests__/filesystem-tools.test.ts +23 -24
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -5
  104. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  105. package/src/__tests__/helpers/mock-actor-context.ts +49 -0
  106. package/src/__tests__/helpers/mock-conversation.ts +13 -1
  107. package/src/__tests__/host-file-read-tool.test.ts +16 -19
  108. package/src/__tests__/http-user-message-parity.test.ts +1 -1
  109. package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
  110. package/src/__tests__/injector-chain.test.ts +63 -41
  111. package/src/__tests__/injector-disk-pressure.test.ts +11 -23
  112. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  113. package/src/__tests__/llm-context-resolution.test.ts +73 -1
  114. package/src/__tests__/llm-schema.test.ts +5 -2
  115. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
  116. package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
  117. package/src/__tests__/media-generate-image.test.ts +131 -21
  118. package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
  119. package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
  120. package/src/__tests__/mtime-cache.test.ts +3 -1
  121. package/src/__tests__/non-member-access-request.test.ts +0 -20
  122. package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
  123. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  124. package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
  125. package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
  126. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  127. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  128. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  129. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  130. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
  131. package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
  132. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
  133. package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
  134. package/src/__tests__/proxy-approval-callback.test.ts +1 -0
  135. package/src/__tests__/qdrant-manager.test.ts +14 -1
  136. package/src/__tests__/reaction-persistence.test.ts +200 -7
  137. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  138. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  139. package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
  140. package/src/__tests__/run-due-schedules.test.ts +21 -0
  141. package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
  142. package/src/__tests__/schedule-routes.test.ts +23 -0
  143. package/src/__tests__/schedule-store.test.ts +17 -0
  144. package/src/__tests__/scoped-approval-grants.test.ts +11 -6
  145. package/src/__tests__/secret-ingress-channel.test.ts +0 -1
  146. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  147. package/src/__tests__/send-endpoint-busy.test.ts +3 -3
  148. package/src/__tests__/skills.test.ts +32 -0
  149. package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
  150. package/src/__tests__/starter-task-flow.test.ts +5 -4
  151. package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
  152. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  153. package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
  154. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  155. package/src/__tests__/subagent-tools.test.ts +81 -101
  156. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
  157. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  158. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  159. package/src/__tests__/tool-executor.test.ts +68 -39
  160. package/src/__tests__/turn-events-store.test.ts +43 -0
  161. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  162. package/src/__tests__/ui-shape-teaching.test.ts +33 -0
  163. package/src/__tests__/ui-visual-surface.test.ts +1 -1
  164. package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
  165. package/src/__tests__/ui-work-result-surface.test.ts +1 -1
  166. package/src/__tests__/user-plugin-loader.test.ts +3 -1
  167. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  168. package/src/__tests__/visible-app-context.test.ts +16 -9
  169. package/src/__tests__/voice-config-update.test.ts +40 -0
  170. package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
  171. package/src/__tests__/voice-session-bridge.test.ts +85 -29
  172. package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
  173. package/src/__tests__/worker-plugin-surface.test.ts +77 -0
  174. package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
  175. package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
  176. package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
  177. package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
  178. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
  179. package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
  180. package/src/acp/__tests__/auth-required.test.ts +161 -0
  181. package/src/acp/acp-claude-oauth.ts +19 -2
  182. package/src/acp/agent-process.test.ts +100 -0
  183. package/src/acp/agent-process.ts +29 -26
  184. package/src/acp/auth-required.ts +102 -0
  185. package/src/acp/session-manager.test.ts +119 -0
  186. package/src/acp/session-manager.ts +76 -3
  187. package/src/api/events/acp-auth-required.ts +55 -0
  188. package/src/api/events/host-file.ts +2 -2
  189. package/src/api/index.ts +7 -0
  190. package/src/api/surfaces.ts +12 -3
  191. package/src/apps/app-store.ts +3 -0
  192. package/src/bundler/package-resolver.ts +2 -30
  193. package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
  194. package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
  195. package/src/calls/call-controller.ts +19 -3
  196. package/src/calls/call-setup-flow.ts +0 -1
  197. package/src/calls/media-stream-stt-session.ts +15 -0
  198. package/src/calls/voice-session-bridge.ts +115 -41
  199. package/src/calls/voice-triage-escalate.ts +105 -2
  200. package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
  201. package/src/channels/config.ts +13 -0
  202. package/src/channels/plugin-channel-declarations.ts +108 -0
  203. package/src/channels/types.ts +30 -0
  204. package/src/cli/AGENTS.md +5 -2
  205. package/src/cli/bundled-modules.ts +29 -0
  206. package/src/cli/commands/credentials.help.ts +2 -2
  207. package/src/cli/commands/db/repair.ts +4 -8
  208. package/src/cli/commands/domain.ts +6 -3
  209. package/src/cli/commands/email.ts +6 -3
  210. package/src/cli/commands/inference-providers.ts +1 -1
  211. package/src/cli/commands/keys.ts +8 -3
  212. package/src/cli/commands/mcp.help.ts +13 -4
  213. package/src/cli/commands/mcp.ts +9 -0
  214. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  215. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
  216. package/src/cli/commands/memory/index.help.ts +84 -28
  217. package/src/cli/commands/memory/index.ts +2 -0
  218. package/src/cli/commands/memory/memory-v2.ts +58 -54
  219. package/src/cli/commands/memory/memory-v3.ts +64 -0
  220. package/src/cli/commands/memory/memory-validate.ts +18 -0
  221. package/src/cli/commands/plugins.ts +85 -36
  222. package/src/cli/commands/schedules.ts +35 -1
  223. package/src/cli/commands/stt.help.ts +27 -2
  224. package/src/cli/commands/trust.ts +3 -14
  225. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
  226. package/src/cli/lib/bundled-marketplace.json +14 -1
  227. package/src/cli/lib/upgrade-plugin.ts +42 -0
  228. package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
  229. package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
  230. package/src/config/__tests__/default-provider.test.ts +6 -1
  231. package/src/config/__tests__/profile-materialization.test.ts +75 -19
  232. package/src/config/assistant-feature-flags.ts +36 -15
  233. package/src/config/balanced-model-experiment.ts +35 -0
  234. package/src/config/bundled-skills/acp/SKILL.md +6 -7
  235. package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
  236. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  237. package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
  238. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
  240. package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
  241. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  242. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
  243. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
  244. package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
  245. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
  246. package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
  247. package/src/config/bundled-skills/subagent/SKILL.md +17 -12
  248. package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
  249. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
  250. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
  251. package/src/config/call-site-defaults.ts +11 -5
  252. package/src/config/default-profile-catalog.ts +179 -16
  253. package/src/config/default-profile-names.ts +4 -1
  254. package/src/config/default-provider-resolution.ts +4 -0
  255. package/src/config/feature-flag-registry.json +12 -12
  256. package/src/config/llm-context-resolution.ts +11 -3
  257. package/src/config/llm-resolver.ts +28 -1
  258. package/src/config/profile-materialization.ts +70 -22
  259. package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
  260. package/src/config/schemas/call-site-catalog.ts +4 -4
  261. package/src/config/schemas/live-voice.ts +57 -23
  262. package/src/config/schemas/llm.ts +59 -32
  263. package/src/config/schemas/mcp.ts +23 -0
  264. package/src/config/schemas/plugin-updates.ts +6 -2
  265. package/src/config/schemas/stt.ts +1 -0
  266. package/src/config/skills.ts +9 -2
  267. package/src/context/outbound-sanitize.ts +96 -1
  268. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
  269. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
  270. package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
  271. package/src/daemon/conversation-agent-loop.ts +31 -19
  272. package/src/daemon/conversation-messaging.ts +5 -1
  273. package/src/daemon/conversation-notifiers.ts +20 -10
  274. package/src/daemon/conversation-process.ts +20 -6
  275. package/src/daemon/conversation-runtime-assembly.ts +12 -6
  276. package/src/daemon/conversation-store.ts +14 -4
  277. package/src/daemon/conversation-surfaces.ts +75 -26
  278. package/src/daemon/conversation-tool-setup.ts +3 -6
  279. package/src/daemon/conversation.ts +154 -51
  280. package/src/daemon/doordash-steps.ts +2 -2
  281. package/src/daemon/lifecycle.ts +14 -1
  282. package/src/daemon/mcp-reload-service.ts +36 -6
  283. package/src/daemon/process-message.ts +13 -26
  284. package/src/daemon/providers-setup.ts +6 -3
  285. package/src/daemon/trust-context-types.ts +29 -0
  286. package/src/daemon/trust-context.ts +12 -7
  287. package/src/daemon/wake-conversation-ops.ts +3 -2
  288. package/src/daemon/windows-compiled-entry.ts +4 -0
  289. package/src/documents/document-store.ts +143 -240
  290. package/src/hooks/hook-loader.ts +3 -3
  291. package/src/hooks/registry.ts +103 -45
  292. package/src/hooks/types.ts +5 -0
  293. package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
  294. package/src/inbound/oauth-callback-url.ts +61 -0
  295. package/src/ipc/gateway-client.test.ts +1 -1
  296. package/src/ipc/gateway-client.ts +14 -21
  297. package/src/ipc/gateway-flag-listener.ts +17 -3
  298. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
  299. package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
  300. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
  301. package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
  302. package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
  303. package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
  304. package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
  305. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
  306. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
  307. package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
  308. package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
  309. package/src/live-voice/live-voice-archive.ts +2 -0
  310. package/src/live-voice/live-voice-manager.ts +16 -3
  311. package/src/live-voice/live-voice-metrics.ts +57 -32
  312. package/src/live-voice/live-voice-photo.ts +1 -2
  313. package/src/live-voice/live-voice-session.ts +598 -323
  314. package/src/live-voice/progress-narration.ts +277 -0
  315. package/src/live-voice/protocol.ts +21 -1
  316. package/src/live-voice/windows-compiled-live-voice.ts +4 -0
  317. package/src/mcp/__tests__/effective-config.test.ts +238 -0
  318. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  319. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
  320. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
  321. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
  322. package/src/mcp/client.ts +16 -11
  323. package/src/mcp/effective-config.ts +113 -0
  324. package/src/mcp/manager.ts +11 -6
  325. package/src/mcp/mcp-auth-orchestrator.ts +13 -22
  326. package/src/mcp/mcp-oauth-provider.ts +205 -240
  327. package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
  328. package/src/monitoring/control.ts +1 -0
  329. package/src/monitoring/db-integrity-sample.ts +4 -5
  330. package/src/monitoring/plugin-auto-update.ts +128 -24
  331. package/src/notifications/AGENTS.md +2 -0
  332. package/src/notifications/approval-card-data.ts +33 -0
  333. package/src/notifications/signal.ts +1 -0
  334. package/src/permissions/AGENTS.md +16 -0
  335. package/src/permissions/checker.test.ts +75 -122
  336. package/src/permissions/checker.ts +44 -560
  337. package/src/permissions/confirmation-guardian-request.test.ts +15 -11
  338. package/src/permissions/confirmation-guardian-request.ts +2 -2
  339. package/src/permissions/prompter.ts +1 -5
  340. package/src/permissions/question-guardian-request.test.ts +14 -6
  341. package/src/permissions/question-guardian-request.ts +1 -2
  342. package/src/persistence/attachments-store.ts +8 -1
  343. package/src/persistence/bookmark-crud.ts +3 -7
  344. package/src/persistence/conversation-attention-store.ts +16 -45
  345. package/src/persistence/conversation-crud.ts +33 -4
  346. package/src/persistence/conversation-lineage.ts +9 -0
  347. package/src/persistence/conversation-queries.ts +182 -52
  348. package/src/persistence/delivery-crud.ts +150 -36
  349. package/src/persistence/embeddings/qdrant-manager.ts +84 -49
  350. package/src/persistence/external-conversation-store.ts +32 -4
  351. package/src/persistence/llm-request-log-store.ts +4 -10
  352. package/src/persistence/llm-usage-store.ts +8 -3
  353. package/src/persistence/message-reads.test.ts +197 -0
  354. package/src/persistence/message-reads.ts +211 -0
  355. package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
  356. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
  357. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
  358. package/src/persistence/real-user-turn-filter.ts +27 -3
  359. package/src/persistence/schema/documents.ts +4 -4
  360. package/src/persistence/steps.ts +9 -0
  361. package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
  362. package/src/plugin-api/constants.ts +8 -0
  363. package/src/plugin-api/conversation-turn.ts +195 -5
  364. package/src/plugin-api/index.ts +38 -6
  365. package/src/plugin-api/resolve-credential.ts +3 -2
  366. package/src/plugin-api/store-credential.ts +146 -0
  367. package/src/plugin-api/vision-support.test.ts +1 -1
  368. package/src/plugin-api/webhook-url.ts +13 -11
  369. package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
  370. package/src/plugins/defaults/main.ts +21 -7
  371. package/src/plugins/defaults/memory/AGENTS.md +15 -3
  372. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
  373. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
  374. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
  375. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
  376. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  377. package/src/plugins/defaults/memory/buffer-format.ts +165 -0
  378. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
  379. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
  380. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
  381. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
  382. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
  383. package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
  384. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
  385. package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
  386. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
  387. package/src/plugins/defaults/memory/indexer.ts +3 -1
  388. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
  389. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
  390. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
  391. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  392. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
  393. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
  394. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  395. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  396. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  397. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  398. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  399. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  400. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
  401. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
  402. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  403. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  404. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  405. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  406. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  407. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  408. package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
  409. package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
  410. package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
  411. package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
  412. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
  413. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
  414. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  415. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  416. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  417. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  418. package/src/plugins/defaults/memory/v3/injector.ts +8 -0
  419. package/src/plugins/defaults/memory/v3/prune.ts +2 -0
  420. package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
  421. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
  422. package/src/plugins/defaults/memory/worker-control.ts +1 -0
  423. package/src/plugins/defaults/memory/worker.ts +6 -3
  424. package/src/plugins/defaults/worker-entrypoints.ts +3 -0
  425. package/src/plugins/external-plugin-loader.ts +47 -0
  426. package/src/plugins/mcp-servers.ts +361 -0
  427. package/src/plugins/mtime-cache.ts +37 -46
  428. package/src/plugins/pipeline.ts +14 -7
  429. package/src/plugins/plugin-execution-context.ts +35 -11
  430. package/src/plugins/worker-plugin-surface.ts +33 -0
  431. package/src/prompts/templates/system-sections.ts +0 -7
  432. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  433. package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
  434. package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
  435. package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
  436. package/src/providers/__tests__/retry-callsite.test.ts +25 -2
  437. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  438. package/src/providers/anthropic/client.ts +332 -241
  439. package/src/providers/call-site-routing.ts +30 -3
  440. package/src/providers/connection-resolution.ts +194 -11
  441. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
  442. package/src/providers/inference/adapter-factory.ts +3 -0
  443. package/src/providers/inference/auth.ts +6 -0
  444. package/src/providers/inference/connection-availability.ts +24 -2
  445. package/src/providers/inference/connections.ts +2 -0
  446. package/src/providers/model-catalog.ts +3 -3
  447. package/src/providers/model-intents.ts +28 -8
  448. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
  449. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  450. package/src/providers/openai/chat-completions-provider.ts +133 -36
  451. package/src/providers/openai/codex-models.ts +2 -1
  452. package/src/providers/provider-send-message.ts +32 -3
  453. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
  454. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
  455. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
  456. package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
  457. package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
  458. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
  459. package/src/providers/speech-to-text/provider-catalog.ts +99 -8
  460. package/src/providers/speech-to-text/resolve.ts +25 -2
  461. package/src/routes/control.ts +1 -0
  462. package/src/routes/route-host-client.ts +1 -0
  463. package/src/routes/route-host-protocol.ts +7 -0
  464. package/src/routes/worker.ts +48 -15
  465. package/src/runtime/AGENTS.md +16 -17
  466. package/src/runtime/access-request-helper.ts +9 -12
  467. package/src/runtime/agent-wake.ts +18 -15
  468. package/src/runtime/effective-capabilities.test.ts +43 -0
  469. package/src/runtime/effective-capabilities.ts +27 -0
  470. package/src/runtime/guardian-reply-router.ts +6 -2
  471. package/src/runtime/pre-first-message-gate.ts +4 -0
  472. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
  473. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
  474. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
  475. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
  476. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
  477. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
  478. package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
  479. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
  480. package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
  481. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  482. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  483. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
  484. package/src/runtime/routes/channel-availability-routes.ts +32 -14
  485. package/src/runtime/routes/channel-route-shared.ts +0 -6
  486. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
  487. package/src/runtime/routes/conversation-list-routes.ts +181 -23
  488. package/src/runtime/routes/conversation-management-routes.ts +17 -12
  489. package/src/runtime/routes/conversation-query-routes.ts +40 -27
  490. package/src/runtime/routes/conversation-routes.ts +43 -29
  491. package/src/runtime/routes/credential-prompt-routes.ts +4 -7
  492. package/src/runtime/routes/credential-routes.ts +26 -82
  493. package/src/runtime/routes/default-provider-routes.ts +15 -0
  494. package/src/runtime/routes/documents-routes.ts +3 -222
  495. package/src/runtime/routes/inbound-message-handler.ts +21 -45
  496. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
  497. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
  498. package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
  499. package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
  500. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
  501. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
  502. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
  503. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
  504. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
  505. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
  506. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
  507. package/src/runtime/routes/inference-profiles-routes.ts +20 -11
  508. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
  509. package/src/runtime/routes/log-export-routes.ts +3 -0
  510. package/src/runtime/routes/mcp-auth-routes.ts +148 -57
  511. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
  512. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
  513. package/src/runtime/routes/playground/inject-failures.ts +2 -2
  514. package/src/runtime/routes/playground/reset-circuit.ts +1 -1
  515. package/src/runtime/routes/plugins-routes.ts +38 -8
  516. package/src/runtime/routes/schedule-routes.ts +94 -7
  517. package/src/runtime/routes/settings-routes.ts +6 -6
  518. package/src/runtime/routes/stt-routes.ts +31 -25
  519. package/src/runtime/routes/surface-action-routes.ts +20 -19
  520. package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
  521. package/src/runtime/routes/user-route-dispatcher.ts +69 -15
  522. package/src/runtime/routes/user-route-import.ts +108 -0
  523. package/src/runtime/routes/user-route-resolution.ts +18 -1
  524. package/src/runtime/routes/workspace-routes.ts +0 -9
  525. package/src/runtime/routes/workspace-utils.ts +3 -13
  526. package/src/runtime/services/conversation-serializer.ts +7 -2
  527. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
  528. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
  529. package/src/schedule/plugin-schedule-availability.ts +58 -0
  530. package/src/schedule/plugin-schedule-declarations.ts +23 -27
  531. package/src/schedule/plugin-schedule-reconciler.ts +12 -3
  532. package/src/schedule/schedule-store.ts +5 -1
  533. package/src/schedule/scheduler.ts +9 -4
  534. package/src/schedule/worker-control.ts +1 -0
  535. package/src/schedule/worker.ts +6 -0
  536. package/src/security/oauth2.ts +6 -22
  537. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
  538. package/src/stt/__tests__/types.test.ts +94 -0
  539. package/src/stt/daemon-batch-transcriber.ts +10 -0
  540. package/src/stt/stt-stream-session.ts +8 -4
  541. package/src/stt/types.ts +103 -0
  542. package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
  543. package/src/subagent/consult-context.ts +11 -11
  544. package/src/subagent/consult-prompt.ts +26 -35
  545. package/src/subagent/manager.ts +21 -40
  546. package/src/subagent/notify.ts +7 -1
  547. package/src/subagent/types.ts +15 -12
  548. package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
  549. package/src/tools/acp/spawn.test.ts +97 -0
  550. package/src/tools/acp/spawn.ts +38 -4
  551. package/src/tools/credentials/ref-parse.ts +35 -0
  552. package/src/tools/credentials/resolve.ts +4 -10
  553. package/src/tools/credentials/store.ts +168 -0
  554. package/src/tools/document/document-tool.ts +12 -3
  555. package/src/tools/executor.ts +53 -15
  556. package/src/tools/filesystem/read.ts +27 -10
  557. package/src/tools/host-filesystem/read.ts +27 -15
  558. package/src/tools/network/url-safety.ts +9 -16
  559. package/src/tools/permission-checker.ts +43 -52
  560. package/src/tools/registry.ts +2 -1
  561. package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
  562. package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
  563. package/src/tools/shared/filesystem/types.ts +5 -5
  564. package/src/tools/skills/scaffold-managed.ts +25 -7
  565. package/src/tools/subagent/spawn.ts +28 -88
  566. package/src/tools/tool-types.ts +26 -13
  567. package/src/tools/types.ts +6 -6
  568. package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
  569. package/src/tools/workflows/run-workflow.ts +1 -2
  570. package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
  571. package/src/tts/reasoning-tag-filter.ts +89 -0
  572. package/src/util/__tests__/worker-process-command.test.ts +37 -0
  573. package/src/util/logger.ts +16 -0
  574. package/src/util/think-tag-stream.ts +95 -0
  575. package/src/util/worker-process.ts +37 -4
  576. package/src/windows-compiled-cli.ts +32 -0
  577. package/src/windows-compiled-entry.ts +4 -0
  578. package/src/windows-compiled-logger.ts +6 -0
  579. package/src/windows-compiled-worker-entry.ts +29 -0
  580. package/src/workspace/byok-default-profile-ensure.ts +76 -24
  581. package/src/workspace/custom-profile-ensure.ts +4 -24
  582. package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
  583. package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
  584. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
  585. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
  586. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
  587. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
  588. package/src/workspace/migrations/registry.ts +10 -0
  589. package/src/workspace/provider-commit-message-generator.ts +7 -5
  590. package/src/__tests__/document-workspace-file.test.ts +0 -467
  591. package/src/live-voice/__tests__/front-decision.test.ts +0 -645
  592. package/src/live-voice/front-decision.ts +0 -476
  593. package/src/permissions/ipc-risk-types.ts +0 -143
  594. package/src/permissions/risk-types.ts +0 -76
  595. package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
  596. package/src/subagent/consult-transcript.ts +0 -90
@@ -33,6 +33,45 @@ const SHUTDOWN_GRACE_MS = 5_000;
33
33
  const STDOUT_CAPTURE_LIMIT = 16_384;
34
34
  const STDERR_CAPTURE_LIMIT = 4_096;
35
35
 
36
+ export function resolveQdrantReleaseAsset(
37
+ os: NodeJS.Platform,
38
+ cpu: string,
39
+ ): {
40
+ binaryName: string;
41
+ filename: string;
42
+ format: "tar.gz" | "zip";
43
+ sha256?: string;
44
+ } {
45
+ let target: string;
46
+ if (os === "darwin" && cpu === "arm64") {
47
+ target = "aarch64-apple-darwin";
48
+ } else if (os === "darwin" && cpu === "x64") {
49
+ target = "x86_64-apple-darwin";
50
+ } else if (os === "linux" && cpu === "x64") {
51
+ target = "x86_64-unknown-linux-musl";
52
+ } else if (os === "linux" && cpu === "arm64") {
53
+ target = "aarch64-unknown-linux-musl";
54
+ } else if (os === "win32" && cpu === "x64") {
55
+ return {
56
+ binaryName: "qdrant.exe",
57
+ filename: "qdrant-x86_64-pc-windows-msvc.zip",
58
+ format: "zip",
59
+ sha256:
60
+ "9d3b1d1fa58566bc71709347c4c9b83a0111d23a550daa93c3ee48e3150c4470",
61
+ };
62
+ } else {
63
+ throw new Error(
64
+ `Unsupported platform: ${os}/${cpu}. ` +
65
+ "Set QDRANT_URL to use an external Qdrant instance.",
66
+ );
67
+ }
68
+ return {
69
+ binaryName: "qdrant",
70
+ filename: `qdrant-${target}.tar.gz`,
71
+ format: "tar.gz",
72
+ };
73
+ }
74
+
36
75
  export interface QdrantManagerConfig {
37
76
  url: string;
38
77
  storagePath?: string;
@@ -181,34 +220,18 @@ export class QdrantManager {
181
220
  private async installBinary(binaryPath: string): Promise<void> {
182
221
  const os = platform();
183
222
  const cpu = arch();
184
-
185
- let target: string;
186
- if (os === "darwin" && cpu === "arm64") {
187
- target = "aarch64-apple-darwin";
188
- } else if (os === "darwin" && cpu === "x64") {
189
- target = "x86_64-apple-darwin";
190
- } else if (os === "linux" && cpu === "x64") {
191
- target = "x86_64-unknown-linux-musl";
192
- } else if (os === "linux" && cpu === "arm64") {
193
- target = "aarch64-unknown-linux-musl";
194
- } else {
195
- throw new Error(
196
- `Unsupported platform: ${os}/${cpu}. ` +
197
- "Set QDRANT_URL to use an external Qdrant instance.",
198
- );
199
- }
200
-
201
- const filename = `qdrant-${target}.tar.gz`;
223
+ const release = resolveQdrantReleaseAsset(os, cpu);
224
+ const { filename } = release;
202
225
  const baseUrl = `https://github.com/qdrant/qdrant/releases/download/v${QDRANT_VERSION}`;
203
226
  const url = `${baseUrl}/${filename}`;
204
227
  const checksumUrl = `${baseUrl}/${filename}.sha256`;
205
228
 
206
229
  log.info({ url, binaryPath }, "Downloading Qdrant binary");
207
230
 
208
- // Fetch the tarball and its SHA-256 checksum in parallel
231
+ // Fetch the archive and its SHA-256 checksum in parallel
209
232
  const [response, checksumResponse] = await Promise.all([
210
233
  fetch(url),
211
- fetch(checksumUrl),
234
+ release.sha256 ? Promise.resolve(null) : fetch(checksumUrl),
212
235
  ]);
213
236
 
214
237
  if (!response.ok) {
@@ -217,15 +240,17 @@ export class QdrantManager {
217
240
  );
218
241
  }
219
242
 
220
- const tarball = await response.arrayBuffer();
243
+ const archive = await response.arrayBuffer();
221
244
 
222
- // Verify SHA-256 integrity if the checksum file is available
223
- if (checksumResponse.ok) {
224
- const checksumText = (await checksumResponse.text()).trim();
245
+ // Verify SHA-256 integrity if a pinned or published checksum is available
246
+ if (release.sha256 || checksumResponse?.ok) {
247
+ const checksumText = release.sha256
248
+ ? release.sha256
249
+ : (await checksumResponse!.text()).trim();
225
250
  // Checksum files contain "<hex> <filename>" or just "<hex>"
226
251
  const expectedHash = checksumText.split(/\s+/)[0].toLowerCase();
227
252
  const actualHash = createHash("sha256")
228
- .update(Buffer.from(tarball))
253
+ .update(Buffer.from(archive))
229
254
  .digest("hex");
230
255
 
231
256
  if (actualHash !== expectedHash) {
@@ -237,39 +262,45 @@ export class QdrantManager {
237
262
  log.info({ hash: actualHash }, "Qdrant binary checksum verified");
238
263
  } else {
239
264
  log.warn(
240
- { checksumUrl, status: checksumResponse.status },
241
- "Could not fetch Qdrant checksum — skipping integrity check",
265
+ { checksumUrl, status: checksumResponse?.status },
266
+ "Could not fetch Qdrant checksum; skipping integrity check",
242
267
  );
243
268
  }
244
269
 
245
- // Extract the qdrant binary from the tarball
246
270
  const binDir = dirname(binaryPath);
247
271
  mkdirSync(binDir, { recursive: true });
248
-
249
- // Write tarball to temp file, extract with tar
250
- const tmpTar = join(binDir, `qdrant-download-${Date.now()}.tar.gz`);
251
- writeFileSync(tmpTar, Buffer.from(tarball));
252
-
253
- try {
254
- const proc = Bun.spawn({
255
- cmd: ["tar", "xzf", tmpTar, "-C", binDir, "qdrant"],
256
- stdout: "ignore",
257
- stderr: "pipe",
258
- });
259
- await proc.exited;
260
- if (proc.exitCode !== 0) {
261
- const stderr = await new Response(proc.stderr).text();
262
- throw new Error(`Failed to extract Qdrant binary: ${stderr}`);
272
+ if (release.format === "zip") {
273
+ const { default: JSZip } = await import("jszip");
274
+ const zip = await JSZip.loadAsync(archive);
275
+ const entry = zip.file(release.binaryName);
276
+ if (!entry) {
277
+ throw new Error(`${filename} does not contain ${release.binaryName}.`);
263
278
  }
264
- } finally {
279
+ writeFileSync(binaryPath, await entry.async("nodebuffer"));
280
+ } else {
281
+ const tmpTar = join(binDir, `qdrant-download-${Date.now()}.tar.gz`);
282
+ writeFileSync(tmpTar, Buffer.from(archive));
265
283
  try {
266
- unlinkSync(tmpTar);
267
- } catch {
268
- /* ignore */
284
+ const proc = Bun.spawn({
285
+ cmd: ["tar", "xzf", tmpTar, "-C", binDir, release.binaryName],
286
+ stdout: "ignore",
287
+ stderr: "pipe",
288
+ });
289
+ await proc.exited;
290
+ if (proc.exitCode !== 0) {
291
+ const stderr = await new Response(proc.stderr).text();
292
+ throw new Error(`Failed to extract Qdrant binary: ${stderr}`);
293
+ }
294
+ } finally {
295
+ try {
296
+ unlinkSync(tmpTar);
297
+ } catch {}
269
298
  }
270
299
  }
271
300
 
272
- chmodSync(binaryPath, 0o755);
301
+ if (os !== "win32") {
302
+ chmodSync(binaryPath, 0o755);
303
+ }
273
304
  log.info(
274
305
  { binaryPath, version: QDRANT_VERSION },
275
306
  "Qdrant binary installed",
@@ -395,7 +426,8 @@ export class QdrantManager {
395
426
  }
396
427
 
397
428
  private getBinaryPath(): string {
398
- return join(getDataDir(), "qdrant", "bin", "qdrant");
429
+ const binaryName = platform() === "win32" ? "qdrant.exe" : "qdrant";
430
+ return join(getDataDir(), "qdrant", "bin", binaryName);
399
431
  }
400
432
 
401
433
  private cleanupStaleProcess(): void {
@@ -447,6 +479,9 @@ export class QdrantManager {
447
479
  * discoverable by tools that scan for "vellum" in process names.
448
480
  */
449
481
  private ensureVellumSymlink(binaryPath: string): string {
482
+ if (platform() === "win32") {
483
+ return binaryPath;
484
+ }
450
485
  const symlinkPath = join(dirname(binaryPath), "vellum-qdrant");
451
486
  const expectedTarget = realpathSync(binaryPath);
452
487
 
@@ -7,7 +7,8 @@
7
7
  * list APIs.
8
8
  */
9
9
 
10
- import { and, eq, inArray, isNull, sql } from "drizzle-orm";
10
+ import { and, eq, inArray, isNull, type SQL, sql } from "drizzle-orm";
11
+ import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core";
11
12
 
12
13
  import { getDb } from "./db-connection.js";
13
14
  import { externalConversationBindings } from "./schema/index.js";
@@ -45,6 +46,19 @@ function normalizeExternalThreadId(
45
46
  return trimmed ? trimmed : null;
46
47
  }
47
48
 
49
+ /**
50
+ * An upsert value that leaves the stored column alone when the caller said
51
+ * nothing about it, distinguishing "I do not know" from "there is none".
52
+ */
53
+ function keepStoredIfAbsent<T extends string | null | undefined>(
54
+ value: T,
55
+ column: AnySQLiteColumn,
56
+ ): Exclude<T, undefined> | SQL {
57
+ return value === undefined
58
+ ? sql`${column}`
59
+ : (value as Exclude<T, undefined>);
60
+ }
61
+
48
62
  function normalizeExternalChatName(
49
63
  externalChatName?: string | null,
50
64
  ): string | null {
@@ -103,9 +117,23 @@ export function upsertBinding(input: UpsertBindingInput): void {
103
117
  externalChatName ??
104
118
  sql`${externalConversationBindings.externalChatName}`,
105
119
  externalThreadId,
106
- externalUserId: input.externalUserId ?? null,
107
- displayName: input.displayName ?? null,
108
- username: input.username ?? null,
120
+ // An omitted sender field keeps what is stored; an explicit value,
121
+ // including null, replaces it. A caller that knows only the chat
122
+ // coordinates on a message is silent about the sender rather than
123
+ // asserting there is none, and erasing a known name on that silence
124
+ // drops it from the conversation and session APIs.
125
+ externalUserId: keepStoredIfAbsent(
126
+ input.externalUserId,
127
+ externalConversationBindings.externalUserId,
128
+ ),
129
+ displayName: keepStoredIfAbsent(
130
+ input.displayName,
131
+ externalConversationBindings.displayName,
132
+ ),
133
+ username: keepStoredIfAbsent(
134
+ input.username,
135
+ externalConversationBindings.username,
136
+ ),
109
137
  updatedAt: now,
110
138
  lastInboundAt: now,
111
139
  },
@@ -28,13 +28,14 @@ import {
28
28
  getTurnTimeBounds,
29
29
  messageMetadataSchema,
30
30
  } from "./conversation-crud.js";
31
- import { type DrizzleDb, getDb, getLogsDb } from "./db-connection.js";
31
+ import { type DrizzleDb, getLogsDb } from "./db-connection.js";
32
32
  import { getClickHouseLlmRequestLogSink } from "./llm-request-log-sink-clickhouse.js";
33
33
  import type {
34
34
  LlmRequestLogWriter,
35
35
  LlmRequestLogWriteRow,
36
36
  } from "./llm-request-log-writer-types.js";
37
- import { llmRequestLogs, messages } from "./schema/index.js";
37
+ import { existingMessageIds } from "./message-reads.js";
38
+ import { llmRequestLogs } from "./schema/index.js";
38
39
  import { timeSyncSection } from "./slow-sync-log.js";
39
40
 
40
41
  /**
@@ -593,14 +594,7 @@ function selectOrphanedLogsInRange(
593
594
  const candidateMessageIds = [
594
595
  ...new Set(candidates.map((c) => c.messageId as string)),
595
596
  ];
596
- const existing = new Set(
597
- getDb()
598
- .select({ id: messages.id })
599
- .from(messages)
600
- .where(inArray(messages.id, candidateMessageIds))
601
- .all()
602
- .map((r) => r.id),
603
- );
597
+ const existing = existingMessageIds(candidateMessageIds);
604
598
 
605
599
  // Orphaned = the referenced message no longer exists.
606
600
  return candidates.filter((c) => !existing.has(c.messageId as string));
@@ -10,7 +10,10 @@ import type {
10
10
  import { APP_VERSION } from "../version.js";
11
11
  import { getDb } from "./db-connection.js";
12
12
  import { rawAll } from "./raw-query.js";
13
- import { realUserTurnContentFilter } from "./real-user-turn-filter.js";
13
+ import {
14
+ realUserTurnContentFilter,
15
+ realUserTurnContentFilterSql,
16
+ } from "./real-user-turn-filter.js";
14
17
  import {
15
18
  buildScheduleAttributionSubquery,
16
19
  buildScheduleRunWindowExists,
@@ -300,6 +303,9 @@ export function queryUnreportedUsageEvents(
300
303
  // branch from a turn far earlier than the fork's creation time, so
301
304
  // they anchor on the fork boundary message instead; child creation is
302
305
  // the fallback when the boundary message is absent.
306
+ // The turn-index subqueries below count user-role rows only. User rows are
307
+ // always written finalized (only assistant turns stream), so no completeness
308
+ // predicate is needed; do not copy this shape for assistant-row counts.
303
309
  const parentTurnCutoffSql = sql<number>`CASE
304
310
  WHEN ${conversations.parentConversationId} IS NOT NULL THEN ${conversations.createdAt}
305
311
  ELSE COALESCE(
@@ -879,8 +885,7 @@ export function getUsageGroupBreakdown(
879
885
  SELECT COUNT(*) FROM messages AS m2
880
886
  WHERE m2.conversation_id = e.conversation_id
881
887
  AND m2.role = 'user'
882
- AND m2.content NOT LIKE '%"type":"tool\\_result"%' ESCAPE '\\'
883
- AND m2.content NOT LIKE '%"type":"web\\_search\\_tool\\_result"%' ESCAPE '\\'
888
+ AND ${realUserTurnContentFilterSql("m2")}
884
889
  )
885
890
  END AS turn_count
886
891
  FROM llm_usage_events e
@@ -0,0 +1,197 @@
1
+ import { beforeEach, describe, expect, test } from "bun:test";
2
+
3
+ import { eq } from "drizzle-orm";
4
+
5
+ import { createConversation } from "./conversation-crud.js";
6
+ import { getDb } from "./db-connection.js";
7
+ import { initializeDb } from "./db-init.js";
8
+ import {
9
+ countMessagesByRoleForConversations,
10
+ existingMessageIds,
11
+ latestAssistantMessage,
12
+ latestAssistantMessageBefore,
13
+ latestUserMessageRawContent,
14
+ messageConversationId,
15
+ } from "./message-reads.js";
16
+ import { messages } from "./schema/index.js";
17
+
18
+ await initializeDb();
19
+
20
+ let seq = 0;
21
+ function insertRow(opts: {
22
+ conversationId: string;
23
+ role: string;
24
+ createdAt: number;
25
+ content?: string;
26
+ finalized?: 0 | 1;
27
+ }): string {
28
+ const id = `msg-${String(++seq).padStart(4, "0")}`;
29
+ getDb()
30
+ .insert(messages)
31
+ .values({
32
+ id,
33
+ conversationId: opts.conversationId,
34
+ role: opts.role,
35
+ content: opts.content ?? JSON.stringify([{ type: "text", text: "hi" }]),
36
+ createdAt: opts.createdAt,
37
+ metadata: null,
38
+ finalized: opts.finalized ?? 1,
39
+ })
40
+ .run();
41
+ return id;
42
+ }
43
+
44
+ function seedConversation(): string {
45
+ return createConversation("Message reads test").id;
46
+ }
47
+
48
+ describe("message-reads", () => {
49
+ beforeEach(() => {
50
+ const db = getDb();
51
+ db.run("DELETE FROM messages");
52
+ db.run("DELETE FROM conversations");
53
+ });
54
+
55
+ test("latestAssistantMessage returns the newest finalized assistant row", () => {
56
+ const conv = seedConversation();
57
+ insertRow({ conversationId: conv, role: "user", createdAt: 1_000 });
58
+ const older = insertRow({
59
+ conversationId: conv,
60
+ role: "assistant",
61
+ createdAt: 2_000,
62
+ });
63
+ const newer = insertRow({
64
+ conversationId: conv,
65
+ role: "assistant",
66
+ createdAt: 3_000,
67
+ });
68
+
69
+ expect(latestAssistantMessage(conv)?.id).toBe(newer);
70
+ expect(latestAssistantMessage(conv)?.id).not.toBe(older);
71
+ expect(latestAssistantMessage("missing-conv")).toBeNull();
72
+ });
73
+
74
+ test("latestAssistantMessage never anchors on a streaming row", () => {
75
+ const conv = seedConversation();
76
+ const finalizedReply = insertRow({
77
+ conversationId: conv,
78
+ role: "assistant",
79
+ createdAt: 1_000,
80
+ });
81
+ insertRow({
82
+ conversationId: conv,
83
+ role: "assistant",
84
+ createdAt: 2_000,
85
+ finalized: 0,
86
+ });
87
+
88
+ // The streaming row is newest but is not a reply yet; the watermark must
89
+ // sit on the completed one until the turn finishes.
90
+ expect(latestAssistantMessage(conv)?.id).toBe(finalizedReply);
91
+ });
92
+
93
+ test("a streaming row qualifies on its own once finalized", () => {
94
+ const conv = seedConversation();
95
+ insertRow({ conversationId: conv, role: "assistant", createdAt: 1_000 });
96
+ const streaming = insertRow({
97
+ conversationId: conv,
98
+ role: "assistant",
99
+ createdAt: 2_000,
100
+ finalized: 0,
101
+ });
102
+
103
+ getDb()
104
+ .update(messages)
105
+ .set({ finalized: 1 })
106
+ .where(eq(messages.id, streaming))
107
+ .run();
108
+
109
+ expect(latestAssistantMessage(conv)?.id).toBe(streaming);
110
+ });
111
+
112
+ test("latestAssistantMessageBefore is strict and skips streaming rows", () => {
113
+ const conv = seedConversation();
114
+ const first = insertRow({
115
+ conversationId: conv,
116
+ role: "assistant",
117
+ createdAt: 1_000,
118
+ });
119
+ insertRow({
120
+ conversationId: conv,
121
+ role: "assistant",
122
+ createdAt: 2_000,
123
+ finalized: 0,
124
+ });
125
+ insertRow({ conversationId: conv, role: "assistant", createdAt: 3_000 });
126
+
127
+ // Strictly before 3000: the streaming row at 2000 is passed over in
128
+ // favour of the completed row at 1000.
129
+ expect(latestAssistantMessageBefore(conv, 3_000)?.id).toBe(first);
130
+ // Strictly before 1000: nothing.
131
+ expect(latestAssistantMessageBefore(conv, 1_000)).toBeNull();
132
+ });
133
+
134
+ test("latestUserMessageRawContent resolves same-timestamp rows by insertion order", () => {
135
+ const conv = seedConversation();
136
+ insertRow({
137
+ conversationId: conv,
138
+ role: "user",
139
+ createdAt: 1_000,
140
+ content: "first",
141
+ });
142
+ insertRow({
143
+ conversationId: conv,
144
+ role: "user",
145
+ createdAt: 1_000,
146
+ content: "second",
147
+ });
148
+ insertRow({ conversationId: conv, role: "assistant", createdAt: 2_000 });
149
+
150
+ expect(latestUserMessageRawContent(conv)).toBe("second");
151
+ expect(latestUserMessageRawContent("missing-conv")).toBeNull();
152
+ });
153
+
154
+ test("countMessagesByRoleForConversations aggregates per conversation", () => {
155
+ const convA = seedConversation();
156
+ const convB = seedConversation();
157
+ insertRow({ conversationId: convA, role: "assistant", createdAt: 1_000 });
158
+ insertRow({ conversationId: convA, role: "assistant", createdAt: 2_000 });
159
+ insertRow({ conversationId: convA, role: "user", createdAt: 3_000 });
160
+ insertRow({ conversationId: convB, role: "assistant", createdAt: 4_000 });
161
+
162
+ const stats = countMessagesByRoleForConversations(
163
+ [convA, convB],
164
+ "assistant",
165
+ );
166
+ expect(stats.get(convA)).toEqual({ count: 2, lastAt: 2_000 });
167
+ expect(stats.get(convB)).toEqual({ count: 1, lastAt: 4_000 });
168
+ expect(countMessagesByRoleForConversations([], "assistant").size).toBe(0);
169
+ });
170
+
171
+ test("existingMessageIds returns only ids that exist", () => {
172
+ const conv = seedConversation();
173
+ const present = insertRow({
174
+ conversationId: conv,
175
+ role: "user",
176
+ createdAt: 1_000,
177
+ });
178
+
179
+ const existing = existingMessageIds([present, "msg-not-there"]);
180
+ expect(existing.has(present)).toBe(true);
181
+ expect(existing.has("msg-not-there")).toBe(false);
182
+ expect(existingMessageIds([]).size).toBe(0);
183
+ });
184
+
185
+ test("messageConversationId resolves ownership in any state", () => {
186
+ const conv = seedConversation();
187
+ const streaming = insertRow({
188
+ conversationId: conv,
189
+ role: "assistant",
190
+ createdAt: 1_000,
191
+ finalized: 0,
192
+ });
193
+
194
+ expect(messageConversationId(streaming)).toBe(conv);
195
+ expect(messageConversationId("msg-not-there")).toBeNull();
196
+ });
197
+ });