@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
@@ -209,8 +209,8 @@ describe("credentials/prompt route", () => {
209
209
  test("stores a non-slack credential to secure storage and reports the value as received", async () => {
210
210
  /**
211
211
  * The default delivery persists the value to secure storage and runs the
212
- * manual-token connection sync. The message must name the outcome — the
213
- * value is in hand — so a bare `ok: true` cannot be misread as "the prompt
212
+ * manual-token connection sync. The message must name the outcome (the
213
+ * value is in hand) so a bare `ok: true` cannot be misread as "the prompt
214
214
  * opened".
215
215
  */
216
216
  // GIVEN a standard store-delivery prompt for a non-slack credential
@@ -236,15 +236,12 @@ describe("credentials/prompt route", () => {
236
236
 
237
237
  test("every successful outcome states that the prompt has closed", async () => {
238
238
  /**
239
- * The prompt blocks until answered, so a caller reads the result only after
240
- * the secure input is gone. Without an explicit close signal a model
241
- * follows up with "the prompt is open, paste it there" and the user
242
- * re-submits into a surface that never reappears — the loop reported in
243
- * the Aug 2026 Claude Code auth feedback. Every success path must say so,
244
- * not just the plain vault write.
239
+ * The prompt blocks until answered, so a caller reads the result only once
240
+ * the secure input is gone. Every success path states the close, not just
241
+ * the plain vault write, so the result cannot be read as "the prompt is
242
+ * open, paste it there".
245
243
  */
246
- const closed =
247
- "The secure prompt has closed — do not ask the user to enter this value again.";
244
+ const closed = "The secure prompt has closed.";
248
245
 
249
246
  // GIVEN a plain vault write
250
247
  const stored = (await promptRoute!.handler({
@@ -238,6 +238,7 @@ describe("Invariant 2: no generic plaintext secret read API", () => {
238
238
  "workspace/default-provider-ensure.ts", // legacy anthropic echo disambiguation (vault key presence check)
239
239
  "providers/inference/connection-availability.ts", // shared (provider, connection) availability status (credential presence check only; value never leaves the helper)
240
240
  "plugin-api/resolve-credential.ts", // plugin-facing resolveCredential — reveal-equivalent plaintext read, scoped to the in-context plugin's own field
241
+ "tools/credentials/store.ts", // shared credential write path (setSecureKeyAsync only; no reads) behind credentials/set and plugin-facing storeCredential
241
242
  ]);
242
243
 
243
244
  const thisDir = dirname(fileURLToPath(import.meta.url));
@@ -97,6 +97,7 @@ function buildMockContext(
97
97
  } as Conversation["currentTurnAuthContext"])
98
98
  : undefined,
99
99
  sendToClient: () => {},
100
+ emit: () => {},
100
101
  pendingSurfaceActions: new Map(),
101
102
  lastSurfaceAction: new Map(),
102
103
  surfaceState: new Map(),
@@ -53,6 +53,10 @@ describe("ensureCompleteCustomProfiles", () => {
53
53
  ensureCompleteCustomProfiles(workspaceDir);
54
54
  const saved = readProfiles().partial;
55
55
  expect(saved.model).toBe("claude-haiku-4-5-20251001");
56
+ // This workspace has no connection rows, so the binding is unverifiable
57
+ // and passes through in the legacy field for the collapse migration to
58
+ // judge; with a verified row it would fold into the provider value (see
59
+ // profile-materialization.test.ts).
56
60
  expect(saved.provider).toBe("anthropic");
57
61
  expect(saved.provider_connection).toBe("anthropic-personal");
58
62
  expect(saved.maxTokens).toBe(12345);
@@ -91,7 +95,7 @@ describe("ensureCompleteCustomProfiles", () => {
91
95
  },
92
96
  });
93
97
  ensureCompleteCustomProfiles(workspaceDir);
94
- expect(readProfiles().gpt.provider_connection).toBe("vellum");
98
+ expect(readProfiles().gpt.provider_connection).toBeUndefined();
95
99
  expect(readProfiles().router.provider_connection).toBeUndefined();
96
100
  });
97
101
 
@@ -1,7 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import { getAllDefaultPlugins } from "../plugins/defaults/index.js";
4
- import { getAllDefaultPluginNames } from "../plugins/defaults/main.js";
4
+ import {
5
+ getAllDefaultPluginNames,
6
+ isFirstPartyDefaultPlugin,
7
+ } from "../plugins/defaults/main.js";
5
8
 
6
9
  /**
7
10
  * Guard: the filesystem-backed default-plugin registry (`defaults/main.ts`)
@@ -25,4 +28,12 @@ describe("default plugin names", () => {
25
28
  expect(name).toMatch(/^default-[a-z0-9-]+$/);
26
29
  }
27
30
  });
31
+
32
+ test("isFirstPartyDefaultPlugin matches the filesystem registry and rejects other names", () => {
33
+ for (const name of getAllDefaultPluginNames()) {
34
+ expect(isFirstPartyDefaultPlugin(name)).toBe(true);
35
+ }
36
+ expect(isFirstPartyDefaultPlugin("default-a")).toBe(false);
37
+ expect(isFirstPartyDefaultPlugin("uplug-a")).toBe(false);
38
+ });
28
39
  });
@@ -342,7 +342,11 @@ describe("Discord access-request decisions stay out of the guild channel", () =>
342
342
  test("no Discord delivery is ever addressed to the originating conversation", async () => {
343
343
  // The umbrella invariant, swept across every decision this resolver takes,
344
344
  // so a newly added action cannot quietly reintroduce the leak.
345
- for (const action of ["verify_code", "block", "leave_unverified"] as const) {
345
+ for (const action of [
346
+ "verify_code",
347
+ "block",
348
+ "leave_unverified",
349
+ ] as const) {
346
350
  resetState();
347
351
  const req = makeDiscordAccessRequest();
348
352
 
@@ -27,9 +27,9 @@ describe("the dm-marked Discord route", () => {
27
27
  // regressed, the notice would fall through to the HTTP proxy, which cannot
28
28
  // fetch a base-less URL: the delivery would vanish rather than error, and
29
29
  // every behavioural assertion about where it landed would still pass.
30
- expect(channelForCallback(resolveDeliverCallbackUrlForChannel("discord")!)).toBe(
31
- "discord",
32
- );
30
+ expect(
31
+ channelForCallback(resolveDeliverCallbackUrlForChannel("discord")!),
32
+ ).toBe("discord");
33
33
  });
34
34
  });
35
35
 
@@ -0,0 +1,233 @@
1
+ import { beforeEach, describe, expect, test } from "bun:test";
2
+
3
+ import { getDocumentById } from "../documents/document-store.js";
4
+ import { getSqlite } from "../persistence/db-connection.js";
5
+ import {
6
+ executeDocumentCreate,
7
+ executeDocumentUpdate,
8
+ } from "../tools/document/document-tool.js";
9
+ import type { ToolContext, ToolExecutionResult } from "../tools/types.js";
10
+ import { resetDbForTesting } from "./db-test-helpers.js";
11
+
12
+ const CONVERSATION_ID = "conv-current";
13
+
14
+ /** Long enough to clear the store's minimum-duplicate-length floor. */
15
+ const OPENING =
16
+ "Remote work reshaped the office long before anyone had a name for it.";
17
+
18
+ function makeContext(overrides: Partial<ToolContext> = {}): ToolContext {
19
+ return {
20
+ workingDir: "/tmp/project",
21
+ conversationId: CONVERSATION_ID,
22
+ trustClass: "trusted_contact",
23
+ executionChannel: "slack",
24
+ sendToClient: () => {},
25
+ ...overrides,
26
+ };
27
+ }
28
+
29
+ function parseResult<T>(result: ToolExecutionResult): T {
30
+ return JSON.parse(result.content) as T;
31
+ }
32
+
33
+ function bootstrapDocumentTables(): void {
34
+ resetDbForTesting();
35
+ const raw = getSqlite();
36
+ raw.exec(/*sql*/ `
37
+ DROP TABLE IF EXISTS document_conversations;
38
+ DROP TABLE IF EXISTS documents;
39
+ DROP TABLE IF EXISTS conversations;
40
+
41
+ CREATE TABLE conversations (
42
+ id TEXT PRIMARY KEY,
43
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)
44
+ );
45
+
46
+ CREATE TABLE documents (
47
+ surface_id TEXT PRIMARY KEY,
48
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
49
+ title TEXT NOT NULL,
50
+ content TEXT NOT NULL,
51
+ word_count INTEGER NOT NULL DEFAULT 0,
52
+ created_at INTEGER NOT NULL,
53
+ updated_at INTEGER NOT NULL,
54
+ workspace_path TEXT
55
+ );
56
+
57
+ CREATE TABLE document_conversations (
58
+ surface_id TEXT NOT NULL,
59
+ conversation_id TEXT NOT NULL,
60
+ created_at INTEGER NOT NULL,
61
+ PRIMARY KEY (surface_id, conversation_id),
62
+ FOREIGN KEY (surface_id) REFERENCES documents(surface_id) ON DELETE CASCADE
63
+ );
64
+ `);
65
+ raw
66
+ .query(`INSERT OR IGNORE INTO conversations (id, created_at) VALUES (?, ?)`)
67
+ .run(CONVERSATION_ID, Date.now());
68
+ }
69
+
70
+ function seedDocument(surfaceId: string, content: string): void {
71
+ const now = Date.now();
72
+ const raw = getSqlite();
73
+ raw
74
+ .query(
75
+ `INSERT INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)`,
76
+ )
77
+ .run(
78
+ surfaceId,
79
+ CONVERSATION_ID,
80
+ "Draft",
81
+ content,
82
+ content.split(/\s+/).filter(Boolean).length,
83
+ now,
84
+ now,
85
+ );
86
+ raw
87
+ .query(
88
+ `INSERT OR IGNORE INTO document_conversations (surface_id, conversation_id, created_at) VALUES (?, ?, ?)`,
89
+ )
90
+ .run(surfaceId, CONVERSATION_ID, now);
91
+ }
92
+
93
+ describe("document append idempotency", () => {
94
+ beforeEach(() => {
95
+ bootstrapDocumentTables();
96
+ });
97
+
98
+ test("an opening passed to both document_create and the first append lands once", () => {
99
+ const created = executeDocumentCreate(
100
+ { title: "Draft", initial_content: `# Draft\n\n${OPENING}` },
101
+ makeContext(),
102
+ );
103
+ const surfaceId = parseResult<{ surface_id: string }>(created).surface_id;
104
+
105
+ const result = executeDocumentUpdate(
106
+ {
107
+ surface_id: surfaceId,
108
+ content: `# Draft\n\n${OPENING}\n\nThe second paragraph carries the argument forward.`,
109
+ mode: "append",
110
+ },
111
+ makeContext(),
112
+ );
113
+
114
+ expect(result.isError).toBe(false);
115
+ expect(getDocumentById(surfaceId)?.content).toBe(
116
+ `# Draft\n\n${OPENING}\n\nThe second paragraph carries the argument forward.`,
117
+ );
118
+ });
119
+
120
+ test("an append that only restates the tail writes nothing", () => {
121
+ seedDocument("doc-restate", `# Draft\n\n${OPENING}`);
122
+
123
+ const result = executeDocumentUpdate(
124
+ { surface_id: "doc-restate", content: OPENING, mode: "append" },
125
+ makeContext(),
126
+ );
127
+
128
+ expect(result.isError).toBe(false);
129
+ const body = parseResult<{ success: boolean; message: string }>(result);
130
+ expect(body.success).toBe(true);
131
+ expect(body.message).toBe(
132
+ "Nothing appended: the content is already at the end of the document",
133
+ );
134
+ expect(getDocumentById("doc-restate")?.content).toBe(
135
+ `# Draft\n\n${OPENING}`,
136
+ );
137
+ });
138
+
139
+ test("the client is told what landed, not what was submitted", () => {
140
+ seedDocument("doc-client", OPENING);
141
+ const sent: { markdown: unknown; mode: unknown }[] = [];
142
+
143
+ executeDocumentUpdate(
144
+ {
145
+ surface_id: "doc-client",
146
+ content: `${OPENING}\n\nAnd then the rest.`,
147
+ mode: "append",
148
+ },
149
+ makeContext({
150
+ sendToClient: (message) => {
151
+ if (message.type === "document_editor_update") {
152
+ sent.push({ markdown: message.markdown, mode: message.mode });
153
+ }
154
+ },
155
+ }),
156
+ );
157
+
158
+ expect(sent).toEqual([{ markdown: "And then the rest.", mode: "append" }]);
159
+ });
160
+
161
+ // ── Legitimate repetition the guard must not eat ──────────────────
162
+
163
+ test("keeps a short repeated line, even back to back", () => {
164
+ seedDocument("doc-refrain", "## Checklist\n\nTODO");
165
+
166
+ executeDocumentUpdate(
167
+ { surface_id: "doc-refrain", content: "TODO\n\nTODO", mode: "append" },
168
+ makeContext(),
169
+ );
170
+
171
+ expect(getDocumentById("doc-refrain")?.content).toBe(
172
+ "## Checklist\n\nTODO\n\nTODO\n\nTODO",
173
+ );
174
+ });
175
+
176
+ test("keeps a repeated heading followed by new prose", () => {
177
+ seedDocument("doc-heading", "# Weekly Notes\n\n## Monday");
178
+
179
+ executeDocumentUpdate(
180
+ {
181
+ surface_id: "doc-heading",
182
+ content: "## Monday\n\nShipped the importer.",
183
+ mode: "append",
184
+ },
185
+ makeContext(),
186
+ );
187
+
188
+ expect(getDocumentById("doc-heading")?.content).toBe(
189
+ "# Weekly Notes\n\n## Monday\n\n## Monday\n\nShipped the importer.",
190
+ );
191
+ });
192
+
193
+ test("keeps a long paragraph that repeats something other than the tail", () => {
194
+ seedDocument("doc-midway", `${OPENING}\n\nA later paragraph ends the doc.`);
195
+
196
+ executeDocumentUpdate(
197
+ { surface_id: "doc-midway", content: OPENING, mode: "append" },
198
+ makeContext(),
199
+ );
200
+
201
+ expect(getDocumentById("doc-midway")?.content).toBe(
202
+ `${OPENING}\n\nA later paragraph ends the doc.\n\n${OPENING}`,
203
+ );
204
+ });
205
+
206
+ test("keeps content whose repetition starts partway into the append", () => {
207
+ seedDocument("doc-partway", `# Draft\n\n${OPENING}`);
208
+
209
+ executeDocumentUpdate(
210
+ {
211
+ surface_id: "doc-partway",
212
+ content: `A fresh lead-in.\n\n${OPENING}`,
213
+ mode: "append",
214
+ },
215
+ makeContext(),
216
+ );
217
+
218
+ expect(getDocumentById("doc-partway")?.content).toBe(
219
+ `# Draft\n\n${OPENING}\n\nA fresh lead-in.\n\n${OPENING}`,
220
+ );
221
+ });
222
+
223
+ test("replace mode is never deduplicated", () => {
224
+ seedDocument("doc-replace", OPENING);
225
+
226
+ executeDocumentUpdate(
227
+ { surface_id: "doc-replace", content: OPENING, mode: "replace" },
228
+ makeContext(),
229
+ );
230
+
231
+ expect(getDocumentById("doc-replace")?.content).toBe(OPENING);
232
+ });
233
+ });
@@ -3,8 +3,6 @@
3
3
  * the Library and the per-conversation assets list converge on every surface.
4
4
  * Read routes and rejected writes must stay silent.
5
5
  */
6
- import { mkdirSync, rmSync, writeFileSync } from "node:fs";
7
- import { join } from "node:path";
8
6
  import { afterAll, beforeEach, describe, expect, test } from "bun:test";
9
7
 
10
8
  import type { AssistantEventEnvelope } from "../api/index.js";
@@ -24,9 +22,6 @@ import { resetDbForTesting } from "./db-test-helpers.js";
24
22
 
25
23
  await initializeDb();
26
24
 
27
- const workspaceDir = process.env.VELLUM_WORKSPACE_DIR!;
28
- const notesDir = join(workspaceDir, "sync-notes");
29
-
30
25
  const CONVERSATION_ID = "conv-doc-sync";
31
26
  const OTHER_CONVERSATION_ID = "conv-doc-sync-other";
32
27
  const MISSING_CONVERSATION_ID = "conv-doc-sync-missing";
@@ -110,15 +105,6 @@ async function saveViaRoute(
110
105
  });
111
106
  }
112
107
 
113
- async function openWorkspaceFile(
114
- path: string,
115
- conversationId = CONVERSATION_ID,
116
- ): Promise<unknown> {
117
- return await invoke("documentForWorkspaceFile", {
118
- body: { path, conversationId },
119
- });
120
- }
121
-
122
108
  async function linkViaRoute(
123
109
  surfaceId: string,
124
110
  conversationId: string,
@@ -136,12 +122,9 @@ beforeEach(() => {
136
122
  db.run("DELETE FROM conversations");
137
123
  createConversation({ id: CONVERSATION_ID });
138
124
  createConversation({ id: OTHER_CONVERSATION_ID });
139
- rmSync(notesDir, { recursive: true, force: true });
140
- mkdirSync(notesDir, { recursive: true });
141
125
  });
142
126
 
143
127
  afterAll(() => {
144
- rmSync(notesDir, { recursive: true, force: true });
145
128
  resetDbForTesting();
146
129
  });
147
130
 
@@ -220,67 +203,9 @@ describe("document write routes publish documents:list", () => {
220
203
  expect(events).toHaveLength(1);
221
204
  expect("originClientId" in events[0].message).toBe(false);
222
205
  });
223
-
224
- test("binding a workspace file publishes without an origin so the caller is not suppressed", async () => {
225
- // `viewer-store.loadWorkspaceFileDocument` creates the row and invalidates
226
- // nothing, so the client that opened the file is the one that most needs
227
- // the invalidation.
228
- writeFileSync(join(notesDir, "plan.md"), "# Plan");
229
-
230
- const events = await captureSyncEvents(() =>
231
- invoke("documentForWorkspaceFile", {
232
- body: { path: "sync-notes/plan.md", conversationId: CONVERSATION_ID },
233
- headers: { "x-vellum-client-id": "client-abc" },
234
- }),
235
- );
236
-
237
- expect(events).toHaveLength(1);
238
- expect("originClientId" in events[0].message).toBe(false);
239
- });
240
-
241
- test("binding a workspace file to a new document publishes", async () => {
242
- writeFileSync(join(notesDir, "plan.md"), "# Plan");
243
-
244
- const events = await captureSyncEvents(() =>
245
- openWorkspaceFile("sync-notes/plan.md"),
246
- );
247
- expectDocumentsChanged(events);
248
- });
249
-
250
- test("reopening the file from another conversation publishes the new link", async () => {
251
- writeFileSync(join(notesDir, "plan.md"), "# Plan");
252
- await openWorkspaceFile("sync-notes/plan.md");
253
-
254
- const events = await captureSyncEvents(() =>
255
- openWorkspaceFile("sync-notes/plan.md", OTHER_CONVERSATION_ID),
256
- );
257
- expectDocumentsChanged(events);
258
- });
259
-
260
- test("refreshing a document whose file changed on disk publishes", async () => {
261
- const filePath = join(notesDir, "plan.md");
262
- writeFileSync(filePath, "# Plan");
263
- await openWorkspaceFile("sync-notes/plan.md");
264
- writeFileSync(filePath, "# Plan\n\nedited outside the editor");
265
-
266
- const events = await captureSyncEvents(() =>
267
- openWorkspaceFile("sync-notes/plan.md"),
268
- );
269
- expectDocumentsChanged(events);
270
- });
271
206
  });
272
207
 
273
208
  describe("document routes that change nothing the list shows stay silent", () => {
274
- test("reopening an unchanged, already-linked file publishes nothing", async () => {
275
- writeFileSync(join(notesDir, "plan.md"), "# Plan");
276
- await openWorkspaceFile("sync-notes/plan.md");
277
-
278
- const events = await captureSyncEvents(() =>
279
- openWorkspaceFile("sync-notes/plan.md"),
280
- );
281
- expect(events).toEqual([]);
282
- });
283
-
284
209
  test("a save rejected by validation publishes nothing", async () => {
285
210
  const events = await captureSyncEvents(async () => {
286
211
  await expect(saveViaRoute({ title: undefined })).rejects.toThrow(
@@ -65,9 +65,7 @@ mock.module("../permissions/checker.js", () => ({
65
65
  isDynamicSkillLoadInvocation: () => dynamicSkillLoad,
66
66
  classifyRisk: async () => ({ level: "medium" }),
67
67
  check: async () => ({ decision: checkDecision, reason: "medium risk" }),
68
- generateAllowlistOptions: () => [],
69
68
  generateScopeOptions: () => [],
70
- getCachedAssessment: () => undefined,
71
69
  }));
72
70
 
73
71
  mock.module("../telemetry/tool-usage-store.js", () => ({
@@ -145,7 +145,6 @@ describe("Slack edit propagation", () => {
145
145
  conversationExternalId: seeded.conversationExternalId,
146
146
  externalMessageId: nextEditEventId(),
147
147
  sourceMessageId: seeded.channelTs,
148
- canonicalAssistantId: "self",
149
148
  assistantId: "self",
150
149
  content: "new text",
151
150
  });
@@ -172,7 +171,100 @@ describe("Slack edit propagation", () => {
172
171
  expect(slackMeta!.editedAt!).toBeGreaterThanOrEqual(t0);
173
172
  });
174
173
 
175
- test("threaded Slack edits use the threaded conversation key and preserve thread metadata", async () => {
174
+ // Times out on the default budget: an unresolvable target pays the full
175
+ // `EDIT_LOOKUP_RETRIES` window before it is dropped.
176
+ test("an edit of a message the assistant never stored creates no conversation", async () => {
177
+ // Keying a conversation off the edit's own address made every edit of an
178
+ // unseen message mint one, permanently titled with the loading placeholder.
179
+ const db = getDb();
180
+ const countRows = (table: string): number =>
181
+ (
182
+ db.$client.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as {
183
+ n: number;
184
+ }
185
+ ).n;
186
+
187
+ const resp = (await handleEditIntercept({
188
+ sourceChannel: "slack",
189
+ conversationExternalId: "C0NEVERSEEN",
190
+ externalMessageId: nextEditEventId(),
191
+ sourceMessageId: "1999.0001",
192
+ assistantId: "self",
193
+ content: "edited text",
194
+ })) as Record<string, unknown>;
195
+
196
+ expect(resp.accepted).toBe(true);
197
+ expect(resp.edited).toBe(false);
198
+ expect(countRows("conversations")).toBe(0);
199
+ expect(countRows("channel_inbound_events")).toBe(0);
200
+ expect(countRows("messages")).toBe(0);
201
+ }, 30_000);
202
+
203
+ test("an edit records against the edited message's conversation, not a new one", async () => {
204
+ const seeded = await seedSlackMessage({
205
+ conversationExternalId: "C0123CHANNEL",
206
+ channelTs: "1234.5678",
207
+ initialContent: "original text",
208
+ });
209
+ const db = getDb();
210
+ const conversationsBefore = (
211
+ db.$client.prepare("SELECT COUNT(*) AS n FROM conversations").get() as {
212
+ n: number;
213
+ }
214
+ ).n;
215
+
216
+ await handleEditIntercept({
217
+ sourceChannel: "slack",
218
+ conversationExternalId: seeded.conversationExternalId,
219
+ externalMessageId: nextEditEventId(),
220
+ sourceMessageId: seeded.channelTs,
221
+ assistantId: "self",
222
+ content: "new text",
223
+ });
224
+
225
+ const conversationsAfter = (
226
+ db.$client.prepare("SELECT COUNT(*) AS n FROM conversations").get() as {
227
+ n: number;
228
+ }
229
+ ).n;
230
+ expect(conversationsAfter).toBe(conversationsBefore);
231
+
232
+ const editEvents = db.$client
233
+ .prepare(
234
+ `SELECT conversation_id AS conversationId FROM channel_inbound_events
235
+ WHERE external_message_id LIKE 'edit-event-%'`,
236
+ )
237
+ .all() as Array<{ conversationId: string }>;
238
+ expect(editEvents).toHaveLength(1);
239
+ expect(editEvents[0].conversationId).toBe(seeded.conversationId);
240
+ });
241
+
242
+ test("a redelivered edit is answered without repeating the lookup window", async () => {
243
+ const seeded = await seedSlackMessage({
244
+ conversationExternalId: "C0123CHANNEL",
245
+ channelTs: "1234.5678",
246
+ initialContent: "original text",
247
+ });
248
+ const editEventId = nextEditEventId();
249
+ const send = () =>
250
+ handleEditIntercept({
251
+ sourceChannel: "slack",
252
+ conversationExternalId: seeded.conversationExternalId,
253
+ externalMessageId: editEventId,
254
+ sourceMessageId: seeded.channelTs,
255
+ assistantId: "self",
256
+ content: "new text",
257
+ }) as Promise<Record<string, unknown>>;
258
+
259
+ const first = await send();
260
+ const second = await send();
261
+
262
+ expect(first.duplicate).toBe(false);
263
+ expect(second.duplicate).toBe(true);
264
+ expect(second.eventId).toBe(first.eventId);
265
+ });
266
+
267
+ test("a threaded edit stays in the edited message's conversation and preserves thread metadata", async () => {
176
268
  const conversationExternalId = "C0123CHANNEL";
177
269
  const threadTs = "1234.0000";
178
270
  const seeded = await seedSlackMessage({
@@ -180,6 +272,14 @@ describe("Slack edit propagation", () => {
180
272
  channelTs: "1234.5678",
181
273
  initialContent: "original text",
182
274
  });
275
+ const db = getDb();
276
+ const conversationCount = (): number =>
277
+ (
278
+ db.$client.prepare("SELECT COUNT(*) AS n FROM conversations").get() as {
279
+ n: number;
280
+ }
281
+ ).n;
282
+ const before = conversationCount();
183
283
 
184
284
  const resp = await handleEditIntercept({
185
285
  sourceChannel: "slack",
@@ -187,16 +287,17 @@ describe("Slack edit propagation", () => {
187
287
  externalMessageId: nextEditEventId(),
188
288
  sourceMessageId: seeded.channelTs,
189
289
  sourceThreadId: threadTs,
190
- canonicalAssistantId: "self",
191
290
  assistantId: "self",
192
291
  content: "new text",
193
292
  });
194
293
 
195
294
  expect((resp as Record<string, unknown>).accepted).toBe(true);
295
+
296
+ // The thread id names where the reply goes, not a conversation of the
297
+ // edit's own. Keying one off it is what minted a conversation per edit.
196
298
  const threadedKey = `asst:self:slack:${conversationExternalId}:thread:${threadTs}`;
197
- const editConversation = getConversationByKey(threadedKey);
198
- expect(editConversation).not.toBeNull();
199
- expect(editConversation!.conversationId).not.toBe(seeded.conversationId);
299
+ expect(getConversationByKey(threadedKey)).toBeNull();
300
+ expect(conversationCount()).toBe(before);
200
301
 
201
302
  const after = readMessageRow(seeded.messageId);
202
303
  const outer = JSON.parse(after.metadata!) as Record<string, unknown>;
@@ -216,7 +317,6 @@ describe("Slack edit propagation", () => {
216
317
  conversationExternalId: seeded.conversationExternalId,
217
318
  externalMessageId: nextEditEventId(),
218
319
  sourceMessageId: seeded.channelTs,
219
- canonicalAssistantId: "self",
220
320
  assistantId: "self",
221
321
  content: "first edit",
222
322
  });
@@ -239,7 +339,6 @@ describe("Slack edit propagation", () => {
239
339
  conversationExternalId: seeded.conversationExternalId,
240
340
  externalMessageId: nextEditEventId(),
241
341
  sourceMessageId: seeded.channelTs,
242
- canonicalAssistantId: "self",
243
342
  assistantId: "self",
244
343
  content: "second edit",
245
344
  });
@@ -272,7 +371,6 @@ describe("Slack edit propagation", () => {
272
371
  conversationExternalId: seeded.conversationExternalId,
273
372
  externalMessageId: nextEditEventId(),
274
373
  sourceMessageId: seeded.channelTs,
275
- canonicalAssistantId: "self",
276
374
  assistantId: "self",
277
375
  // Same text as stored -- simulates a Slack unfurl `message_changed`
278
376
  // where only attachments changed.
@@ -313,7 +411,6 @@ describe("Slack edit propagation", () => {
313
411
  conversationExternalId: seeded.conversationExternalId,
314
412
  externalMessageId: nextEditEventId(),
315
413
  sourceMessageId: seeded.channelTs,
316
- canonicalAssistantId: "self",
317
414
  assistantId: "self",
318
415
  content: "edited searchable text",
319
416
  });
@@ -341,7 +438,6 @@ describe("Slack edit propagation", () => {
341
438
  // sourceMessageId points at a ts that was never stored.
342
439
  externalMessageId: nextEditEventId(),
343
440
  sourceMessageId: "9999.0000",
344
- canonicalAssistantId: "self",
345
441
  assistantId: "self",
346
442
  content: "new text",
347
443
  });