@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
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Named read accessors for the `messages` table.
3
+ *
4
+ * Every row in `messages` is conversation content in some state of
5
+ * completeness: `finalized = 1` rows are immutable history, `finalized = 0`
6
+ * rows are still being written and their `content` may be a `{ ref }` into an
7
+ * in-flight delta file that disappears when the turn completes. Ad-hoc queries
8
+ * tend to encode a visibility decision without stating it; each accessor here
9
+ * states its decision in its name and contract, so a caller (and a reviewer)
10
+ * chooses between "completed history" and "any row" deliberately.
11
+ *
12
+ * Conversation-history reads (transcripts, lineage, pagination) stay with
13
+ * `getMessages` / `getMessagesAfter` / `getMessagesPaginated` in
14
+ * `conversation-crud.ts`, which also own fork-lineage resolution. This module
15
+ * is for the narrower point lookups and aggregates that other persistence
16
+ * modules need.
17
+ *
18
+ * Correlated subqueries embedded inside larger SQL (usage accounting's
19
+ * turn-index arithmetic, search candidate joins, `message_count` projections)
20
+ * are out of scope: extracting them would restructure their host queries. They
21
+ * carry their visibility decision as a comment at the site instead.
22
+ */
23
+
24
+ import { and, desc, eq, inArray, lt, sql } from "drizzle-orm";
25
+
26
+ import { type DrizzleDb, getDb } from "./db-connection.js";
27
+ import { messages } from "./schema/index.js";
28
+
29
+ /** `(id, createdAt)` of a message, the shape cursor and watermark logic needs. */
30
+ export interface MessageRef {
31
+ id: string;
32
+ createdAt: number;
33
+ }
34
+
35
+ /**
36
+ * Structural read handle: anything that can `select` like the shared
37
+ * connection, which includes the connection itself and an open transaction.
38
+ * Every accessor takes `opts.db` with this type and defaults to the shared
39
+ * connection, so a caller holding its own handle (a transaction, an injected
40
+ * or in-memory database) reads the same database it writes.
41
+ */
42
+ export type MessageReadHandle = Pick<DrizzleDb, "select">;
43
+
44
+ /**
45
+ * The newest completed assistant message in a conversation, or null when it
46
+ * has none.
47
+ *
48
+ * Finalized-only: an assistant row that is still streaming is not a reply yet,
49
+ * so consumers tracking "the latest reply" (read/unread watermarks, previews)
50
+ * must not anchor on it. The row qualifies on its own once the turn completes.
51
+ *
52
+ * `db` lets a caller inside a transaction read through its own handle.
53
+ */
54
+ export function latestAssistantMessage(
55
+ conversationId: string,
56
+ opts?: { db?: MessageReadHandle },
57
+ ): MessageRef | null {
58
+ return newestFinalizedAssistantRow(conversationId, opts?.db ?? getDb());
59
+ }
60
+
61
+ /**
62
+ * The newest completed assistant message strictly before `createdAt`, or null.
63
+ * Strict comparison: rewind logic that landed on a same-timestamp sibling
64
+ * would classify the latest reply as already seen.
65
+ */
66
+ export function latestAssistantMessageBefore(
67
+ conversationId: string,
68
+ createdAt: number,
69
+ opts?: { db?: MessageReadHandle },
70
+ ): MessageRef | null {
71
+ return newestFinalizedAssistantRow(
72
+ conversationId,
73
+ opts?.db ?? getDb(),
74
+ createdAt,
75
+ );
76
+ }
77
+
78
+ function newestFinalizedAssistantRow(
79
+ conversationId: string,
80
+ db: MessageReadHandle,
81
+ strictlyBefore?: number,
82
+ ): MessageRef | null {
83
+ const row = db
84
+ .select({ id: messages.id, createdAt: messages.createdAt })
85
+ .from(messages)
86
+ .where(
87
+ and(
88
+ eq(messages.conversationId, conversationId),
89
+ eq(messages.role, "assistant"),
90
+ eq(messages.finalized, 1),
91
+ ...(strictlyBefore === undefined
92
+ ? []
93
+ : [lt(messages.createdAt, strictlyBefore)]),
94
+ ),
95
+ )
96
+ .orderBy(desc(messages.createdAt), desc(messages.id))
97
+ .limit(1)
98
+ .get();
99
+ return row ?? null;
100
+ }
101
+
102
+ /**
103
+ * Raw `content` of the last user-role row in a conversation, in insertion
104
+ * order (`rowid DESC`, not `createdAt`), or null when there is none.
105
+ *
106
+ * Insertion order is load-bearing for the undo path this serves: same-
107
+ * millisecond rows must resolve to the one written last. User rows are always
108
+ * written finalized, so no completeness predicate applies; only assistant
109
+ * turns stream.
110
+ */
111
+ export function latestUserMessageRawContent(
112
+ conversationId: string,
113
+ opts?: { db?: MessageReadHandle },
114
+ ): string | null {
115
+ const row = (opts?.db ?? getDb())
116
+ .select({ content: messages.content })
117
+ .from(messages)
118
+ .where(
119
+ and(
120
+ eq(messages.conversationId, conversationId),
121
+ eq(messages.role, "user"),
122
+ ),
123
+ )
124
+ .orderBy(sql`rowid DESC`)
125
+ .limit(1)
126
+ .get();
127
+ return row?.content ?? null;
128
+ }
129
+
130
+ /**
131
+ * Per-conversation count and latest timestamp of rows with `role`, for the
132
+ * given conversations.
133
+ *
134
+ * Any-state deliberately: these aggregates feed list ordering and previews,
135
+ * where a streaming reply still counts as activity. A caller needing
136
+ * completed-only aggregates should say so here rather than post-filtering.
137
+ */
138
+ export function countMessagesByRoleForConversations(
139
+ conversationIds: string[],
140
+ role: string,
141
+ opts?: { db?: MessageReadHandle },
142
+ ): Map<string, { count: number; lastAt: number }> {
143
+ if (conversationIds.length === 0) {
144
+ return new Map();
145
+ }
146
+ const rows = (opts?.db ?? getDb())
147
+ .select({
148
+ conversationId: messages.conversationId,
149
+ count: sql<number>`COUNT(*)`.as("count"),
150
+ lastAt: sql<number>`MAX(${messages.createdAt})`.as("last_at"),
151
+ })
152
+ .from(messages)
153
+ .where(
154
+ and(
155
+ inArray(messages.conversationId, conversationIds),
156
+ eq(messages.role, role),
157
+ ),
158
+ )
159
+ .groupBy(messages.conversationId)
160
+ .all();
161
+ return new Map(
162
+ rows.map((r) => [
163
+ r.conversationId,
164
+ { count: Number(r.count), lastAt: Number(r.lastAt) },
165
+ ]),
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Which of `messageIds` exist as rows, in any state.
171
+ *
172
+ * Any-state deliberately: existence is the question (orphan detection for
173
+ * rows referencing messages), and a streaming row exists. An empty input
174
+ * returns an empty set without querying.
175
+ */
176
+ export function existingMessageIds(
177
+ messageIds: string[],
178
+ opts?: { db?: MessageReadHandle },
179
+ ): Set<string> {
180
+ if (messageIds.length === 0) {
181
+ return new Set();
182
+ }
183
+ return new Set(
184
+ (opts?.db ?? getDb())
185
+ .select({ id: messages.id })
186
+ .from(messages)
187
+ .where(inArray(messages.id, messageIds))
188
+ .all()
189
+ .map((r) => r.id),
190
+ );
191
+ }
192
+
193
+ /**
194
+ * The conversation that owns `messageId`, in any state, or null when the
195
+ * message does not exist.
196
+ *
197
+ * Any-state deliberately: callers hold an id the user acted on (a bookmark on
198
+ * a rendered row, an attachment link), and a rendered row may still be
199
+ * streaming.
200
+ */
201
+ export function messageConversationId(
202
+ messageId: string,
203
+ opts?: { db?: MessageReadHandle },
204
+ ): string | null {
205
+ const row = (opts?.db ?? getDb())
206
+ .select({ conversationId: messages.conversationId })
207
+ .from(messages)
208
+ .where(eq(messages.id, messageId))
209
+ .get();
210
+ return row?.conversationId ?? null;
211
+ }
@@ -7,20 +7,11 @@ const COLUMN_DEFINITION = "workspace_path TEXT";
7
7
  /**
8
8
  * Add `workspace_path` to `documents` and enforce one document per file.
9
9
  *
10
- * The column holds the workspace-relative path of the markdown file a document
11
- * is bound to. It is set when a client opens a workspace `.md` file through
12
- * `POST /v1/documents/for-workspace-file`, which gives the file a document
13
- * identity so comments, assistant iteration, and PDF export — all keyed off a
14
- * document id — work on it. Documents that have no file behind them (assistant
15
- * drafts, client-created surfaces) stay NULL.
16
- *
17
- * The unique index is partial (`WHERE workspace_path IS NOT NULL`) so the many
18
- * NULL rows stay unconstrained while a given file resolves to exactly one
19
- * document. The find-or-create route depends on that uniqueness for its
20
- * idempotency.
21
- *
22
- * Nullable with no backfill: nothing recorded a file binding before this
23
- * column existed, so pre-existing rows correctly stay NULL.
10
+ * The column and its partial unique index are unused by the daemon: no code
11
+ * reads or writes them. Some rows carry a non-NULL path; new rows stay NULL.
12
+ * The migration stays in the chain because migrations are append-only, and the
13
+ * drizzle model in `schema/documents.ts` carries the column so it keeps
14
+ * describing the physical table.
24
15
  *
25
16
  * Idempotent: the column add is guarded with `tableHasColumn` and the index
26
17
  * with `IF NOT EXISTS`, so a crash between the two does not break the next
@@ -0,0 +1,120 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { describe, expect, test } from "bun:test";
3
+
4
+ import { drizzle } from "drizzle-orm/bun-sqlite";
5
+
6
+ import * as schema from "../schema.js";
7
+ import { migrateChatgptSubscriptionRowIdentity } from "./366-chatgpt-subscription-row-identity.js";
8
+
9
+ function createTestDb() {
10
+ const sqlite = new Database(":memory:");
11
+ sqlite.exec(/*sql*/ `
12
+ CREATE TABLE provider_connections (
13
+ name TEXT PRIMARY KEY,
14
+ provider TEXT NOT NULL,
15
+ auth TEXT NOT NULL,
16
+ label TEXT,
17
+ base_url TEXT,
18
+ models TEXT,
19
+ created_at INTEGER NOT NULL,
20
+ updated_at INTEGER NOT NULL
21
+ );
22
+ `);
23
+ return { sqlite, db: drizzle(sqlite, { schema }) };
24
+ }
25
+
26
+ function insertRow(
27
+ sqlite: Database,
28
+ name: string,
29
+ provider: string,
30
+ auth: string,
31
+ ): void {
32
+ sqlite
33
+ .query(
34
+ /*sql*/ `INSERT INTO provider_connections (name, provider, auth, created_at, updated_at)
35
+ VALUES (?, ?, ?, 1, 1)`,
36
+ )
37
+ .run(name, provider, auth);
38
+ }
39
+
40
+ function readProvider(sqlite: Database, name: string): string | undefined {
41
+ const row = sqlite
42
+ .query(`SELECT provider FROM provider_connections WHERE name = ?`)
43
+ .get(name) as { provider: string } | null;
44
+ return row?.provider;
45
+ }
46
+
47
+ describe("migration 366: chatgpt-subscription row identity", () => {
48
+ test("flips the subscription row to provider chatgpt", () => {
49
+ const { sqlite, db } = createTestDb();
50
+ insertRow(
51
+ sqlite,
52
+ "chatgpt-subscription",
53
+ "openai",
54
+ '{"type":"oauth_subscription","credential":"credential/chatgpt/access_token"}',
55
+ );
56
+
57
+ migrateChatgptSubscriptionRowIdentity(db);
58
+
59
+ expect(readProvider(sqlite, "chatgpt-subscription")).toBe("chatgpt");
60
+ });
61
+
62
+ test("leaves a claiming row with key auth untouched", () => {
63
+ const { sqlite, db } = createTestDb();
64
+ insertRow(
65
+ sqlite,
66
+ "chatgpt-subscription",
67
+ "openai",
68
+ '{"type":"api_key","credential":"vault/openai"}',
69
+ );
70
+
71
+ migrateChatgptSubscriptionRowIdentity(db);
72
+
73
+ expect(readProvider(sqlite, "chatgpt-subscription")).toBe("openai");
74
+ });
75
+
76
+ test("leaves other rows untouched", () => {
77
+ const { sqlite, db } = createTestDb();
78
+ insertRow(sqlite, "openai-key", "openai", '{"type":"api_key"}');
79
+ insertRow(sqlite, "vellum", "vellum", '{"type":"platform"}');
80
+
81
+ migrateChatgptSubscriptionRowIdentity(db);
82
+
83
+ expect(readProvider(sqlite, "openai-key")).toBe("openai");
84
+ expect(readProvider(sqlite, "vellum")).toBe("vellum");
85
+ });
86
+
87
+ test("leaves unparseable auth untouched", () => {
88
+ const { sqlite, db } = createTestDb();
89
+ insertRow(sqlite, "chatgpt-subscription", "openai", "not json");
90
+
91
+ migrateChatgptSubscriptionRowIdentity(db);
92
+
93
+ expect(readProvider(sqlite, "chatgpt-subscription")).toBe("openai");
94
+ });
95
+
96
+ test("is idempotent", () => {
97
+ const { sqlite, db } = createTestDb();
98
+ insertRow(
99
+ sqlite,
100
+ "chatgpt-subscription",
101
+ "openai",
102
+ '{"type":"oauth_subscription"}',
103
+ );
104
+
105
+ migrateChatgptSubscriptionRowIdentity(db);
106
+ migrateChatgptSubscriptionRowIdentity(db);
107
+
108
+ expect(readProvider(sqlite, "chatgpt-subscription")).toBe("chatgpt");
109
+ });
110
+
111
+ test("no-ops without the table or the row", () => {
112
+ const bare = new Database(":memory:");
113
+ expect(() =>
114
+ migrateChatgptSubscriptionRowIdentity(drizzle(bare, { schema })),
115
+ ).not.toThrow();
116
+
117
+ const { db } = createTestDb();
118
+ expect(() => migrateChatgptSubscriptionRowIdentity(db)).not.toThrow();
119
+ });
120
+ });
@@ -0,0 +1,62 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+
3
+ /**
4
+ * Stamp the ChatGPT-subscription row with its own provider identity.
5
+ *
6
+ * The row is the subscription route by definition (auth modality = provider
7
+ * identity), but it historically stored `provider: "openai"` and was found
8
+ * by name, which left provider "openai" ambiguous on disk: a BYOK api_key
9
+ * row and the subscription row read identically at the provider column.
10
+ * With the row carrying `provider: "chatgpt"`, auth type is derivable from
11
+ * the provider for every row, and provider-keyed scans for "openai" no
12
+ * longer surface the subscription row.
13
+ *
14
+ * Scoped tightly: only the canonical row name with oauth_subscription auth
15
+ * is flipped. A claiming row under the same name with key auth is an
16
+ * ordinary connection and keeps its provider. Idempotent: a flipped row no
17
+ * longer matches, and the table-exists guard covers databases from before
18
+ * migration 243.
19
+ */
20
+ export function migrateChatgptSubscriptionRowIdentity(
21
+ database: DrizzleDb,
22
+ ): void {
23
+ const raw = getSqliteFrom(database);
24
+
25
+ const tableExists = raw
26
+ .query(
27
+ `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'provider_connections'`,
28
+ )
29
+ .get();
30
+ if (!tableExists) {
31
+ return;
32
+ }
33
+
34
+ const row = raw
35
+ .query(
36
+ `SELECT provider, auth FROM provider_connections WHERE name = 'chatgpt-subscription'`,
37
+ )
38
+ .get() as { provider: string; auth: string } | null;
39
+ if (!row || row.provider !== "openai") {
40
+ return;
41
+ }
42
+
43
+ let authType: unknown;
44
+ try {
45
+ const parsed: unknown = JSON.parse(row.auth);
46
+ authType =
47
+ parsed !== null && typeof parsed === "object"
48
+ ? (parsed as { type?: unknown }).type
49
+ : undefined;
50
+ } catch {
51
+ return;
52
+ }
53
+ if (authType !== "oauth_subscription") {
54
+ return;
55
+ }
56
+
57
+ raw
58
+ .prepare(
59
+ `UPDATE provider_connections SET provider = 'chatgpt', updated_at = ? WHERE name = 'chatgpt-subscription'`,
60
+ )
61
+ .run(Date.now());
62
+ }
@@ -19,8 +19,32 @@ import { sql } from "drizzle-orm";
19
19
  export function realUserTurnContentFilter(
20
20
  alias: string,
21
21
  ): ReturnType<typeof sql> {
22
- return sql.raw(
23
- `${alias}.content NOT LIKE '%"type":"tool\\_result"%' ESCAPE '\\' ` +
24
- `AND ${alias}.content NOT LIKE '%"type":"web\\_search\\_tool\\_result"%' ESCAPE '\\'`,
22
+ return sql.raw(realUserTurnContentFilterSql(alias));
23
+ }
24
+
25
+ /**
26
+ * Raw-string form of {@link realUserTurnContentFilter}, for queries built as
27
+ * plain SQL template strings (`rawAll` sites). Same fragment, one source.
28
+ *
29
+ * `finalized = 1`: the grouped tool-result row is a USER-role row reserved
30
+ * in-flight (`ensureToolResultRowReserved`), and while it streams its content
31
+ * is a `{ ref }` pointer that does not contain the tool_result text the
32
+ * exclusions match. Without this predicate it counts as a real user turn
33
+ * mid-tool-execution and stops counting once the content folds inline.
34
+ *
35
+ * Bare `[]` content is deliberately NOT excluded: a hidden send persists its
36
+ * user row with empty display content (`processMessage` with
37
+ * `displayContent: ""`) and still runs a turn, so `[]` rows are legitimate
38
+ * turns. The cost is a narrow pre-existing window in the writer-creation
39
+ * fallback, where the tool-result row is born finalized with a `[]`
40
+ * placeholder and counts until the first content write lands; that window is
41
+ * rare (writer creation failure only) and transient, and closing it needs a
42
+ * signal that distinguishes the placeholder from a real empty-display turn.
43
+ */
44
+ export function realUserTurnContentFilterSql(alias: string): string {
45
+ return (
46
+ `${alias}.finalized = 1 ` +
47
+ `AND ${alias}.content NOT LIKE '%"type":"tool\\_result"%' ESCAPE '\\' ` +
48
+ `AND ${alias}.content NOT LIKE '%"type":"web\\_search\\_tool\\_result"%' ESCAPE '\\'`
25
49
  );
26
50
  }
@@ -22,13 +22,13 @@ export const documents = sqliteTable(
22
22
  wordCount: integer("word_count").notNull().default(0),
23
23
  createdAt: integer("created_at").notNull(),
24
24
  updatedAt: integer("updated_at").notNull(),
25
- // Workspace-relative path of the markdown file this document is bound to.
26
- // NULL for documents with no file behind them.
25
+ // Unused by the daemon: no code reads or writes the column, and some rows
26
+ // carry a non-NULL path. It stays in the model because migration 360 puts
27
+ // it in the physical table and the model must keep describing that table.
27
28
  workspacePath: text("workspace_path"),
28
29
  },
29
30
  (table) => [
30
- // Partial so the many file-less documents stay unconstrained while a given
31
- // file resolves to exactly one document.
31
+ // Partial, so the NULL rows stay unconstrained.
32
32
  uniqueIndex("idx_documents_workspace_path")
33
33
  .on(table.workspacePath)
34
34
  .where(sql`workspace_path IS NOT NULL`),
@@ -473,6 +473,7 @@ import { migrateAddConversationSubagentKind } from "./migrations/362-add-convers
473
473
  import { migrateBackfillScheduleInferenceProfile } from "./migrations/363-backfill-schedule-inference-profile.js";
474
474
  import { migrateAddScheduleSourceKey } from "./migrations/364-add-schedule-source-key.js";
475
475
  import { migrateAddConversationForkStrategy } from "./migrations/365-add-conversation-fork-strategy.js";
476
+ import { migrateChatgptSubscriptionRowIdentity } from "./migrations/366-chatgpt-subscription-row-identity.js";
476
477
  import type { MigrationStep } from "./migrations/run-migrations.js";
477
478
 
478
479
  export const migrationSteps: MigrationStep[] = [
@@ -1573,4 +1574,12 @@ export const migrationSteps: MigrationStep[] = [
1573
1574
  },
1574
1575
  migrateAddScheduleSourceKey,
1575
1576
  migrateAddConversationForkStrategy,
1577
+ {
1578
+ name: "migrateChatgptSubscriptionRowIdentity",
1579
+ run: migrateChatgptSubscriptionRowIdentity,
1580
+ // The table-exists guard treats a missing table as nothing-to-do, so the
1581
+ // creating migration must be checkpointed first or a repair flow could
1582
+ // permanently checkpoint the no-op.
1583
+ dependsOn: ["migrateCreateProviderConnections"],
1584
+ },
1576
1585
  ];
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Guards that `resolveOauthCallbackUrl` reaches plugins.
3
+ *
4
+ * The shim written into `<workspaceDir>/node_modules/@vellumai/plugin-api`
5
+ * re-binds whatever `Object.keys()` finds on the plugin-api namespace, so an
6
+ * export missing from `index.ts` is missing from every installed plugin with
7
+ * no other signal than a plugin failing to import it.
8
+ */
9
+
10
+ import { describe, expect, test } from "bun:test";
11
+
12
+ import { PLUGIN_API_EXPORTS } from "../../embedded/plugin-api.js";
13
+ import * as pluginApi from "../index.js";
14
+
15
+ describe("plugin-api OAuth callback export", () => {
16
+ test("is exported from the plugin-api surface", () => {
17
+ expect(typeof pluginApi.resolveOauthCallbackUrl).toEqual("function");
18
+ });
19
+
20
+ test("is carried into the generated shim's binding list", () => {
21
+ expect(PLUGIN_API_EXPORTS).toContain("resolveOauthCallbackUrl");
22
+ });
23
+
24
+ test("takes no arguments, so a plugin cannot vary the URI", () => {
25
+ // The value a Client ID Metadata Document publishes and the value the
26
+ // host later authorizes with have to be the same string.
27
+ expect(pluginApi.resolveOauthCallbackUrl.length).toEqual(0);
28
+ });
29
+ });
@@ -39,6 +39,14 @@ export const HOOKS = {
39
39
  /** Union of every hook name declared in {@link HOOKS}. */
40
40
  export type HookName = (typeof HOOKS)[keyof typeof HOOKS];
41
41
 
42
+ /**
43
+ * Message kind for the hidden user row that starts a voice escalation leg.
44
+ * Hooks use this marker to distinguish the continuation instruction from
45
+ * other transcript-suppressed prompts without depending on host voice code.
46
+ */
47
+ export const VOICE_ESCALATION_CONTINUATION_MESSAGE_KIND =
48
+ "voice_escalation_continuation";
49
+
42
50
  /**
43
51
  * Appended (inside the `<system_notice>` wrapper) to the internal continuation /
44
52
  * completion nudge strings that re-query the model. Those notices are injected