@vellumai/assistant 0.8.5 → 0.8.6

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 (544) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +1 -1
  3. package/bunfig.toml +6 -1
  4. package/docs/credential-execution-service.md +6 -6
  5. package/docs/plugins.md +4 -3
  6. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
  7. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
  8. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  9. package/openapi.yaml +1900 -166
  10. package/package.json +1 -1
  11. package/src/__tests__/actor-token-service.test.ts +3 -2
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
  13. package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
  14. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  15. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  16. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  17. package/src/__tests__/annotate-risk-options.test.ts +1 -0
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/approval-routes-http.test.ts +9 -13
  20. package/src/__tests__/assert-not-live-db.ts +79 -0
  21. package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
  22. package/src/__tests__/audit-log-rotation.test.ts +2 -2
  23. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  24. package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
  25. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  26. package/src/__tests__/btw-routes.test.ts +3 -2
  27. package/src/__tests__/call-controller.test.ts +3 -2
  28. package/src/__tests__/channel-approval-routes.test.ts +3 -2
  29. package/src/__tests__/channel-guardian.test.ts +3 -2
  30. package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
  31. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  32. package/src/__tests__/channel-retry-sweep.test.ts +320 -3
  33. package/src/__tests__/checker.test.ts +12 -12
  34. package/src/__tests__/compaction-events.test.ts +1 -0
  35. package/src/__tests__/compaction-trail-store.test.ts +264 -0
  36. package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
  37. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  38. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
  39. package/src/__tests__/computer-use-tools.test.ts +12 -14
  40. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  41. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  42. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  43. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  44. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  45. package/src/__tests__/config-schema.test.ts +10 -10
  46. package/src/__tests__/connection-model-compat.test.ts +83 -0
  47. package/src/__tests__/contacts-tools.test.ts +3 -2
  48. package/src/__tests__/context-token-estimator.test.ts +22 -0
  49. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
  50. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  52. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  53. package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
  54. package/src/__tests__/conversation-agent-loop.test.ts +488 -2
  55. package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
  56. package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
  57. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
  58. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  61. package/src/__tests__/conversation-error.test.ts +30 -0
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -8
  63. package/src/__tests__/conversation-fork-route.test.ts +3 -2
  64. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  65. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  66. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  67. package/src/__tests__/conversation-lifecycle.test.ts +1 -0
  68. package/src/__tests__/conversation-list-source.test.ts +3 -2
  69. package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
  70. package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
  71. package/src/__tests__/conversation-pairing.test.ts +53 -0
  72. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
  73. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  74. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
  75. package/src/__tests__/conversation-queue.test.ts +333 -291
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
  80. package/src/__tests__/conversation-skill-tools.test.ts +38 -142
  81. package/src/__tests__/conversation-slash-queue.test.ts +84 -32
  82. package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
  83. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
  85. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
  90. package/src/__tests__/conversation-sync-tags.test.ts +128 -12
  91. package/src/__tests__/conversation-title-service.test.ts +1 -0
  92. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
  93. package/src/__tests__/conversation-usage.test.ts +1 -0
  94. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  95. package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
  96. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
  97. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  98. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  99. package/src/__tests__/credential-execution-client.test.ts +72 -1
  100. package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
  101. package/src/__tests__/credential-health-service.test.ts +252 -3
  102. package/src/__tests__/credential-security-invariants.test.ts +5 -5
  103. package/src/__tests__/credential-vault-unit.test.ts +19 -19
  104. package/src/__tests__/credential-vault.test.ts +5 -5
  105. package/src/__tests__/cross-provider-web-search.test.ts +56 -2
  106. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  107. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  108. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  109. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  110. package/src/__tests__/db-test-helpers.ts +58 -0
  111. package/src/__tests__/disk-pressure-guard.test.ts +58 -41
  112. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  113. package/src/__tests__/disk-pressure-routes.test.ts +0 -33
  114. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  115. package/src/__tests__/dm-persistence.test.ts +26 -40
  116. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  117. package/src/__tests__/document-find-replace.test.ts +3 -2
  118. package/src/__tests__/document-tool-security.test.ts +81 -2
  119. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  120. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  121. package/src/__tests__/encrypted-store.test.ts +11 -9
  122. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  123. package/src/__tests__/filing-service.test.ts +1 -0
  124. package/src/__tests__/first-greeting.test.ts +62 -12
  125. package/src/__tests__/gateway-flag-listener.test.ts +0 -1
  126. package/src/__tests__/gemini-provider.test.ts +26 -0
  127. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  128. package/src/__tests__/guardian-outbound-http.test.ts +3 -2
  129. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  130. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
  131. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  132. package/src/__tests__/heartbeat-service.test.ts +1 -0
  133. package/src/__tests__/helpers/mock-logger.ts +26 -0
  134. package/src/__tests__/host-bash-routes.test.ts +1 -0
  135. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
  136. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  137. package/src/__tests__/host-shell-tool.test.ts +5 -4
  138. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  139. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  140. package/src/__tests__/http-user-message-parity.test.ts +29 -7
  141. package/src/__tests__/identity-intro-cache.test.ts +133 -22
  142. package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
  143. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  144. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  145. package/src/__tests__/injector-disk-pressure.test.ts +3 -17
  146. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  147. package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
  148. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  149. package/src/__tests__/llm-resolver.test.ts +331 -0
  150. package/src/__tests__/llm-schema.test.ts +1 -1
  151. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  152. package/src/__tests__/mcp-abort-signal.test.ts +14 -0
  153. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  154. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  155. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  156. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  157. package/src/__tests__/model-intents.test.ts +3 -3
  158. package/src/__tests__/native-web-search.test.ts +30 -2
  159. package/src/__tests__/notification-deep-link.test.ts +62 -0
  160. package/src/__tests__/oauth-commands-routes.test.ts +37 -0
  161. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  162. package/src/__tests__/oauth-store.test.ts +3 -2
  163. package/src/__tests__/onboarding-template-contract.test.ts +3 -2
  164. package/src/__tests__/openai-provider.test.ts +8 -9
  165. package/src/__tests__/openai-responses-provider.test.ts +70 -10
  166. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  167. package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
  168. package/src/__tests__/persistence-pipeline.test.ts +139 -1
  169. package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
  170. package/src/__tests__/plugin-bootstrap.test.ts +9 -11
  171. package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
  172. package/src/__tests__/process-message-background-slack.test.ts +21 -16
  173. package/src/__tests__/process-message-display-content.test.ts +19 -22
  174. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  175. package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
  176. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  177. package/src/__tests__/recording-handler.test.ts +1 -0
  178. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  179. package/src/__tests__/registry.test.ts +82 -76
  180. package/src/__tests__/relay-server.test.ts +10 -10
  181. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  182. package/src/__tests__/schedule-store.test.ts +16 -1
  183. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  184. package/src/__tests__/secret-ingress-http.test.ts +5 -1
  185. package/src/__tests__/secure-keys.test.ts +3 -3
  186. package/src/__tests__/send-endpoint-busy.test.ts +81 -42
  187. package/src/__tests__/server-history-render.test.ts +4 -1
  188. package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
  189. package/src/__tests__/skill-feature-flags.test.ts +14 -16
  190. package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
  191. package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
  192. package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
  193. package/src/__tests__/skill-tool-factory.test.ts +96 -95
  194. package/src/__tests__/slack-channel-config.test.ts +3 -3
  195. package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
  196. package/src/__tests__/subagent-disposal.test.ts +27 -8
  197. package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
  198. package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
  199. package/src/__tests__/subagent-manager-notify.test.ts +20 -8
  200. package/src/__tests__/subagent-notify-parent.test.ts +5 -4
  201. package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
  202. package/src/__tests__/subagent-tools.test.ts +2 -1
  203. package/src/__tests__/suggestion-routes.test.ts +1 -0
  204. package/src/__tests__/system-prompt.test.ts +38 -0
  205. package/src/__tests__/test-preload-verifier.ts +68 -0
  206. package/src/__tests__/test-preload.ts +32 -39
  207. package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
  208. package/src/__tests__/tool-executor.test.ts +55 -10
  209. package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
  210. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  211. package/src/__tests__/twilio-routes.test.ts +3 -2
  212. package/src/__tests__/validate-input.test.ts +381 -0
  213. package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
  214. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
  215. package/src/__tests__/voice-session-bridge.test.ts +37 -28
  216. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  217. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  218. package/src/acp/session-manager.ts +5 -6
  219. package/src/agent/loop.ts +80 -0
  220. package/src/api/README.md +124 -2
  221. package/src/api/constants/call-sites.ts +27 -0
  222. package/src/api/events/assistant-outbound-attachment.ts +51 -0
  223. package/src/api/events/assistant-text-delta.ts +32 -0
  224. package/src/api/events/assistant-turn-start.ts +33 -0
  225. package/src/api/events/document-comment-created.ts +48 -0
  226. package/src/api/events/document-comment-deleted.ts +24 -0
  227. package/src/api/events/document-comment-reopened.ts +25 -0
  228. package/src/api/events/document-comment-resolved.ts +27 -0
  229. package/src/api/events/generation-cancelled.ts +24 -0
  230. package/src/api/events/generation-handoff.ts +41 -0
  231. package/src/api/events/message-complete.ts +42 -0
  232. package/src/api/events/open-url.ts +30 -0
  233. package/src/{events → api/events}/relationship-state-updated.ts +3 -3
  234. package/src/api/events/tool-use-start.ts +32 -0
  235. package/src/api/index.ts +128 -3
  236. package/src/api/responses/llm-context-response.ts +39 -0
  237. package/src/api/responses/llm-request-log-entry.ts +93 -0
  238. package/src/api/responses/memory-recall-log.ts +65 -0
  239. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  240. package/src/background-wake/background-wake-routes.test.ts +687 -52
  241. package/src/background-wake/platform-client.test.ts +308 -0
  242. package/src/background-wake/platform-client.ts +167 -0
  243. package/src/background-wake/publisher.ts +91 -0
  244. package/src/background-wake/runtime-registry.ts +2 -2
  245. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  246. package/src/calls/guardian-dispatch.ts +1 -0
  247. package/src/calls/voice-session-bridge.ts +4 -4
  248. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  249. package/src/cli/commands/__tests__/notifications.test.ts +184 -40
  250. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  251. package/src/cli/commands/channels/index.ts +229 -0
  252. package/src/cli/commands/memory-v3-render.ts +147 -0
  253. package/src/cli/commands/memory-v3.ts +255 -4
  254. package/src/cli/commands/notifications.ts +365 -55
  255. package/src/cli/lib/open-browser.ts +7 -2
  256. package/src/cli/program.ts +2 -0
  257. package/src/config/assistant-feature-flags.ts +23 -42
  258. package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
  259. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  260. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  261. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  262. package/src/config/call-site-defaults.ts +1 -1
  263. package/src/config/feature-flag-cache.ts +86 -0
  264. package/src/config/feature-flag-registry.json +17 -17
  265. package/src/config/llm-context-resolution.ts +10 -1
  266. package/src/config/llm-resolver.ts +121 -15
  267. package/src/config/loader.ts +4 -5
  268. package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
  269. package/src/config/schemas/heartbeat.ts +1 -1
  270. package/src/config/schemas/llm.ts +90 -1
  271. package/src/config/schemas/memory-v2.ts +26 -0
  272. package/src/config/schemas/services.ts +6 -2
  273. package/src/config/seed-inference-profiles.ts +36 -16
  274. package/src/context/token-estimator.ts +10 -5
  275. package/src/credential-execution/executable-discovery.ts +40 -0
  276. package/src/credential-execution/process-manager.ts +6 -2
  277. package/src/credential-health/credential-health-service.ts +125 -40
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
  279. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
  280. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
  281. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  282. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  283. package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
  284. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  285. package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
  286. package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
  287. package/src/daemon/conversation-agent-loop.ts +132 -28
  288. package/src/daemon/conversation-error.ts +33 -5
  289. package/src/daemon/conversation-messaging.ts +84 -43
  290. package/src/daemon/conversation-process.ts +74 -37
  291. package/src/daemon/conversation-runtime-assembly.ts +29 -9
  292. package/src/daemon/conversation-skill-tools.ts +14 -30
  293. package/src/daemon/conversation-surfaces.ts +69 -34
  294. package/src/daemon/conversation-tool-setup.ts +33 -48
  295. package/src/daemon/conversation.ts +26 -46
  296. package/src/daemon/daemon-control.ts +1 -1
  297. package/src/daemon/daemon-skill-host.ts +9 -2
  298. package/src/daemon/disk-pressure-guard.ts +27 -29
  299. package/src/daemon/first-greeting.ts +31 -13
  300. package/src/daemon/handlers/shared.ts +6 -1
  301. package/src/daemon/lifecycle.ts +12 -12
  302. package/src/daemon/mcp-reload-service.ts +1 -1
  303. package/src/daemon/meet-manifest-loader.ts +10 -17
  304. package/src/daemon/message-types/conversations.ts +20 -22
  305. package/src/daemon/message-types/document-comments.ts +8 -44
  306. package/src/daemon/message-types/home.ts +2 -2
  307. package/src/daemon/message-types/integrations.ts +2 -7
  308. package/src/daemon/message-types/messages.ts +23 -38
  309. package/src/daemon/message-types/subagents.ts +6 -0
  310. package/src/daemon/process-message.ts +9 -9
  311. package/src/daemon/providers-setup.ts +1 -1
  312. package/src/daemon/server.ts +16 -0
  313. package/src/daemon/switch-inference-profile-tool.ts +13 -3
  314. package/src/daemon/tool-setup-types.ts +0 -6
  315. package/src/daemon/wake-target-adapter.ts +10 -0
  316. package/src/documents/document-store.ts +38 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  318. package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
  319. package/src/heartbeat/heartbeat-service.ts +63 -0
  320. package/src/home/__tests__/feed-writer.test.ts +161 -0
  321. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  322. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  323. package/src/home/feed-writer.ts +146 -7
  324. package/src/home/suggested-prompts.ts +27 -145
  325. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  326. package/src/ipc/gateway-client.test.ts +4 -1
  327. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
  328. package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
  329. package/src/ipc/skill-routes/memory.ts +4 -3
  330. package/src/ipc/skill-routes/registries.ts +28 -29
  331. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
  332. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
  333. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  334. package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
  335. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  336. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  337. package/src/memory/conversation-attention-store.ts +17 -3
  338. package/src/memory/conversation-crud.ts +352 -112
  339. package/src/memory/db-connection.ts +29 -19
  340. package/src/memory/db-init.ts +4 -0
  341. package/src/memory/db-singleton.ts +77 -0
  342. package/src/memory/delivery-channels.ts +82 -0
  343. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  344. package/src/memory/graph/retriever.test.ts +3 -3
  345. package/src/memory/job-handlers/embedding.test.ts +3 -2
  346. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  347. package/src/memory/jobs-worker.ts +12 -1
  348. package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
  349. package/src/memory/llm-request-log-source-local.ts +24 -0
  350. package/src/memory/llm-request-log-source.ts +31 -0
  351. package/src/memory/llm-request-log-store.ts +188 -3
  352. package/src/memory/memory-v2-activation-log-store.ts +95 -1
  353. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  354. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  355. package/src/memory/migrations/index.ts +2 -0
  356. package/src/memory/schema/conversations.ts +9 -1
  357. package/src/memory/schema/inference.ts +0 -1
  358. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  359. package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
  362. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
  363. package/src/memory/v2/harness/metrics.ts +5 -1
  364. package/src/memory/v2/harness/replay-input.ts +19 -3
  365. package/src/memory/v2/harness/runner.ts +6 -0
  366. package/src/memory/v2/harness/trace.ts +6 -0
  367. package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
  368. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
  369. package/src/memory/v3/__tests__/edges.test.ts +144 -1
  370. package/src/memory/v3/__tests__/filter.test.ts +48 -0
  371. package/src/memory/v3/__tests__/gate.test.ts +96 -33
  372. package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
  373. package/src/memory/v3/__tests__/loop.test.ts +250 -5
  374. package/src/memory/v3/__tests__/scouts.test.ts +49 -0
  375. package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
  376. package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
  377. package/src/memory/v3/__tests__/traversal.test.ts +39 -0
  378. package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
  379. package/src/memory/v3/__tests__/validate.test.ts +32 -0
  380. package/src/memory/v3/coretrieval-seed.ts +240 -0
  381. package/src/memory/v3/edges.ts +58 -21
  382. package/src/memory/v3/filter.ts +27 -22
  383. package/src/memory/v3/gate.ts +51 -36
  384. package/src/memory/v3/index-composition.ts +18 -5
  385. package/src/memory/v3/loop.ts +65 -17
  386. package/src/memory/v3/scouts.ts +15 -4
  387. package/src/memory/v3/shadow-diff.ts +287 -0
  388. package/src/memory/v3/shadow-middleware.ts +44 -2
  389. package/src/memory/v3/traversal.ts +6 -1
  390. package/src/memory/v3/tree-walk.ts +6 -1
  391. package/src/memory/v3/validate.ts +56 -33
  392. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  393. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  394. package/src/notifications/adapters/slack.ts +45 -11
  395. package/src/notifications/broadcaster.ts +114 -63
  396. package/src/notifications/conversation-pairing.ts +23 -3
  397. package/src/notifications/decisions-store.ts +32 -1
  398. package/src/notifications/deliveries-store.ts +45 -0
  399. package/src/notifications/edit-notification.ts +201 -0
  400. package/src/notifications/emit-signal.ts +11 -1
  401. package/src/notifications/signal.ts +10 -0
  402. package/src/notifications/types.ts +37 -0
  403. package/src/oauth/byo-connection.test.ts +67 -3
  404. package/src/oauth/byo-connection.ts +32 -5
  405. package/src/oauth/connect-orchestrator.ts +9 -0
  406. package/src/oauth/connection-resolver.test.ts +76 -0
  407. package/src/oauth/connection-resolver.ts +49 -10
  408. package/src/oauth/manual-token-connection.ts +51 -3
  409. package/src/oauth/seed-providers.ts +3 -0
  410. package/src/permissions/approval-policy.test.ts +19 -5
  411. package/src/permissions/approval-policy.ts +14 -3
  412. package/src/permissions/checker.ts +21 -8
  413. package/src/platform/client.test.ts +24 -1
  414. package/src/platform/client.ts +8 -0
  415. package/src/platform/feature-gate.ts +15 -0
  416. package/src/plugins/defaults/injectors.ts +2 -8
  417. package/src/plugins/defaults/persistence.ts +25 -6
  418. package/src/plugins/types.ts +57 -13
  419. package/src/proactive-artifact/job.test.ts +1 -0
  420. package/src/prompts/__tests__/system-prompt.test.ts +4 -4
  421. package/src/prompts/system-prompt.ts +38 -40
  422. package/src/prompts/template-detection.ts +10 -4
  423. package/src/prompts/templates/BOOTSTRAP.md +7 -11
  424. package/src/prompts/templates/IDENTITY.md +0 -2
  425. package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
  426. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  427. package/src/providers/call-site-routing.ts +33 -9
  428. package/src/providers/connection-model-compat.ts +23 -0
  429. package/src/providers/connection-resolution.ts +39 -20
  430. package/src/providers/fireworks/client.ts +1 -0
  431. package/src/providers/gemini/client.ts +24 -3
  432. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  433. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  434. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  435. package/src/providers/inference/auth.ts +0 -8
  436. package/src/providers/inference/connections.ts +3 -66
  437. package/src/providers/inference/resolve-auth.ts +2 -3
  438. package/src/providers/model-catalog.ts +35 -1
  439. package/src/providers/model-intents.ts +3 -3
  440. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  441. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
  442. package/src/providers/openai/chat-completions-provider.ts +110 -12
  443. package/src/providers/openai/codex-models.ts +2 -0
  444. package/src/providers/openai/responses-provider.ts +53 -53
  445. package/src/providers/openrouter/client.ts +13 -8
  446. package/src/providers/provider-send-message.ts +18 -9
  447. package/src/providers/registry.ts +48 -8
  448. package/src/providers/retry.ts +16 -4
  449. package/src/providers/search-provider-catalog.ts +17 -9
  450. package/src/providers/types.ts +9 -0
  451. package/src/runtime/__tests__/agent-wake.test.ts +1 -0
  452. package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
  453. package/src/runtime/access-request-helper.ts +1 -0
  454. package/src/runtime/auth/route-policy.ts +10 -0
  455. package/src/runtime/channel-readiness-service.ts +68 -0
  456. package/src/runtime/channel-reply-delivery.ts +23 -0
  457. package/src/runtime/channel-retry-sweep.ts +47 -14
  458. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  459. package/src/runtime/migrations/vbundle-builder.ts +3 -2
  460. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  461. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
  462. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  463. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  464. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  465. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
  466. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
  467. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
  468. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  469. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
  470. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  471. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  472. package/src/runtime/routes/app-management-routes.ts +111 -4
  473. package/src/runtime/routes/background-wake-routes.ts +188 -20
  474. package/src/runtime/routes/btw-routes.ts +4 -4
  475. package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
  476. package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
  477. package/src/runtime/routes/conversation-list-routes.ts +147 -0
  478. package/src/runtime/routes/conversation-management-routes.ts +39 -14
  479. package/src/runtime/routes/conversation-query-routes.ts +60 -10
  480. package/src/runtime/routes/conversation-routes.ts +186 -140
  481. package/src/runtime/routes/conversations-import-routes.ts +19 -6
  482. package/src/runtime/routes/documents-routes.ts +10 -1
  483. package/src/runtime/routes/group-routes.ts +11 -0
  484. package/src/runtime/routes/home-feed-routes.ts +129 -0
  485. package/src/runtime/routes/identity-intro-cache.ts +61 -16
  486. package/src/runtime/routes/identity-routes.ts +30 -9
  487. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
  488. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
  489. package/src/runtime/routes/index.ts +2 -0
  490. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
  491. package/src/runtime/routes/integrations/vercel.ts +15 -0
  492. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  493. package/src/runtime/routes/memory-v3-routes.ts +160 -2
  494. package/src/runtime/routes/migration-routes.ts +20 -13
  495. package/src/runtime/routes/notification-routes.ts +63 -1
  496. package/src/runtime/routes/oauth-commands-routes.ts +6 -1
  497. package/src/runtime/routes/surface-action-routes.ts +1 -38
  498. package/src/runtime/routes/surface-content-routes.ts +12 -5
  499. package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
  500. package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
  501. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
  502. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  503. package/src/runtime/sync/resource-sync-events.ts +1 -1
  504. package/src/runtime/tool-grant-request-helper.ts +1 -0
  505. package/src/schedule/schedule-store.ts +8 -1
  506. package/src/schedule/scheduler.ts +111 -15
  507. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  508. package/src/security/encrypted-store.ts +7 -16
  509. package/src/security/store-path-override.ts +61 -0
  510. package/src/signals/user-message.ts +5 -8
  511. package/src/skills/validate-input.ts +177 -0
  512. package/src/subagent/manager.ts +13 -13
  513. package/src/subagent/types.ts +6 -0
  514. package/src/tasks/tool-sanitizer.ts +2 -2
  515. package/src/tools/apps/definitions.ts +35 -21
  516. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  517. package/src/tools/computer-use/definitions.ts +268 -266
  518. package/src/tools/document/document-tool.ts +131 -8
  519. package/src/tools/execution-target.ts +2 -5
  520. package/src/tools/executor.ts +18 -55
  521. package/src/tools/host-filesystem/edit.test.ts +1 -0
  522. package/src/tools/host-filesystem/read.test.ts +1 -0
  523. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  524. package/src/tools/host-filesystem/write.test.ts +1 -0
  525. package/src/tools/mcp/mcp-tool-factory.ts +0 -2
  526. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  527. package/src/tools/network/__tests__/web-search.test.ts +211 -3
  528. package/src/tools/network/managed-search-proxy.ts +183 -0
  529. package/src/tools/network/web-search.ts +199 -44
  530. package/src/tools/policy-context.ts +3 -1
  531. package/src/tools/registry.ts +146 -103
  532. package/src/tools/schedule/create.ts +1 -1
  533. package/src/tools/skills/skill-tool-factory.ts +17 -36
  534. package/src/tools/subagent/spawn.ts +3 -0
  535. package/src/tools/tool-approval-handler.ts +10 -4
  536. package/src/tools/tool-name-aliases.ts +72 -14
  537. package/src/tools/types.ts +17 -15
  538. package/src/tools/ui-surface/definitions.ts +98 -86
  539. package/src/types/onboarding-context.ts +6 -0
  540. package/src/usage/attribution.ts +32 -1
  541. package/src/util/browser.ts +7 -2
  542. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  543. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  544. package/src/workspace/migrations/registry.ts +4 -0
@@ -31,10 +31,7 @@ mock.module("../security/secure-keys.js", () => ({
31
31
  getSecureKeyAsync: getSecureKeyAsyncMock,
32
32
  }));
33
33
 
34
- import {
35
- _setOverridesForTesting,
36
- clearFeatureFlagOverridesCache,
37
- } from "../config/assistant-feature-flags.js";
34
+ import { clearFeatureFlagOverridesCache } from "../config/assistant-feature-flags.js";
38
35
  import type { AssistantConfig } from "../config/schema.js";
39
36
  import {
40
37
  bootstrapPlugins,
@@ -54,6 +51,7 @@ import {
54
51
  PluginExecutionError,
55
52
  type PluginInitContext,
56
53
  } from "../plugins/types.js";
54
+ import { setOverridesForTesting } from "./feature-flag-test-helpers.js";
57
55
 
58
56
  // Redirect plugin storage directory creation into a per-process temp tree so
59
57
  // the test doesn't touch the developer's real ~/.vellum.
@@ -125,7 +123,7 @@ describe("plugin bootstrap", () => {
125
123
  getSecureKeyAsyncMock.mockReset();
126
124
  getSecureKeyAsyncMock.mockImplementation(async () => undefined);
127
125
  // Reset feature-flag cache so tests start from a known state. Individual
128
- // tests that exercise `requiresFlag` use `_setOverridesForTesting(...)`
126
+ // tests that exercise `requiresFlag` use `setOverridesForTesting(...)`
129
127
  // to install their own overrides.
130
128
  clearFeatureFlagOverridesCache();
131
129
  // Clean storage directory between runs so nothing leaks across cases.
@@ -335,11 +333,11 @@ describe("plugin bootstrap", () => {
335
333
  // - no shutdown hook entry is installed (nothing to tear down later).
336
334
  // Plugins without `requiresFlag` are unaffected.
337
335
  //
338
- // Uses `_setOverridesForTesting` to control the resolver deterministically
336
+ // Uses `setOverridesForTesting` to control the resolver deterministically
339
337
  // — no disk writes, no gateway IPC, no reliance on registry defaults.
340
338
 
341
339
  test("requiresFlag enabled: plugin inits normally", async () => {
342
- _setOverridesForTesting({ "plugin-gated-enabled": true });
340
+ setOverridesForTesting({ "plugin-gated-enabled": true });
343
341
 
344
342
  let initFired = false;
345
343
  const plugin = buildPlugin(
@@ -359,7 +357,7 @@ describe("plugin bootstrap", () => {
359
357
  });
360
358
 
361
359
  test("requiresFlag disabled: init does not fire and no tools/routes/skills are registered", async () => {
362
- _setOverridesForTesting({ "plugin-gated-disabled": false });
360
+ setOverridesForTesting({ "plugin-gated-disabled": false });
363
361
 
364
362
  let initFired = false;
365
363
  // Attach tool/route/skill contributions alongside init. If gating works,
@@ -440,7 +438,7 @@ describe("plugin bootstrap", () => {
440
438
  test("requiresFlag: one disabled flag out of several skips the plugin", async () => {
441
439
  // When ANY listed flag is disabled, the plugin is skipped wholesale —
442
440
  // this prevents sneaky partial activation on AND semantics.
443
- _setOverridesForTesting({
441
+ setOverridesForTesting({
444
442
  "plugin-multi-a": true,
445
443
  "plugin-multi-b": false,
446
444
  });
@@ -469,7 +467,7 @@ describe("plugin bootstrap", () => {
469
467
  // injectors still ran on every pipeline invocation and system-prompt
470
468
  // assembly even though `init()` had never fired to set up the state they
471
469
  // depended on.
472
- _setOverridesForTesting({ "plugin-middleware-disabled": false });
470
+ setOverridesForTesting({ "plugin-middleware-disabled": false });
473
471
 
474
472
  const gatedMiddleware: PipelineMiddlewareMap["llmCall"] = async (
475
473
  args,
@@ -506,7 +504,7 @@ describe("plugin bootstrap", () => {
506
504
  });
507
505
 
508
506
  test("requiresFlag disabled: no shutdown hook entry installed for the skipped plugin", async () => {
509
- _setOverridesForTesting({ "plugin-shutdown-flag": false });
507
+ setOverridesForTesting({ "plugin-shutdown-flag": false });
510
508
 
511
509
  let shutdownFired = false;
512
510
  const plugin = buildPlugin(
@@ -6,9 +6,11 @@
6
6
  *
7
7
  * - Registering a plugin with `tools: Tool[]`, running `bootstrapPlugins`,
8
8
  * and observing the contributed tool via `getAllTools()` / `getTool()`.
9
- * - Tool ownership metadata (`origin: "plugin"`, `ownerPluginId: <plugin>`)
10
- * stamped authoritatively by `registerPluginTools` regardless of what the
11
- * plugin author set on the incoming object.
9
+ * - Tool ownership (`owner: { kind: "plugin", id: <plugin> }`) recorded
10
+ * authoritatively by `registerPluginTools` into the registry's
11
+ * `ownersByName` map (queried via `getToolOwner(name)`), regardless of
12
+ * what the plugin author set on the incoming object. The `Tool` itself
13
+ * carries no ownership field — the bootstrap is the only writer.
12
14
  * - Shutdown hook unregistering the contributed tools so the registry is
13
15
  * clean again after teardown.
14
16
  * - Direct `registerPluginTools` / `unregisterPluginTools` semantics,
@@ -55,6 +57,7 @@ import {
55
57
  getAllTools,
56
58
  getPluginRefCount,
57
59
  getTool,
60
+ getToolOwner,
58
61
  registerPluginTools,
59
62
  unregisterPluginTools,
60
63
  } from "../tools/registry.js";
@@ -164,13 +167,17 @@ describe("plugin tool contributions", () => {
164
167
 
165
168
  const retrieved = getTool("plugin-contrib-tool");
166
169
  expect(retrieved).toBeDefined();
167
- // Ownership metadata must be stamped authoritatively by the bootstrap
168
- // the registry uses it to drive ref-counting and conflict detection when
169
- // the plugin shuts down or is hot-reloaded. Plugin tools live in their
170
- // own `origin: "plugin"` namespace, disjoint from real skills, so a
171
- // plugin name that happens to match a skill id cannot collide.
172
- expect(retrieved?.origin).toBe("plugin");
173
- expect(retrieved?.ownerPluginId).toBe("alpha-contributor");
170
+ // Ownership is recorded authoritatively by the bootstrap into the
171
+ // registry's `ownersByName` map (keyed by tool name, accessed via
172
+ // `getToolOwner(name)`) — the registry uses it to drive ref-counting
173
+ // and conflict detection when the plugin shuts down or is hot-reloaded.
174
+ // Plugin tools live in their own namespace, disjoint from real skills,
175
+ // so a plugin name that happens to match a skill id cannot collide.
176
+ // Ownership is not stamped on the `Tool` object itself.
177
+ expect(getToolOwner("plugin-contrib-tool")).toEqual({
178
+ kind: "plugin",
179
+ id: "alpha-contributor",
180
+ });
174
181
 
175
182
  // The tool surfaces in the global `getAllTools()` snapshot, which is
176
183
  // what downstream consumers (tool-manifest, session projection) read.
@@ -248,22 +255,23 @@ describe("registerPluginTools / unregisterPluginTools helpers", () => {
248
255
  __resetRegistryForTesting();
249
256
  });
250
257
 
251
- test("registerPluginTools stamps category, origin, and ownerPluginId from the plugin name", () => {
252
- // Even if the plugin author hands in a tool with no category or ownership
253
- // metadata, the helper fills it in so the tool can be registered and
254
- // unregistered consistently.
258
+ test("registerPluginTools stamps category and records ownership in the registry", () => {
259
+ // Even if the plugin author hands in a tool with no category, the
260
+ // helper fills it in and records ownership in the registry's
261
+ // `ownersByName` map — the tool itself never carries an `owner` field,
262
+ // so plugin authors can't spoof ownership by forging one.
255
263
  const accepted = registerPluginTools("my-plugin", [
256
264
  makeFakeTool("pt_stamped"),
257
265
  ]);
258
266
  expect(accepted).toHaveLength(1);
259
267
  expect(accepted[0]?.category).toBe("plugin");
260
- expect(accepted[0]?.origin).toBe("plugin");
261
- expect(accepted[0]?.ownerPluginId).toBe("my-plugin");
268
+ expect(getToolOwner("pt_stamped")).toEqual({
269
+ kind: "plugin",
270
+ id: "my-plugin",
271
+ });
262
272
 
263
273
  const retrieved = getTool("pt_stamped");
264
274
  expect(retrieved?.category).toBe("plugin");
265
- expect(retrieved?.origin).toBe("plugin");
266
- expect(retrieved?.ownerPluginId).toBe("my-plugin");
267
275
  });
268
276
 
269
277
  test("registerPluginTools exposes provider-safe aliases for unsafe plugin tool names", async () => {
@@ -313,33 +321,28 @@ describe("registerPluginTools / unregisterPluginTools helpers", () => {
313
321
  expect(getTool(paddedAlias!)).toBeDefined();
314
322
  });
315
323
 
316
- test("registerPluginTools overwrites any pre-existing ownership metadata", () => {
324
+ test("registerPluginTools ignores forged ownership fields on the incoming tool", () => {
317
325
  // A plugin author could (maliciously or mistakenly) hand in a tool
318
- // pre-tagged with another skill's or plugin's ID. The helper must
319
- // overwrite it so the bootstrap is always the source of truth for
320
- // ownership and it must clear cross-origin fields (ownerSkillId /
321
- // ownerMcpServerId / ownerSkillBundled / ownerSkillVersionHash) so the
322
- // stamped tool cannot leak across namespaces or spoof bundled-skill
323
- // auto-allow.
326
+ // pre-tagged with another skill's or plugin's ID. The `Tool` type now
327
+ // carries no ownership field at all, so any such forgery is purely
328
+ // inert extra data the registry only populates `ownersByName` from
329
+ // the first argument to `register*Tools`, which is the single source
330
+ // of truth for ownership and cannot be spoofed by forging fields on
331
+ // the manifest.
324
332
  //
325
- // The narrow `ToolDefinition` shape doesn't expose these ownership
326
- // fields, so the cast through `unknown` simulates a hostile or
327
- // transpiled artifact that arrives with spoofed fields baked in —
328
- // the bootstrap-side defense is the second layer that must hold.
333
+ // Cast through `unknown` to simulate a hostile or transpiled artifact
334
+ // arriving with extra fields baked in.
329
335
  const spoofed = {
330
336
  ...makeFakeTool("pt_spoof"),
331
337
  origin: "skill",
332
- ownerSkillId: "some-other-skill",
333
- ownerSkillBundled: true,
334
- ownerSkillVersionHash: "deadbeef",
338
+ owner: { kind: "skill", id: "some-other-skill" },
335
339
  } as unknown as LoadedTool;
336
340
  registerPluginTools("my-plugin", [spoofed]);
337
- const retrieved = getTool("pt_spoof");
338
- expect(retrieved?.origin).toBe("plugin");
339
- expect(retrieved?.ownerPluginId).toBe("my-plugin");
340
- expect(retrieved?.ownerSkillId).toBeUndefined();
341
- expect(retrieved?.ownerSkillBundled).toBeUndefined();
342
- expect(retrieved?.ownerSkillVersionHash).toBeUndefined();
341
+ expect(getTool("pt_spoof")).toBeDefined();
342
+ expect(getToolOwner("pt_spoof")).toEqual({
343
+ kind: "plugin",
344
+ id: "my-plugin",
345
+ });
343
346
  });
344
347
 
345
348
  test("unregisterPluginTools removes the plugin's tools", () => {
@@ -24,6 +24,7 @@ mock.module("../memory/conversation-crud.js", () => ({
24
24
  provenanceFromTrustContext: () => ({}),
25
25
  setConversationOriginChannelIfUnset: () => {},
26
26
  setConversationOriginInterfaceIfUnset: () => {},
27
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
27
28
  }));
28
29
 
29
30
  mock.module("../memory/conversation-disk-view.js", () => ({
@@ -84,12 +85,14 @@ type Deferred<T> = {
84
85
  };
85
86
  type PersistUserMessageMock = ReturnType<
86
87
  typeof mock<
87
- (
88
- content: string,
89
- attachments: unknown[],
90
- requestId?: string,
91
- metadata?: Record<string, unknown>,
92
- ) => Promise<string>
88
+ (options: {
89
+ content: string;
90
+ attachments?: unknown[];
91
+ requestId?: string;
92
+ metadata?: Record<string, unknown>;
93
+ displayContent?: string;
94
+ clientMessageId?: string;
95
+ }) => Promise<{ id: string; deduplicated: boolean }>
93
96
  >
94
97
  >;
95
98
  type RunAgentLoopMock = ReturnType<
@@ -209,12 +212,14 @@ function makeConversation(): TestConversation {
209
212
  estimatedCost: 0,
210
213
  },
211
214
  persistUserMessage: mock(
212
- async (
213
- _content: string,
214
- _attachments: unknown[],
215
- _requestId?: string,
216
- _metadata?: Record<string, unknown>,
217
- ) => "persisted-user-message-id",
215
+ async (_options: {
216
+ content: string;
217
+ attachments?: unknown[];
218
+ requestId?: string;
219
+ metadata?: Record<string, unknown>;
220
+ displayContent?: string;
221
+ clientMessageId?: string;
222
+ }) => ({ id: "persisted-user-message-id", deduplicated: false }),
218
223
  ),
219
224
  runAgentLoop: mock(async (..._args: unknown[]) => {
220
225
  await loopDeferred.promise;
@@ -259,9 +264,9 @@ describe("processMessageInBackground Slack option propagation", () => {
259
264
 
260
265
  expect(result).toEqual({ messageId: "persisted-user-message-id" });
261
266
  expect(activeConversation.persistUserMessage).toHaveBeenCalledTimes(1);
262
- expect(activeConversation.persistUserMessage.mock.calls[0][3]).toEqual({
263
- slackInbound,
264
- });
267
+ expect(
268
+ activeConversation.persistUserMessage.mock.calls[0][0].metadata,
269
+ ).toEqual({ slackInbound });
265
270
  expect(activeConversation.runAgentLoop).toHaveBeenCalledTimes(1);
266
271
 
267
272
  activeConversation.__loopDeferred.resolve();
@@ -324,7 +329,7 @@ describe("processMessageInBackground Slack option propagation", () => {
324
329
 
325
330
  expect(activeConversation.persistUserMessage).toHaveBeenCalledTimes(1);
326
331
  expect(
327
- activeConversation.persistUserMessage.mock.calls[0][3],
332
+ activeConversation.persistUserMessage.mock.calls[0][0].metadata,
328
333
  ).toBeUndefined();
329
334
  expect(activeConversation.runAgentLoop.mock.calls[0][3]).toEqual({
330
335
  isInteractive: false,
@@ -50,6 +50,7 @@ mock.module("../memory/conversation-crud.js", () => ({
50
50
  provenanceFromTrustContext: () => ({}),
51
51
  setConversationOriginChannelIfUnset: () => {},
52
52
  setConversationOriginInterfaceIfUnset: () => {},
53
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
53
54
  }));
54
55
 
55
56
  mock.module("../memory/conversation-disk-view.js", () => ({
@@ -181,21 +182,18 @@ function makeTestConversation() {
181
182
  getTurnChannelContext: () => turnChannelContext,
182
183
  getTurnInterfaceContext: () => turnInterfaceContext,
183
184
  getMessages: () => messages,
184
- persistUserMessage: async (
185
- content: string,
186
- attachments: UserMessageAttachment[],
187
- requestId?: string,
188
- metadata?: Record<string, unknown>,
189
- displayContent?: string,
190
- ) =>
191
- persistQueuedMessageBody(
192
- messagingCtx,
193
- content,
194
- attachments,
195
- requestId ?? "req-display-content",
196
- metadata,
197
- displayContent,
198
- ),
185
+ persistUserMessage: async (options: {
186
+ content: string;
187
+ attachments?: UserMessageAttachment[];
188
+ requestId?: string;
189
+ metadata?: Record<string, unknown>;
190
+ displayContent?: string;
191
+ clientMessageId?: string;
192
+ }) =>
193
+ persistQueuedMessageBody(messagingCtx, {
194
+ ...options,
195
+ requestId: options.requestId ?? "req-display-content",
196
+ }),
199
197
  runAgentLoop,
200
198
  updateClient: () => {},
201
199
  getCurrentSender: () => undefined,
@@ -340,9 +338,9 @@ describe("processMessage displayContent", () => {
340
338
  const modelContent =
341
339
  '<external_content source="slack">\n\n</external_content>';
342
340
 
343
- await conversation.persistUserMessage(
344
- modelContent,
345
- [
341
+ await conversation.persistUserMessage({
342
+ content: modelContent,
343
+ attachments: [
346
344
  {
347
345
  id: "att-1",
348
346
  filename: "attachment.pdf",
@@ -350,10 +348,9 @@ describe("processMessage displayContent", () => {
350
348
  data: Buffer.from("pdf bytes").toString("base64"),
351
349
  },
352
350
  ],
353
- "req-display-content",
354
- undefined,
355
- "",
356
- );
351
+ requestId: "req-display-content",
352
+ displayContent: "",
353
+ });
357
354
 
358
355
  expect(addMessageCalls).toHaveLength(1);
359
356
  const persistedBlocks = JSON.parse(addMessageCalls[0]!.content);
@@ -1,16 +1,16 @@
1
1
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
2
 
3
- import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
4
3
  import type { AssistantConfig } from "../config/schema.js";
5
4
  import { PROVIDER_CATALOG } from "../providers/model-catalog.js";
6
5
  import { getVisibleProviderCatalog } from "../providers/provider-catalog-visibility.js";
6
+ import { setOverridesForTesting } from "./feature-flag-test-helpers.js";
7
7
 
8
8
  beforeEach(() => {
9
- _setOverridesForTesting({});
9
+ setOverridesForTesting({});
10
10
  });
11
11
 
12
12
  afterEach(() => {
13
- _setOverridesForTesting({});
13
+ setOverridesForTesting({});
14
14
  });
15
15
 
16
16
  /** Minimal AssistantConfig stub for feature-flag resolution. */
@@ -20,7 +20,7 @@ function makeConfig(): AssistantConfig {
20
20
 
21
21
  describe("getVisibleProviderCatalog", () => {
22
22
  test("hides openai-compatible endpoints by default", () => {
23
- _setOverridesForTesting({});
23
+ setOverridesForTesting({});
24
24
 
25
25
  const visible = getVisibleProviderCatalog(makeConfig());
26
26
 
@@ -28,7 +28,7 @@ describe("getVisibleProviderCatalog", () => {
28
28
  });
29
29
 
30
30
  test("shows openai-compatible endpoints when its flag is enabled", () => {
31
- _setOverridesForTesting({ "openai-compatible-endpoints": true });
31
+ setOverridesForTesting({ "openai-compatible-endpoints": true });
32
32
 
33
33
  const visible = getVisibleProviderCatalog(makeConfig());
34
34
 
@@ -43,7 +43,7 @@ describe("getVisibleProviderCatalog", () => {
43
43
  if (model.featureFlag) allFlags[model.featureFlag] = true;
44
44
  }
45
45
  }
46
- _setOverridesForTesting(allFlags);
46
+ setOverridesForTesting(allFlags);
47
47
 
48
48
  const visible = getVisibleProviderCatalog(makeConfig());
49
49
  expect(visible.length).toBe(PROVIDER_CATALOG.length);
@@ -58,7 +58,7 @@ describe("getVisibleProviderCatalog", () => {
58
58
  if (model.featureFlag) allFlags[model.featureFlag] = true;
59
59
  }
60
60
  }
61
- _setOverridesForTesting({ ...allFlags, "test-provider-flag": false });
61
+ setOverridesForTesting({ ...allFlags, "test-provider-flag": false });
62
62
 
63
63
  const original = [...PROVIDER_CATALOG];
64
64
  PROVIDER_CATALOG.push({
@@ -87,7 +87,7 @@ describe("getVisibleProviderCatalog", () => {
87
87
  });
88
88
 
89
89
  test("hides a model whose featureFlag is disabled but keeps the provider", () => {
90
- _setOverridesForTesting({ "test-model-flag": false });
90
+ setOverridesForTesting({ "test-model-flag": false });
91
91
 
92
92
  const original = [...PROVIDER_CATALOG];
93
93
  PROVIDER_CATALOG.push({
@@ -121,7 +121,7 @@ describe("getVisibleProviderCatalog", () => {
121
121
  });
122
122
 
123
123
  test("hides a provider entirely when all its models are flagged off", () => {
124
- _setOverridesForTesting({
124
+ setOverridesForTesting({
125
125
  "flag-a": false,
126
126
  "flag-b": false,
127
127
  });