@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62

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 (490) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -110,7 +110,7 @@ describe("memory-v3-live v2 suppression", () => {
110
110
  ];
111
111
 
112
112
  const result = await applyRuntimeInjections(runMessages, {
113
- turnContext: makeTurnContext(),
113
+ ...makeTurnContext(),
114
114
  });
115
115
 
116
116
  // Exactly one <memory> source across the WHOLE assembled context.
@@ -149,7 +149,7 @@ describe("memory-v3-live v2 suppression", () => {
149
149
  ];
150
150
 
151
151
  const result = await applyRuntimeInjections(runMessages, {
152
- turnContext: makeTurnContext(),
152
+ ...makeTurnContext(),
153
153
  });
154
154
 
155
155
  // v2's block survives — the turn still ships memory.
@@ -177,7 +177,7 @@ describe("memory-v3-live v2 suppression", () => {
177
177
  // captures the exact pre-flag assembly behavior: v2 prefix stays, v3
178
178
  // splices after it.
179
179
  const offResult = await applyRuntimeInjections(runMessages, {
180
- turnContext: makeTurnContext(),
180
+ ...makeTurnContext(),
181
181
  });
182
182
 
183
183
  // The tail keeps v2's block AND gains v3's (the historical double-injection
@@ -206,7 +206,7 @@ describe("memory-v3-live v2 suppression", () => {
206
206
  ];
207
207
 
208
208
  const result = await applyRuntimeInjections(runMessages, {
209
- turnContext: makeTurnContext(),
209
+ ...makeTurnContext(),
210
210
  });
211
211
 
212
212
  expect(result.messages).toEqual(runMessages);
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Tests for handleListMessages clientMessageId projection.
3
+ *
4
+ * Verifies that the persisted idempotency nonce is echoed back on the
5
+ * messages snapshot row so a client can correlate its optimistic row with
6
+ * the confirmed server row by identity instead of matching message text.
7
+ */
8
+
9
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
10
+
11
+ mock.module("../util/logger.js", () => ({
12
+ getLogger: () =>
13
+ new Proxy({} as Record<string, unknown>, {
14
+ get: () => () => {},
15
+ }),
16
+ }));
17
+
18
+ mock.module("../config/loader.js", () => ({
19
+ getConfig: () => ({
20
+ ui: {},
21
+ model: "test",
22
+ provider: "test",
23
+ memory: { enabled: false },
24
+ rateLimit: { maxRequestsPerMinute: 0 },
25
+ }),
26
+ }));
27
+
28
+ import { addMessage, createConversation } from "../memory/conversation-crud.js";
29
+ import { getDb } from "../memory/db-connection.js";
30
+ import { initializeDb } from "../memory/db-init.js";
31
+ import { handleListMessages } from "../runtime/routes/conversation-routes.js";
32
+
33
+ initializeDb();
34
+
35
+ function resetTables() {
36
+ const db = getDb();
37
+ db.run("DELETE FROM messages");
38
+ db.run("DELETE FROM conversations");
39
+ }
40
+
41
+ interface MessagePayload {
42
+ role: string;
43
+ clientMessageId?: string;
44
+ }
45
+
46
+ describe("handleListMessages clientMessageId", () => {
47
+ beforeEach(resetTables);
48
+
49
+ test("echoes the persisted clientMessageId onto the user row", async () => {
50
+ // GIVEN a user message persisted with a client-generated idempotency nonce
51
+ const conv = createConversation();
52
+ await addMessage(
53
+ conv.id,
54
+ "user",
55
+ JSON.stringify([{ type: "text", text: "hello" }]),
56
+ { clientMessageId: "nonce-abc", skipIndexing: true },
57
+ );
58
+
59
+ // WHEN the messages snapshot is built
60
+ const response = handleListMessages({
61
+ queryParams: { conversationId: conv.id },
62
+ });
63
+ const body = response as { messages: MessagePayload[] };
64
+
65
+ // THEN the snapshot row carries the nonce back for id-based correlation
66
+ expect(body.messages).toHaveLength(1);
67
+ expect(body.messages[0].role).toBe("user");
68
+ expect(body.messages[0].clientMessageId).toBe("nonce-abc");
69
+ });
70
+
71
+ test("omits clientMessageId when the row was persisted without one", async () => {
72
+ // GIVEN a user message persisted without a client nonce (e.g. a channel send)
73
+ const conv = createConversation();
74
+ await addMessage(
75
+ conv.id,
76
+ "user",
77
+ JSON.stringify([{ type: "text", text: "hello" }]),
78
+ { skipIndexing: true },
79
+ );
80
+
81
+ // WHEN the messages snapshot is built
82
+ const response = handleListMessages({
83
+ queryParams: { conversationId: conv.id },
84
+ });
85
+ const body = response as { messages: MessagePayload[] };
86
+
87
+ // THEN the field is absent rather than emitted as null/empty
88
+ expect(body.messages).toHaveLength(1);
89
+ expect(body.messages[0].clientMessageId).toBeUndefined();
90
+ });
91
+ });
@@ -96,6 +96,44 @@ describe("handleListMessages metadata.hidden filtering", () => {
96
96
  expect(llmRows[1].metadata).toContain('"hidden":true');
97
97
  });
98
98
 
99
+ test("UI serializer omits system rows but LLM-side getMessages includes them", async () => {
100
+ // GIVEN a conversation with a system row sandwiched between two
101
+ // renderable turns (e.g. a skill-authored context message)
102
+ const conv = createConversation();
103
+ await addMessage(
104
+ conv.id,
105
+ "user",
106
+ JSON.stringify([{ type: "text", text: "first visible" }]),
107
+ );
108
+ await addMessage(
109
+ conv.id,
110
+ "system",
111
+ JSON.stringify([{ type: "text", text: "system scaffolding" }]),
112
+ );
113
+ await addMessage(
114
+ conv.id,
115
+ "assistant",
116
+ JSON.stringify([{ type: "text", text: "second visible" }]),
117
+ );
118
+
119
+ // WHEN the UI history list is serialized
120
+ const response = handleListMessages({
121
+ queryParams: { conversationId: conv.id },
122
+ });
123
+ const body = response as { messages: MessagePayload[] };
124
+
125
+ // THEN only the user/assistant turns are returned, never the system row
126
+ expect(body.messages.map((m) => m.role)).toEqual(["user", "assistant"]);
127
+ expect(
128
+ body.messages.some((m) => plainText(m).includes("system scaffolding")),
129
+ ).toBe(false);
130
+
131
+ // AND the LLM-side loader still includes the system row for agent context
132
+ const llmRows = getMessages(conv.id);
133
+ expect(llmRows).toHaveLength(3);
134
+ expect(llmRows[1].role).toBe("system");
135
+ });
136
+
99
137
  test("messages without metadata or with hidden=false are returned", async () => {
100
138
  const conv = createConversation();
101
139
  await addMessage(
@@ -53,6 +53,7 @@ interface ClientCatalogModel {
53
53
  longContextPricingThresholdTokens?: number;
54
54
  longContextMode?: "native-model" | "provider-request-option" | "unsupported";
55
55
  supportsThinking?: boolean;
56
+ adaptiveThinkingOnly?: boolean;
56
57
  supportsCaching?: boolean;
57
58
  supportsVision?: boolean;
58
59
  supportsToolUse?: boolean;
@@ -194,6 +195,9 @@ describe("LLM catalog parity: daemon vs client", () => {
194
195
  );
195
196
  expect(clientModel.longContextMode).toBe(daemonModel.longContextMode);
196
197
  expect(clientModel.supportsThinking).toBe(daemonModel.supportsThinking);
198
+ expect(clientModel.adaptiveThinkingOnly).toBe(
199
+ daemonModel.adaptiveThinkingOnly,
200
+ );
197
201
  expect(clientModel.supportsCaching).toBe(daemonModel.supportsCaching);
198
202
  expect(clientModel.supportsVision).toBe(daemonModel.supportsVision);
199
203
  expect(clientModel.supportsToolUse).toBe(daemonModel.supportsToolUse);
@@ -1249,3 +1249,76 @@ describe("resolveDefaultProfileKey", () => {
1249
1249
  expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("balanced");
1250
1250
  });
1251
1251
  });
1252
+
1253
+ describe("resolveCallSiteConfig logitBias provenance", () => {
1254
+ const kimi = "accounts/fireworks/models/kimi-k2p6";
1255
+
1256
+ test("forwards logitBias from the active profile that opted in", () => {
1257
+ const llm = LLMSchema.parse({
1258
+ default: fullDefault,
1259
+ profiles: {
1260
+ "balanced-economy": {
1261
+ provider: "fireworks",
1262
+ model: kimi,
1263
+ logitBias: "suppress-cjk",
1264
+ },
1265
+ },
1266
+ activeProfile: "balanced-economy",
1267
+ });
1268
+ expect(resolveCallSiteConfig("mainAgent", llm).logitBias).toBe(
1269
+ "suppress-cjk",
1270
+ );
1271
+ });
1272
+
1273
+ test("a higher-precedence override profile that omits logitBias clears it", () => {
1274
+ // Active profile opts in, but a pinned (override) Kimi profile did not —
1275
+ // the override must not inherit suppress-cjk just because it resolves to
1276
+ // Fireworks.
1277
+ const llm = LLMSchema.parse({
1278
+ default: fullDefault,
1279
+ profiles: {
1280
+ "balanced-economy": {
1281
+ provider: "fireworks",
1282
+ model: kimi,
1283
+ logitBias: "suppress-cjk",
1284
+ },
1285
+ "my-kimi": { provider: "fireworks", model: kimi },
1286
+ },
1287
+ activeProfile: "balanced-economy",
1288
+ });
1289
+ const resolved = resolveCallSiteConfig("mainAgent", llm, {
1290
+ overrideProfile: "my-kimi",
1291
+ });
1292
+ expect(resolved.logitBias).toBeUndefined();
1293
+ });
1294
+
1295
+ test("does not leak the active profile's logitBias into a call site's own profile", () => {
1296
+ // For non-main call sites the call-site profile wins; since it didn't opt
1297
+ // in, the active profile's preset must not bleed through.
1298
+ const llm = LLMSchema.parse({
1299
+ default: fullDefault,
1300
+ profiles: {
1301
+ "balanced-economy": {
1302
+ provider: "fireworks",
1303
+ model: kimi,
1304
+ logitBias: "suppress-cjk",
1305
+ },
1306
+ plain: { provider: "anthropic", model: "claude-opus-4-7" },
1307
+ },
1308
+ activeProfile: "balanced-economy",
1309
+ callSites: { memoryExtraction: { profile: "plain" } },
1310
+ });
1311
+ expect(
1312
+ resolveCallSiteConfig("memoryExtraction", llm).logitBias,
1313
+ ).toBeUndefined();
1314
+ });
1315
+
1316
+ test("a logitBias on a non-profile layer (llm.default) does not apply when the winning profile omits it", () => {
1317
+ const llm = LLMSchema.parse({
1318
+ default: { ...fullDefault, logitBias: "suppress-cjk" },
1319
+ profiles: { plain: { provider: "anthropic", model: "claude-opus-4-7" } },
1320
+ activeProfile: "plain",
1321
+ });
1322
+ expect(resolveCallSiteConfig("mainAgent", llm).logitBias).toBeUndefined();
1323
+ });
1324
+ });
@@ -1,12 +1,16 @@
1
1
  /**
2
- * Tests for the default `user-prompt-submit-temp` hook (memory retrieval).
2
+ * Tests for the default `user-prompt-submit` hook (memory retrieval +
3
+ * runtime injection).
3
4
  *
4
5
  * Covers the retrieval behavior, the side effects the hook owns (injected-block
5
- * metadata, recall log, `memory_recalled` event), trust gating, error
6
- * propagation, and abort-signal forwarding. Uses `mock.module` to stub the
7
- * persistence helpers so the test doesn't touch the developer's real
8
- * `~/.vellum` or database. The memory graph handle is a hand-rolled fake
9
- * passed on the hook context — the hook only needs `prepareMemory`.
6
+ * metadata, recall log, `memory_recalled` event), trust gating, the runtime
7
+ * injection the hook applies for every actor (and the assembled-block persist),
8
+ * error propagation, and abort-signal forwarding. Uses `mock.module` to stub
9
+ * the persistence helpers, `applyRuntimeInjections`, and the conversation
10
+ * registry / trust resolver so the test doesn't touch the developer's real
11
+ * `~/.vellum`, database, or live conversation state. The memory graph handle,
12
+ * abort signal, and trust class are self-resolved by the hook from a fake
13
+ * conversation installed in the registry mock.
10
14
  */
11
15
 
12
16
  import { beforeEach, describe, expect, mock, test } from "bun:test";
@@ -23,13 +27,52 @@ mock.module("../memory/memory-recall-log-store.js", () => ({
23
27
  recordMemoryRecallLog: recordMemoryRecallLogMock,
24
28
  }));
25
29
 
30
+ // Pass-through injection stub: returns the input messages unchanged with no
31
+ // assembled blocks, so existing array-identity assertions hold. Individual
32
+ // tests override it via `mockImplementationOnce` to exercise injected blocks.
33
+ const applyRuntimeInjectionsMock = mock(async (messages: unknown) => ({
34
+ messages,
35
+ blocks: {},
36
+ }));
37
+ mock.module("../daemon/conversation-runtime-assembly.js", () => ({
38
+ applyRuntimeInjections: applyRuntimeInjectionsMock,
39
+ resolveTurnInboundActorContext: () => null,
40
+ resolveTurnModelProfileLabel: () => null,
41
+ }));
42
+
43
+ // The hook self-resolves the live conversation and its trust class; both are
44
+ // driven from these refs so each test controls what the hook sees.
45
+ let currentConversation: Conversation | undefined;
46
+ let currentTrustClass: "guardian" | "unknown" = "guardian";
47
+ const findConversationOrSubagentMock = mock(
48
+ (_conversationId?: string) => currentConversation,
49
+ );
50
+ mock.module("../daemon/conversation-registry.js", () => ({
51
+ findConversationOrSubagent: findConversationOrSubagentMock,
52
+ }));
53
+ mock.module("../daemon/trust-context.js", () => ({
54
+ resolveTrustClass: () => currentTrustClass,
55
+ }));
56
+ mock.module("../config/loader.js", () => ({
57
+ getConfig: () => ({}) as AssistantConfig,
58
+ }));
59
+
60
+ // The hook publishes `memory_recalled` (and forwards the sink into
61
+ // `prepareMemory` for `memory_status`) through the shared `broadcastMessage`
62
+ // hub. Stub it so tests can assert what the hook emits.
63
+ const broadcastMessageMock = mock((_msg: unknown) => {});
64
+ mock.module("../runtime/assistant-event-hub.js", () => ({
65
+ broadcastMessage: broadcastMessageMock,
66
+ }));
67
+
68
+ import type { UserPromptSubmitContext } from "@vellumai/plugin-api";
69
+
26
70
  import type { AssistantConfig } from "../config/schema.js";
71
+ import type { Conversation } from "../daemon/conversation.js";
27
72
  import type { ServerMessage } from "../daemon/message-protocol.js";
28
73
  import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
29
74
  import type { QdrantSparseVector } from "../memory/qdrant-client.js";
30
- import userPromptSubmitMemoryRetrieval, {
31
- type MemoryRetrievalHookContext,
32
- } from "../plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.js";
75
+ import userPromptSubmitMemoryRetrieval from "../plugins/defaults/memory-retrieval/hooks/user-prompt-submit.js";
33
76
  import type { Message } from "../providers/types.js";
34
77
 
35
78
  /** Canonical metrics payload the graph retriever attaches to a real hit. */
@@ -102,31 +145,55 @@ function makeFakeGraphMemory(overrides?: {
102
145
  }
103
146
 
104
147
  function makeHookCtx(
105
- overrides: Partial<MemoryRetrievalHookContext> = {},
106
- ): MemoryRetrievalHookContext {
107
- const { memory } = makeFakeGraphMemory();
148
+ overrides: Partial<UserPromptSubmitContext> = {},
149
+ ): UserPromptSubmitContext {
108
150
  return {
109
- graphMemory: memory,
110
- config: {} as AssistantConfig,
111
- onEvent: () => {},
112
- isTrustedActor: true,
113
151
  conversationId: "conv-test",
114
152
  userMessageId: "msg-test",
115
153
  logger: {
116
154
  warn: () => {},
117
- } as unknown as MemoryRetrievalHookContext["logger"],
118
- signal: new AbortController().signal,
155
+ } as unknown as UserPromptSubmitContext["logger"],
119
156
  latestMessages: [],
157
+ requestId: "req-test",
158
+ isNonInteractive: false,
159
+ modelProfileKey: null,
160
+ prompt: "",
161
+ originalMessages: [],
120
162
  ...overrides,
121
163
  };
122
164
  }
123
165
 
166
+ /**
167
+ * Install a fake live conversation for the hook to self-resolve by id: the
168
+ * graph handle, abort signal, and trust class all come from here rather than
169
+ * the hook context.
170
+ */
171
+ function installConversation(
172
+ graphMemory: ConversationGraphMemory,
173
+ opts?: {
174
+ trusted?: boolean;
175
+ signal?: AbortSignal;
176
+ },
177
+ ): void {
178
+ currentTrustClass = opts?.trusted === false ? "unknown" : "guardian";
179
+ currentConversation = {
180
+ graphMemory,
181
+ trustContext: undefined,
182
+ abortController: { signal: opts?.signal ?? new AbortController().signal },
183
+ } as unknown as Conversation;
184
+ }
185
+
124
186
  beforeEach(() => {
125
187
  updateMessageMetadataMock.mockReset();
126
188
  recordMemoryRecallLogMock.mockReset();
189
+ applyRuntimeInjectionsMock.mockClear();
190
+ findConversationOrSubagentMock.mockClear();
191
+ broadcastMessageMock.mockReset();
192
+ currentConversation = undefined;
193
+ currentTrustClass = "guardian";
127
194
  });
128
195
 
129
- describe("user-prompt-submit-temp hook (memory retrieval)", () => {
196
+ describe("user-prompt-submit hook (memory retrieval)", () => {
130
197
  test("adopts the injected run messages when the actor is trusted", async () => {
131
198
  const injected: Message[] = [
132
199
  { role: "user", content: [{ type: "text", text: "injected" }] },
@@ -134,7 +201,8 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
134
201
  const { memory, prepareMemoryMock } = makeFakeGraphMemory({
135
202
  messages: injected,
136
203
  });
137
- const ctx = makeHookCtx({ graphMemory: memory, isTrustedActor: true });
204
+ installConversation(memory, { trusted: true });
205
+ const ctx = makeHookCtx();
138
206
 
139
207
  await userPromptSubmitMemoryRetrieval(ctx);
140
208
 
@@ -156,7 +224,8 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
156
224
  userQueryVector: userDense,
157
225
  userQuerySparseVector: userSparse,
158
226
  });
159
- const userCtx = makeHookCtx({ graphMemory: withUserQuery.memory });
227
+ installConversation(withUserQuery.memory, { trusted: true });
228
+ const userCtx = makeHookCtx();
160
229
  await userPromptSubmitMemoryRetrieval(userCtx);
161
230
  // User-query pair wins — never crossed with the summary signal — and is
162
231
  // recorded back onto the graph handle for the PKB-reminder injector.
@@ -169,7 +238,8 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
169
238
  queryVector: summaryDense,
170
239
  sparseVector: summarySparse,
171
240
  });
172
- const summaryCtx = makeHookCtx({ graphMemory: summaryOnly.memory });
241
+ installConversation(summaryOnly.memory, { trusted: true });
242
+ const summaryCtx = makeHookCtx();
173
243
  await userPromptSubmitMemoryRetrieval(summaryCtx);
174
244
  expect(summaryOnly.recordPkbQueryVectorsMock).toHaveBeenCalledWith(
175
245
  summaryDense,
@@ -177,17 +247,59 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
177
247
  );
178
248
  });
179
249
 
250
+ test("applies runtime injection on the retrieved history and persists the assembled blocks", async () => {
251
+ const retrieved: Message[] = [
252
+ { role: "user", content: [{ type: "text", text: "retrieved" }] },
253
+ ];
254
+ const injected: Message[] = [
255
+ { role: "user", content: [{ type: "text", text: "injected" }] },
256
+ ];
257
+ const { memory } = makeFakeGraphMemory({ messages: retrieved });
258
+ applyRuntimeInjectionsMock.mockImplementationOnce(async () => ({
259
+ messages: injected,
260
+ blocks: { unifiedTurnContext: "tc-block" },
261
+ }));
262
+ installConversation(memory, { trusted: true });
263
+ const ctx = makeHookCtx({ userMessageId: "msg-77" });
264
+
265
+ await userPromptSubmitMemoryRetrieval(ctx);
266
+
267
+ // Injection runs on the retrieved history; its result becomes the working
268
+ // list the loop reads back.
269
+ expect(applyRuntimeInjectionsMock).toHaveBeenCalledTimes(1);
270
+ expect(applyRuntimeInjectionsMock.mock.calls[0]?.[0]).toBe(retrieved);
271
+ expect(ctx.latestMessages).toBe(injected);
272
+ // The assembled blocks are persisted onto the user message metadata.
273
+ expect(updateMessageMetadataMock).toHaveBeenCalledWith("msg-77", {
274
+ turnContextBlock: "tc-block",
275
+ });
276
+ });
277
+
278
+ test("applies runtime injection for untrusted actors despite skipping retrieval", async () => {
279
+ const { memory, prepareMemoryMock } = makeFakeGraphMemory();
280
+ const seeded: Message[] = [
281
+ { role: "user", content: [{ type: "text", text: "seeded" }] },
282
+ ];
283
+ installConversation(memory, { trusted: false });
284
+ const ctx = makeHookCtx({ latestMessages: seeded });
285
+
286
+ await userPromptSubmitMemoryRetrieval(ctx);
287
+
288
+ // The memory-graph step is gated on trust, but injection runs for everyone
289
+ // — on the seeded history, since no retrieval replaced it.
290
+ expect(prepareMemoryMock).not.toHaveBeenCalled();
291
+ expect(applyRuntimeInjectionsMock).toHaveBeenCalledTimes(1);
292
+ expect(applyRuntimeInjectionsMock.mock.calls[0]?.[0]).toBe(seeded);
293
+ });
294
+
180
295
  test("skips graph retrieval and side effects for untrusted actors", async () => {
181
296
  const { memory, prepareMemoryMock, recordPkbQueryVectorsMock } =
182
297
  makeFakeGraphMemory();
183
298
  const seeded: Message[] = [
184
299
  { role: "user", content: [{ type: "text", text: "seeded" }] },
185
300
  ];
186
- const ctx = makeHookCtx({
187
- graphMemory: memory,
188
- isTrustedActor: false,
189
- latestMessages: seeded,
190
- });
301
+ installConversation(memory, { trusted: false });
302
+ const ctx = makeHookCtx({ latestMessages: seeded });
191
303
 
192
304
  await userPromptSubmitMemoryRetrieval(ctx);
193
305
 
@@ -201,14 +313,12 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
201
313
  });
202
314
 
203
315
  test("persists injected block, recall log, and emits memory_recalled", async () => {
204
- const received: ServerMessage[] = [];
205
316
  const { memory } = makeFakeGraphMemory({
206
317
  injectedBlockText: "injected-block",
207
318
  metrics: makeMetrics(),
208
319
  });
320
+ installConversation(memory, { trusted: true });
209
321
  const ctx = makeHookCtx({
210
- graphMemory: memory,
211
- onEvent: (msg) => received.push(msg),
212
322
  userMessageId: "msg-42",
213
323
  conversationId: "conv-42",
214
324
  });
@@ -225,13 +335,16 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
225
335
  };
226
336
  expect(logEntry.conversationId).toBe("conv-42");
227
337
  expect(logEntry.reason).toBe("graph:none");
228
- expect(received).toHaveLength(1);
229
- expect(received[0]?.type).toBe("memory_recalled");
338
+ // The `memory_recalled` summary publishes through the shared broadcast hub.
339
+ expect(broadcastMessageMock).toHaveBeenCalledTimes(1);
340
+ const emitted = broadcastMessageMock.mock.calls[0]?.[0] as ServerMessage;
341
+ expect(emitted.type).toBe("memory_recalled");
230
342
  });
231
343
 
232
344
  test("skips metadata persist when no block text is injected", async () => {
233
345
  const { memory } = makeFakeGraphMemory({ injectedBlockText: null });
234
- const ctx = makeHookCtx({ graphMemory: memory });
346
+ installConversation(memory, { trusted: true });
347
+ const ctx = makeHookCtx();
235
348
 
236
349
  await userPromptSubmitMemoryRetrieval(ctx);
237
350
 
@@ -254,16 +367,17 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
254
367
  const graphMemory = {
255
368
  prepareMemory: failingPrepare,
256
369
  } as unknown as ConversationGraphMemory;
257
- const ctx = makeHookCtx({ graphMemory, isTrustedActor: true });
370
+ installConversation(graphMemory, { trusted: true });
371
+ const ctx = makeHookCtx();
258
372
 
259
373
  await expect(userPromptSubmitMemoryRetrieval(ctx)).rejects.toThrow(
260
374
  "retrieval failed",
261
375
  );
262
376
  });
263
377
 
264
- test("forwards the context abort signal into prepareMemory", async () => {
265
- // The hook hands its `ctx.signal` straight to `prepareMemory` so an
266
- // external cancel aborts the underlying retrieval.
378
+ test("forwards the conversation abort signal into prepareMemory", async () => {
379
+ // The hook hands the live conversation's abort signal straight to
380
+ // `prepareMemory` so an external cancel aborts the underlying retrieval.
267
381
  let capturedSignal: AbortSignal | undefined;
268
382
  const prepareMemoryMock = mock(
269
383
  async (
@@ -288,7 +402,11 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
288
402
  recordPkbQueryVectors: mock(() => {}),
289
403
  } as unknown as ConversationGraphMemory;
290
404
  const controller = new AbortController();
291
- const ctx = makeHookCtx({ graphMemory, signal: controller.signal });
405
+ installConversation(graphMemory, {
406
+ trusted: true,
407
+ signal: controller.signal,
408
+ });
409
+ const ctx = makeHookCtx();
292
410
 
293
411
  await userPromptSubmitMemoryRetrieval(ctx);
294
412