@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
@@ -90,7 +90,6 @@ export interface AclEnforcementParams {
90
90
  rawSenderId: string | undefined;
91
91
  sourceChannel: ChannelId;
92
92
  conversationExternalId: string;
93
- canonicalAssistantId: string;
94
93
  trimmedContent: string;
95
94
  sourceMetadata: SourceMetadata | undefined;
96
95
  actorDisplayName: string | undefined;
@@ -190,7 +189,6 @@ export async function enforceIngressAcl(
190
189
  rawSenderId,
191
190
  sourceChannel,
192
191
  conversationExternalId,
193
- canonicalAssistantId,
194
192
  trimmedContent,
195
193
  sourceMetadata,
196
194
  actorDisplayName,
@@ -426,7 +424,6 @@ export async function enforceIngressAcl(
426
424
  // Still notify the guardian about the access attempt
427
425
  try {
428
426
  await notifyGuardianOfAccessRequest({
429
- canonicalAssistantId,
430
427
  sourceChannel,
431
428
  conversationExternalId,
432
429
  actorExternalId: canonicalSenderId ?? rawSenderId,
@@ -509,7 +506,6 @@ export async function enforceIngressAcl(
509
506
  if (emailVerifyResult.initiated) {
510
507
  try {
511
508
  await notifyGuardianOfAccessRequest({
512
- canonicalAssistantId,
513
509
  sourceChannel,
514
510
  conversationExternalId,
515
511
  actorExternalId: canonicalSenderId ?? rawSenderId,
@@ -554,14 +550,12 @@ export async function enforceIngressAcl(
554
550
  let handshakeInProgress = false;
555
551
  if (isCallbackInteraction) {
556
552
  handshakeInProgress = await isApprovalHandshakeInProgress({
557
- canonicalAssistantId,
558
553
  sourceChannel,
559
554
  actorExternalId: (canonicalSenderId ?? rawSenderId)!,
560
555
  });
561
556
  } else {
562
557
  try {
563
558
  const accessResult = await notifyGuardianOfAccessRequest({
564
- canonicalAssistantId,
565
559
  sourceChannel,
566
560
  conversationExternalId,
567
561
  actorExternalId: canonicalSenderId ?? rawSenderId,
@@ -730,7 +724,6 @@ export async function enforceIngressAcl(
730
724
  if (slackVerifyResult.initiated) {
731
725
  try {
732
726
  await notifyGuardianOfAccessRequest({
733
- canonicalAssistantId,
734
727
  sourceChannel,
735
728
  conversationExternalId,
736
729
  actorExternalId: canonicalSenderId ?? rawSenderId,
@@ -803,14 +796,12 @@ export async function enforceIngressAcl(
803
796
  if (!terminallyKeptOut) {
804
797
  if (isCallbackInteraction) {
805
798
  handshakeInProgress = await isApprovalHandshakeInProgress({
806
- canonicalAssistantId,
807
799
  sourceChannel,
808
800
  actorExternalId: (canonicalSenderId ?? rawSenderId)!,
809
801
  });
810
802
  } else {
811
803
  try {
812
804
  const accessResult = await notifyGuardianOfAccessRequest({
813
- canonicalAssistantId,
814
805
  sourceChannel,
815
806
  conversationExternalId,
816
807
  actorExternalId: canonicalSenderId ?? rawSenderId,
@@ -27,6 +27,7 @@ import {
27
27
  ADMISSION_FLOOR,
28
28
  type AdmissionPolicy,
29
29
  isAdmissionPolicyExemptChannel,
30
+ TRUST_CLASS_RANK,
30
31
  } from "@vellumai/gateway-client";
31
32
 
32
33
  import type { ChannelId } from "../../../channels/types.js";
@@ -73,23 +74,6 @@ export type AdmissionPolicyResult =
73
74
  // Public API
74
75
  // ---------------------------------------------------------------------------
75
76
 
76
- /**
77
- * Trust-class ordinal compared against {@link ADMISSION_FLOOR} to make the
78
- * admission decision (`rank >= floor`). Higher rank = more trusted.
79
- * Blocked/revoked never reach this comparison — they short-circuit to deny on
80
- * member status above — so they carry no rank here.
81
- *
82
- * The two halves of the floor check: this table is keyed by `TrustClass`,
83
- * `ADMISSION_FLOOR` (from `@vellumai/gateway-client`) by `AdmissionPolicy`.
84
- * They are only ever read together, here, so they live next to their use.
85
- */
86
- const TRUST_CLASS_RANK: Record<TrustClass, number> = {
87
- guardian: 4,
88
- trusted_contact: 3,
89
- unverified_contact: 2,
90
- unknown: 1,
91
- };
92
-
93
77
  /**
94
78
  * Policies under which completing verification could lift the sender past
95
79
  * the floor. Used to decide whether to fire the upgrade UX on deny.
@@ -54,7 +54,6 @@ function makeParams(
54
54
  isDuplicate: false,
55
55
  commandIntent: { type: "start", payload: "gv_token123" },
56
56
  rawSenderId: "user-42",
57
- canonicalAssistantId: "self",
58
57
  sourceChannel: "telegram",
59
58
  conversationExternalId: "chat-123",
60
59
  eventId: "event-1",
@@ -24,6 +24,7 @@ import {
24
24
  import type { ChannelId } from "../../../channels/types.js";
25
25
  import { sendTelegramReply } from "../../../messaging/providers/telegram-bot/send.js";
26
26
  import { getLogger } from "../../../util/logger.js";
27
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../assistant-scope.js";
27
28
  import { RESEND_COOLDOWN_MS } from "../../verification-outbound-actions.js";
28
29
  import {
29
30
  composeVerificationText,
@@ -40,7 +41,6 @@ export interface BootstrapInterceptParams {
40
41
  isDuplicate: boolean;
41
42
  commandIntent: Record<string, unknown> | undefined;
42
43
  rawSenderId: string | undefined;
43
- canonicalAssistantId: string;
44
44
  sourceChannel: ChannelId;
45
45
  conversationExternalId: string;
46
46
  eventId: string;
@@ -96,7 +96,6 @@ export async function handleBootstrapIntercept(
96
96
  isDuplicate,
97
97
  commandIntent,
98
98
  rawSenderId,
99
- canonicalAssistantId,
100
99
  sourceChannel,
101
100
  conversationExternalId,
102
101
  eventId,
@@ -208,7 +207,7 @@ export async function handleBootstrapIntercept(
208
207
  deliverBootstrapVerificationTelegram(
209
208
  conversationExternalId,
210
209
  telegramBody,
211
- canonicalAssistantId,
210
+ DAEMON_INTERNAL_ASSISTANT_ID,
212
211
  );
213
212
 
214
213
  // Update delivery tracking (best-effort — the code is already on its way)
@@ -11,20 +11,23 @@
11
11
  * the message's metadata via a single transactional content+metadata update,
12
12
  * so downstream renderers can surface the edited marker.
13
13
  *
14
- * Extracted from inbound-message-handler.ts to keep the top-level handler
15
- * focused on orchestration.
14
+ * An edit belongs to the conversation of the message it changes, so the stage
15
+ * resolves that message before it records anything, and an edit with no
16
+ * resolvable target is dropped.
16
17
  */
17
18
  import type { ChannelId } from "../../../channels/types.js";
18
19
  import {
19
20
  mergeSlackMetadata,
20
21
  readSlackMetadata,
21
22
  } from "../../../messaging/providers/slack/message-metadata.js";
23
+ import type { MessageRow } from "../../../persistence/conversation-crud.js";
22
24
  import {
23
25
  getMessageById,
24
26
  updateMessageContent,
25
27
  updateMessageContentAndMetadata,
26
28
  } from "../../../persistence/conversation-crud.js";
27
29
  import {
30
+ findInboundEvent,
28
31
  findMessageBySourceId,
29
32
  recordInbound,
30
33
  } from "../../../persistence/delivery-crud.js";
@@ -45,7 +48,6 @@ export interface EditInterceptParams {
45
48
  externalMessageId: string;
46
49
  sourceMessageId: string;
47
50
  sourceThreadId?: string;
48
- canonicalAssistantId: string;
49
51
  assistantId: string;
50
52
  content: string | undefined;
51
53
  /** Channel ID for channel-level interaction tracking. */
@@ -68,24 +70,23 @@ export async function handleEditIntercept(
68
70
  externalMessageId,
69
71
  sourceMessageId,
70
72
  sourceThreadId,
71
- canonicalAssistantId,
72
73
  assistantId,
73
74
  content,
74
75
  } = params;
75
76
 
76
- // Dedup the edit event itself (retried edited_message webhooks)
77
- const editResult = recordInbound(
77
+ // Dedup the edit event itself (retried edited_message webhooks) before the
78
+ // lookup below, so a redelivery answers immediately instead of waiting out
79
+ // the retry window a second time.
80
+ const alreadyRecorded = findInboundEvent(
78
81
  sourceChannel,
79
82
  conversationExternalId,
80
83
  externalMessageId,
81
- { sourceMessageId, sourceThreadId, assistantId: canonicalAssistantId },
82
84
  );
83
-
84
- if (editResult.duplicate) {
85
+ if (alreadyRecorded) {
85
86
  return {
86
87
  accepted: true,
87
88
  duplicate: true,
88
- eventId: editResult.eventId,
89
+ eventId: alreadyRecorded.eventId,
89
90
  };
90
91
  }
91
92
 
@@ -119,81 +120,100 @@ export async function handleEditIntercept(
119
120
  }
120
121
  }
121
122
 
122
- if (original) {
123
- const newContent = content ?? "";
124
- // Short-circuit no-op edits: Slack fires `message_changed` for link
125
- // unfurls and other decorations where the text is identical to the
126
- // previous revision. Skipping the DB write here covers that case and
127
- // also drops trivially-redundant edit webhooks. We only have the
128
- // authoritative previous text once the original row is located, so
129
- // this check lives after the lookup.
130
- const existingRow = getMessageById(original.messageId);
131
- if (
132
- existingRow &&
133
- stringifyMessageContent(existingRow.content) === newContent
134
- ) {
135
- log.debug(
136
- {
137
- assistantId,
138
- sourceChannel,
139
- sourceMessageId,
140
- messageId: original.messageId,
141
- },
142
- "Edit text unchanged; skipping update",
143
- );
144
- return {
145
- accepted: true,
146
- duplicate: false,
147
- noop: true,
148
- eventId: editResult.eventId,
149
- };
150
- }
151
- if (sourceChannel === "slack") {
152
- // Slack edits stamp `slackMeta.editedAt` so the chronological
153
- // transcript renderer can surface the edited marker. The merge
154
- // tolerates rows that lack slackMeta enrichment by synthesizing
155
- // the minimum-required fields from the lookup data.
156
- applySlackEditMetadata({
157
- messageId: original.messageId,
158
- conversationExternalId,
159
- sourceMessageId,
160
- sourceThreadId,
161
- newContent,
162
- });
163
- } else {
164
- updateMessageContent(original.messageId, newContent);
165
- }
166
- // The edit changed searchable text (the no-op guard above already returned
167
- // for identical content) and this path bypasses the `addMessage` persist
168
- // path, so reindex the message into the lexical index — the idempotent
169
- // upsert replaces the stale Qdrant point with the edited content.
170
- enqueueLexicalIndexForMessage(original.messageId);
171
- log.info(
172
- { assistantId, sourceMessageId, messageId: original.messageId },
173
- "Updated message content from edited_message",
174
- );
175
- } else {
176
- // For Slack, treat missing-target edits as `debug` (the row may have
177
- // been compacted, never stored, or pre-date this upgrade); for other
178
- // channels, retain the louder `warn` since their edit pipelines
179
- // historically expect the row to exist.
123
+ if (!original) {
124
+ // Nothing to edit, and nothing to record it against: recording it anyway
125
+ // would resolve a conversation from the edit's own address and create one
126
+ // there.
127
+ //
128
+ // Slack keeps this at `debug`, since the row may have been compacted or
129
+ // never stored. Other channels keep the louder `warn`, since their edit
130
+ // pipelines expect the row to exist.
131
+ const missingTarget = {
132
+ assistantId,
133
+ sourceChannel,
134
+ conversationExternalId,
135
+ sourceMessageId,
136
+ };
180
137
  if (sourceChannel === "slack") {
181
- log.debug(
182
- {
183
- assistantId,
184
- sourceChannel,
185
- channelId: conversationExternalId,
186
- externalMessageId: sourceMessageId,
187
- },
188
- "Slack edit target not found, ignoring",
189
- );
138
+ log.debug(missingTarget, "Slack edit target not found, ignoring");
190
139
  } else {
191
140
  log.warn(
192
- { assistantId, sourceChannel, conversationExternalId, sourceMessageId },
141
+ missingTarget,
193
142
  "Could not find original message for edit after retries, ignoring",
194
143
  );
195
144
  }
145
+ return { accepted: true, duplicate: false, edited: false };
146
+ }
147
+
148
+ // The edit belongs to the conversation of the message it changes. Resolving
149
+ // one from the edit's own address would key it on the edited message's
150
+ // timestamp and create a conversation there.
151
+ const editResult = recordInbound(
152
+ sourceChannel,
153
+ conversationExternalId,
154
+ externalMessageId,
155
+ { sourceMessageId, conversationId: original.conversationId },
156
+ );
157
+ if (editResult.duplicate) {
158
+ // Two deliveries of one edit raced through the probe above while neither
159
+ // had recorded yet. The first owns the write; applying it twice would
160
+ // re-enqueue lexical indexing for no change.
161
+ return { accepted: true, duplicate: true, eventId: editResult.eventId };
162
+ }
163
+
164
+ const newContent = content ?? "";
165
+ // Short-circuit no-op edits: Slack fires `message_changed` for link
166
+ // unfurls and other decorations where the text is identical to the
167
+ // previous revision. Skipping the DB write here covers that case and
168
+ // also drops trivially-redundant edit webhooks. We only have the
169
+ // authoritative previous text once the original row is located, so
170
+ // this check lives after the lookup.
171
+ const existingRow = getMessageById(original.messageId);
172
+ if (
173
+ existingRow &&
174
+ stringifyMessageContent(existingRow.content) === newContent
175
+ ) {
176
+ log.debug(
177
+ {
178
+ assistantId,
179
+ sourceChannel,
180
+ sourceMessageId,
181
+ messageId: original.messageId,
182
+ },
183
+ "Edit text unchanged; skipping update",
184
+ );
185
+ return {
186
+ accepted: true,
187
+ duplicate: false,
188
+ noop: true,
189
+ eventId: editResult.eventId,
190
+ };
191
+ }
192
+ if (sourceChannel === "slack") {
193
+ // Slack edits stamp `slackMeta.editedAt` so the chronological
194
+ // transcript renderer can surface the edited marker. The merge
195
+ // tolerates rows that lack slackMeta enrichment by synthesizing
196
+ // the minimum-required fields from the lookup data.
197
+ applySlackEditMetadata({
198
+ messageId: original.messageId,
199
+ existingRow,
200
+ conversationExternalId,
201
+ sourceMessageId,
202
+ sourceThreadId,
203
+ newContent,
204
+ });
205
+ } else {
206
+ updateMessageContent(original.messageId, newContent);
196
207
  }
208
+ // The edit changed searchable text (the no-op guard above already returned
209
+ // for identical content) and this path bypasses the `addMessage` persist
210
+ // path, so reindex the message into the lexical index — the idempotent
211
+ // upsert replaces the stale Qdrant point with the edited content.
212
+ enqueueLexicalIndexForMessage(original.messageId);
213
+ log.info(
214
+ { assistantId, sourceMessageId, messageId: original.messageId },
215
+ "Updated message content from edited_message",
216
+ );
197
217
 
198
218
  return {
199
219
  accepted: true,
@@ -219,6 +239,8 @@ export async function handleEditIntercept(
219
239
  */
220
240
  function applySlackEditMetadata(params: {
221
241
  messageId: string;
242
+ /** The stored row, already read by the caller's no-op guard. */
243
+ existingRow: MessageRow | null;
222
244
  conversationExternalId: string;
223
245
  sourceMessageId: string;
224
246
  sourceThreadId?: string;
@@ -226,13 +248,13 @@ function applySlackEditMetadata(params: {
226
248
  }): void {
227
249
  const {
228
250
  messageId,
251
+ existingRow: row,
229
252
  conversationExternalId,
230
253
  sourceMessageId,
231
254
  sourceThreadId,
232
255
  newContent,
233
256
  } = params;
234
257
 
235
- const row = getMessageById(messageId);
236
258
  const outerMetadata: Record<string, unknown> =
237
259
  row?.metadata != null ? safeParseRecord(row.metadata) : {};
238
260
  const existingSlackMeta =
@@ -51,7 +51,6 @@ function makeParams(
51
51
  callbackData: undefined,
52
52
  rawSenderId: "user-42",
53
53
  canonicalSenderId: "user-42",
54
- canonicalAssistantId: "self",
55
54
  sourceChannel: "slack" as const,
56
55
  conversationExternalId: "chat-123",
57
56
  conversationId: "conv-abc",
@@ -15,6 +15,7 @@ import {
15
15
  } from "../../../channels/gateway-guardian-requests.js";
16
16
  import type { ChannelId } from "../../../channels/types.js";
17
17
  import { getLogger } from "../../../util/logger.js";
18
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../assistant-scope.js";
18
19
  import { deliverChannelReply } from "../../gateway-client.js";
19
20
  import {
20
21
  type GuardianPendingScope,
@@ -41,11 +42,16 @@ export interface GuardianReplyInterceptParams {
41
42
  reactedMessageTs?: string;
42
43
  rawSenderId: string | undefined;
43
44
  canonicalSenderId: string | null;
44
- canonicalAssistantId: string;
45
45
  sourceChannel: ChannelId;
46
46
  conversationExternalId: string;
47
- conversationId: string;
48
- eventId: string;
47
+ /**
48
+ * Conversation the message arrived in. Reactions resolve their target by the
49
+ * reacted card's own address and are routed before any conversation is
50
+ * known, so they pass none.
51
+ */
52
+ conversationId?: string;
53
+ /** Inbound event id, echoed on the consumed response when the caller has one. */
54
+ eventId?: string;
49
55
  replyCallbackUrl: string | undefined;
50
56
  trustClass: string;
51
57
  guardianPrincipalId: string | null | undefined;
@@ -77,7 +83,6 @@ export async function handleGuardianReplyIntercept(
77
83
  reactedMessageTs,
78
84
  rawSenderId,
79
85
  canonicalSenderId,
80
- canonicalAssistantId,
81
86
  sourceChannel,
82
87
  conversationExternalId,
83
88
  conversationId,
@@ -178,7 +183,7 @@ export async function handleGuardianReplyIntercept(
178
183
  channelDeliveryContext: {
179
184
  replyCallbackUrl,
180
185
  guardianChatId: conversationExternalId,
181
- assistantId: canonicalAssistantId,
186
+ assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
182
187
  },
183
188
  });
184
189
 
@@ -188,7 +193,7 @@ export async function handleGuardianReplyIntercept(
188
193
  const routerReplyPayload: Parameters<typeof deliverChannelReply>[1] = {
189
194
  chatId: conversationExternalId,
190
195
  text: routerResult.replyText,
191
- assistantId: canonicalAssistantId,
196
+ assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
192
197
  };
193
198
  // On Slack, send guardian management replies (disambiguation, pending
194
199
  // request lists, etc.) as ephemeral so only the guardian sees them.
@@ -210,7 +215,7 @@ export async function handleGuardianReplyIntercept(
210
215
  response: {
211
216
  accepted: true,
212
217
  duplicate: false,
213
- eventId,
218
+ ...(eventId ? { eventId } : {}),
214
219
  canonicalRouter: routerResult.type,
215
220
  requestId: routerResult.requestId,
216
221
  },
@@ -69,17 +69,28 @@ mock.module("../../../contacts/contact-store.js", () => ({
69
69
  // Downstream side-effect stubs
70
70
  // ---------------------------------------------------------------------------
71
71
 
72
- let recordInboundCalls = 0;
72
+ let recordInboundCalls: Array<{ conversationId?: string }> = [];
73
+ let recordedEvent: { eventId: string; conversationId: string } | null = null;
74
+ let outboundTargetConversationId: string | null = null;
75
+ let storedTarget: { messageId: string; conversationId: string } | null = null;
73
76
  mock.module("../../../persistence/delivery-crud.js", () => ({
74
- recordInbound: () => {
75
- recordInboundCalls++;
77
+ recordInbound: (
78
+ _channel: string,
79
+ _chat: string,
80
+ _externalMessageId: string,
81
+ options?: { conversationId?: string },
82
+ ) => {
83
+ recordInboundCalls.push({ conversationId: options?.conversationId });
76
84
  return {
77
85
  eventId: "evt-1",
78
- conversationId: "conv-1",
86
+ conversationId: options?.conversationId ?? "conv-minted",
79
87
  accepted: true,
80
88
  duplicate: false,
81
89
  };
82
90
  },
91
+ findMessageBySourceId: () => storedTarget,
92
+ findSlackConversationByMessageTs: () => outboundTargetConversationId,
93
+ findInboundEvent: () => recordedEvent,
83
94
  clearPayload: () => {},
84
95
  linkMessage: () => {},
85
96
  }));
@@ -172,7 +183,6 @@ function buildParams(overrides: {
172
183
  sourceInterface: "slack" as const,
173
184
  conversationExternalId: SLACK_CHANNEL_ID,
174
185
  externalMessageId: `${SLACK_CHANNEL_ID}:1700000000.1:${msgCounter}`,
175
- canonicalAssistantId: "assistant-1",
176
186
  rawSenderId: overrides.rawSenderId,
177
187
  canonicalSenderId: overrides.rawSenderId,
178
188
  actorDisplayName: "Reactor",
@@ -185,7 +195,6 @@ function buildParams(overrides: {
185
195
  ? { trustVerdict: overrides.trustVerdict }
186
196
  : {}),
187
197
  } as never,
188
- slackChannelName: "general",
189
198
  approvalConversationGenerator: undefined,
190
199
  };
191
200
  }
@@ -194,7 +203,7 @@ function expectDropped(result: Record<string, unknown>): void {
194
203
  expect(result.reaction).toBe("dropped_unknown_actor");
195
204
  // Dropped before any write or routing: no dedup record, no transcript row,
196
205
  // no approval-pipeline dispatch.
197
- expect(recordInboundCalls).toBe(0);
206
+ expect(recordInboundCalls.length).toBe(0);
198
207
  expect(addMessageCalls).toBe(0);
199
208
  expect(guardianReplyCalls.length).toBe(0);
200
209
  }
@@ -205,10 +214,13 @@ describe("reaction intercept consumes the stamped verdict directly", () => {
205
214
  guardianDeliveryReads = 0;
206
215
  setMemberVerdictCalls = 0;
207
216
  contactLookups = 0;
208
- recordInboundCalls = 0;
217
+ recordInboundCalls = [];
218
+ recordedEvent = null;
219
+ outboundTargetConversationId = null;
209
220
  addMessageCalls = 0;
210
221
  guardianReplyCalls = [];
211
222
  guardianReplyResponse = undefined;
223
+ storedTarget = { messageId: "msg-target", conversationId: "conv-target" };
212
224
  });
213
225
 
214
226
  test("guardian verdict routes the reaction into the approval decision pipeline", async () => {
@@ -245,6 +257,77 @@ describe("reaction intercept consumes the stamped verdict directly", () => {
245
257
  expect(result.accepted).toBe(true);
246
258
  expect(result.reaction).toBeUndefined();
247
259
  expect(addMessageCalls).toBe(1);
260
+ // Recorded into the reacted message's conversation, never a fresh one.
261
+ expect(recordInboundCalls).toEqual([{ conversationId: "conv-target" }]);
262
+ });
263
+
264
+ test("a reaction on the assistant's own post resolves through slackMeta", async () => {
265
+ // Outbound posts open no inbound event, so the ts is only on the row.
266
+ storedTarget = null;
267
+ outboundTargetConversationId = "conv-assistant-post";
268
+
269
+ const result = await handleSlackReactionIntercept(
270
+ buildParams({
271
+ rawSenderId: MEMBER_USER_ID,
272
+ trustVerdict: MEMBER_VERDICT,
273
+ }),
274
+ );
275
+
276
+ expect(recordInboundCalls).toEqual([
277
+ { conversationId: "conv-assistant-post" },
278
+ ]);
279
+ expect(addMessageCalls).toBe(1);
280
+ expect(result).toMatchObject({ accepted: true, duplicate: false });
281
+ });
282
+
283
+ test("a reaction on a message that is not stored is dropped without minting", async () => {
284
+ storedTarget = null;
285
+
286
+ const result = await handleSlackReactionIntercept(
287
+ buildParams({
288
+ rawSenderId: MEMBER_USER_ID,
289
+ trustVerdict: MEMBER_VERDICT,
290
+ }),
291
+ );
292
+
293
+ expect(result.reaction).toBe("dropped_unknown_target");
294
+ expect(recordInboundCalls.length).toBe(0);
295
+ expect(addMessageCalls).toBe(0);
296
+ });
297
+
298
+ test("a redelivered reaction never reaches the guardian rail twice", async () => {
299
+ recordedEvent = { eventId: "evt-1", conversationId: "conv-target" };
300
+
301
+ const result = await handleSlackReactionIntercept(
302
+ buildParams({
303
+ rawSenderId: GUARDIAN_USER_ID,
304
+ trustVerdict: GUARDIAN_VERDICT,
305
+ }),
306
+ );
307
+
308
+ expect(result).toEqual({
309
+ accepted: true,
310
+ duplicate: true,
311
+ eventId: "evt-1",
312
+ });
313
+ expect(guardianReplyCalls.length).toBe(0);
314
+ expect(addMessageCalls).toBe(0);
315
+ expect(recordInboundCalls.length).toBe(0);
316
+ });
317
+
318
+ test("a guardian card reaction still applies when the card is not a stored message", async () => {
319
+ storedTarget = null;
320
+ guardianReplyResponse = { accepted: true, canonicalRouter: "applied" };
321
+
322
+ const result = await handleSlackReactionIntercept(
323
+ buildParams({
324
+ rawSenderId: GUARDIAN_USER_ID,
325
+ trustVerdict: GUARDIAN_VERDICT,
326
+ }),
327
+ );
328
+
329
+ expect(result).toEqual(guardianReplyResponse);
330
+ expect(recordInboundCalls.length).toBe(0);
248
331
  });
249
332
 
250
333
  test("unknown verdict is dropped before any write", async () => {