@vellumai/assistant 0.8.10 → 0.8.11-staging.1

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 (400) hide show
  1. package/bun.lock +62 -1
  2. package/docs/workspace-tools.md +196 -0
  3. package/examples/plugins/echo/README.md +3 -3
  4. package/knip.json +1 -0
  5. package/openapi.yaml +460 -128
  6. package/package.json +2 -1
  7. package/scripts/build-plugin-api.ts +299 -0
  8. package/src/__tests__/agent-loop-callsite-precedence.test.ts +7 -0
  9. package/src/__tests__/agent-loop-compaction-events.test.ts +197 -0
  10. package/src/__tests__/agent-loop-exit-reason.test.ts +93 -96
  11. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +2 -0
  12. package/src/__tests__/agent-loop-output-hooks.test.ts +274 -1
  13. package/src/__tests__/agent-loop-override-profile.test.ts +3 -0
  14. package/src/__tests__/agent-loop-provider-error-recording.test.ts +4 -0
  15. package/src/__tests__/agent-loop-thinking.test.ts +4 -0
  16. package/src/__tests__/agent-loop.test.ts +578 -5
  17. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -1
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  20. package/src/__tests__/btw-routes.test.ts +0 -1
  21. package/src/__tests__/build-persisted-content.test.ts +75 -1
  22. package/src/__tests__/catalog-install-normalize.test.ts +141 -0
  23. package/src/__tests__/ces-startup-timeout.test.ts +60 -0
  24. package/src/__tests__/compaction-events.test.ts +1 -0
  25. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  26. package/src/__tests__/context-overflow-reducer.test.ts +264 -124
  27. package/src/__tests__/context-window-manager-overflow-rung.test.ts +351 -0
  28. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  29. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -5
  30. package/src/__tests__/conversation-agent-loop-overflow.test.ts +284 -455
  31. package/src/__tests__/conversation-agent-loop.test.ts +131 -551
  32. package/src/__tests__/conversation-app-control-instantiation.test.ts +13 -0
  33. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  34. package/src/__tests__/conversation-fork-crud.test.ts +259 -0
  35. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  36. package/src/__tests__/conversation-lifecycle.test.ts +257 -1
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +38 -377
  39. package/src/__tests__/conversation-queue.test.ts +1 -39
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +119 -8
  41. package/src/__tests__/conversation-skill-tools.test.ts +491 -5
  42. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  43. package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
  44. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  45. package/src/__tests__/conversation-store.test.ts +74 -0
  46. package/src/__tests__/conversation-surfaces-app-control.test.ts +4 -1
  47. package/src/__tests__/conversation-tool-setup-attribution.test.ts +323 -0
  48. package/src/__tests__/conversation-tool-setup-tools-disabled.test.ts +34 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -0
  52. package/src/__tests__/corrected-target.test.ts +93 -0
  53. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -5
  54. package/src/__tests__/credential-execution-tools.test.ts +23 -11
  55. package/src/__tests__/credential-security-invariants.test.ts +6 -1
  56. package/src/__tests__/db-schedule-syntax-migration.test.ts +80 -0
  57. package/src/__tests__/device-id.test.ts +70 -1
  58. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  59. package/src/__tests__/empty-response-hook.test.ts +242 -66
  60. package/src/__tests__/external-plugin-loader.test.ts +0 -31
  61. package/src/__tests__/get-skill-detail-audit.test.ts +43 -1
  62. package/src/__tests__/guardian-routing-invariants.test.ts +91 -0
  63. package/src/__tests__/history-repair-hook.test.ts +228 -3
  64. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +254 -9
  66. package/src/__tests__/identity-routes.test.ts +1 -0
  67. package/src/__tests__/image-recovery-hook.test.ts +387 -0
  68. package/src/__tests__/injector-chain.test.ts +5 -4
  69. package/src/__tests__/injector-v3-suppression.test.ts +373 -47
  70. package/src/__tests__/intent-routing.test.ts +7 -0
  71. package/src/__tests__/memory-retrieval-hook.test.ts +117 -15
  72. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  73. package/src/__tests__/oauth-store.test.ts +0 -85
  74. package/src/__tests__/{context-overflow-policy.test.ts → overflow-policy.test.ts} +1 -1
  75. package/src/__tests__/parallel-tool.benchmark.test.ts +4 -0
  76. package/src/__tests__/persist-unsendable-image-downscale.test.ts +29 -9
  77. package/src/__tests__/persist-unsendable-image.test.ts +4 -4
  78. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  79. package/src/__tests__/plugin-bootstrap.test.ts +82 -73
  80. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  81. package/src/__tests__/plugin-types.test.ts +0 -8
  82. package/src/__tests__/provider-catalog-visibility.test.ts +1 -9
  83. package/src/__tests__/prune-old-conversations-job.test.ts +99 -0
  84. package/src/__tests__/registry.test.ts +240 -1
  85. package/src/__tests__/require-fresh-approval.test.ts +3 -0
  86. package/src/__tests__/schedule-routes.test.ts +116 -1
  87. package/src/__tests__/schedule-store.test.ts +28 -0
  88. package/src/__tests__/schedule-tools.test.ts +94 -1
  89. package/src/__tests__/server-history-render.test.ts +39 -0
  90. package/src/__tests__/skill-projection-feature-flag.test.ts +13 -0
  91. package/src/__tests__/skill-projection.benchmark.test.ts +25 -7
  92. package/src/__tests__/skills.test.ts +202 -0
  93. package/src/__tests__/slim-skill-category.test.ts +195 -0
  94. package/src/__tests__/strip-memory-injections.test.ts +33 -39
  95. package/src/__tests__/test-support/tool-invocation-seed.ts +79 -0
  96. package/src/__tests__/title-generate-hook.test.ts +9 -7
  97. package/src/__tests__/tool-audit-listener.test.ts +264 -1
  98. package/src/__tests__/tool-error-hook.test.ts +4 -3
  99. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
  100. package/src/__tests__/tool-executor-lifecycle-events.test.ts +273 -0
  101. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
  102. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  103. package/src/__tests__/tools-get-route.test.ts +202 -0
  104. package/src/__tests__/workspace-tool-loader.test.ts +319 -0
  105. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  106. package/src/agent/loop.ts +569 -319
  107. package/src/api/events/tool-result.ts +9 -0
  108. package/src/api/events/tool-use-start.ts +7 -0
  109. package/src/api/index.ts +10 -0
  110. package/src/api/responses/conversation-message.ts +135 -27
  111. package/src/api/responses/memory-v3-selection-log.ts +4 -4
  112. package/src/approvals/guardian-request-resolvers.ts +26 -0
  113. package/src/browser-session/backends/host-bridge.ts +29 -0
  114. package/src/browser-session/index.ts +1 -0
  115. package/src/browser-session/types.ts +5 -1
  116. package/src/cli/commands/__tests__/schedules.test.ts +62 -4
  117. package/src/cli/commands/__tests__/skills.test.ts +53 -0
  118. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  119. package/src/cli/commands/inference-providers.ts +0 -8
  120. package/src/cli/commands/plugins.ts +2 -2
  121. package/src/cli/commands/schedules.ts +27 -4
  122. package/src/cli/commands/skills.ts +187 -146
  123. package/src/cli/commands/tools.ts +106 -0
  124. package/src/cli/lib/__tests__/install-from-github.test.ts +256 -328
  125. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +6 -2
  126. package/src/cli/lib/__tests__/plugin-details.test.ts +10 -16
  127. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +2 -2
  128. package/src/cli/lib/__tests__/search-plugins.test.ts +145 -240
  129. package/src/cli/lib/install-from-github.ts +187 -117
  130. package/src/cli/lib/plugin-catalog-cache.ts +9 -9
  131. package/src/cli/lib/plugin-details.ts +38 -68
  132. package/src/cli/lib/plugin-marketplace.ts +42 -14
  133. package/src/cli/lib/search-plugins.ts +29 -129
  134. package/src/cli/program.ts +2 -0
  135. package/src/config/bundled-skills/acp/SKILL.md +1 -0
  136. package/src/config/bundled-skills/app-builder/SKILL.md +1 -0
  137. package/src/config/bundled-skills/app-control/SKILL.md +1 -0
  138. package/src/config/bundled-skills/computer-use/SKILL.md +1 -0
  139. package/src/config/bundled-skills/contacts/SKILL.md +1 -0
  140. package/src/config/bundled-skills/document-editor/SKILL.md +1 -0
  141. package/src/config/bundled-skills/followups/SKILL.md +1 -0
  142. package/src/config/bundled-skills/image-studio/SKILL.md +1 -0
  143. package/src/config/bundled-skills/media-processing/SKILL.md +1 -0
  144. package/src/config/bundled-skills/messaging/SKILL.md +1 -0
  145. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -0
  146. package/src/config/bundled-skills/playbooks/SKILL.md +1 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +1 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +11 -3
  149. package/src/config/bundled-skills/sequences/SKILL.md +1 -0
  150. package/src/config/bundled-skills/settings/SKILL.md +1 -0
  151. package/src/config/bundled-skills/skill-management/SKILL.md +101 -1
  152. package/src/config/bundled-skills/subagent/SKILL.md +1 -0
  153. package/src/config/bundled-skills/transcribe/SKILL.md +1 -0
  154. package/src/config/env-registry.ts +23 -0
  155. package/src/config/feature-flag-registry.json +17 -81
  156. package/src/config/loader.ts +5 -22
  157. package/src/config/schema.ts +2 -0
  158. package/src/config/schemas/__tests__/compaction-logs.test.ts +56 -0
  159. package/src/config/schemas/__tests__/memory-v2.test.ts +0 -1
  160. package/src/config/schemas/__tests__/memory-v3.test.ts +61 -1
  161. package/src/config/schemas/compaction-logs.ts +79 -0
  162. package/src/config/schemas/memory-v2.ts +0 -8
  163. package/src/config/schemas/memory-v3.ts +104 -33
  164. package/src/config/seed-inference-profiles.ts +1 -1
  165. package/src/config/skills.ts +117 -47
  166. package/src/context/compactor.ts +11 -0
  167. package/src/context/strip-injections.ts +38 -4
  168. package/src/credential-execution/feature-gates.ts +0 -21
  169. package/src/credential-execution/startup-timeout.ts +32 -4
  170. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +18 -0
  171. package/src/daemon/conversation-agent-loop-handlers.ts +140 -91
  172. package/src/daemon/conversation-agent-loop.ts +123 -658
  173. package/src/daemon/conversation-error.ts +6 -33
  174. package/src/daemon/conversation-lifecycle.ts +1 -1
  175. package/src/daemon/conversation-runtime-assembly.ts +183 -22
  176. package/src/daemon/conversation-skill-tools.ts +137 -8
  177. package/src/daemon/conversation-slash.ts +0 -14
  178. package/src/daemon/conversation-store.ts +2 -19
  179. package/src/daemon/conversation-tool-setup.ts +87 -1
  180. package/src/daemon/conversation.ts +119 -50
  181. package/src/daemon/external-plugins-bootstrap.ts +36 -95
  182. package/src/daemon/handlers/config-channels.ts +11 -2
  183. package/src/daemon/handlers/shared.ts +9 -1
  184. package/src/daemon/handlers/skills.ts +10 -4
  185. package/src/daemon/host-app-control-proxy.ts +72 -57
  186. package/src/daemon/host-browser-proxy.ts +117 -22
  187. package/src/daemon/lifecycle.ts +34 -5
  188. package/src/daemon/message-protocol.ts +0 -7
  189. package/src/daemon/message-types/schedules.ts +1 -0
  190. package/src/daemon/message-types/skills.ts +17 -0
  191. package/src/daemon/providers-setup.ts +3 -0
  192. package/src/daemon/server.ts +3 -3
  193. package/src/daemon/tool-setup-types.ts +9 -3
  194. package/src/daemon/trust-context.ts +23 -0
  195. package/src/daemon/workspace-tools-watcher.ts +324 -0
  196. package/src/events/tool-audit-listener.ts +78 -16
  197. package/src/events/tool-metrics-listener.ts +2 -5
  198. package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +227 -0
  199. package/src/memory/__tests__/conversation-queries.test.ts +176 -0
  200. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +20 -32
  201. package/src/memory/compaction-log-writer-clickhouse.ts +418 -0
  202. package/src/memory/conversation-crud.ts +134 -3
  203. package/src/memory/conversation-queries.ts +64 -7
  204. package/src/memory/db-init.ts +14 -0
  205. package/src/memory/embedding-backend.test.ts +130 -1
  206. package/src/memory/embedding-backend.ts +79 -106
  207. package/src/memory/embedding-gemini.ts +5 -0
  208. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +12 -0
  209. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +19 -0
  210. package/src/memory/graph/conversation-graph-memory.ts +36 -25
  211. package/src/memory/graph/tool-handlers.ts +3 -0
  212. package/src/memory/job-handlers/cleanup.ts +3 -1
  213. package/src/memory/jobs-store.ts +0 -28
  214. package/src/memory/jobs-worker.ts +10 -22
  215. package/src/memory/memory-marker.ts +29 -0
  216. package/src/memory/memory-retrospective-startup-cleanup.ts +1 -1
  217. package/src/memory/migrations/268-add-memory-v3-selections.ts +6 -0
  218. package/src/memory/migrations/270-schedule-description.ts +36 -0
  219. package/src/memory/migrations/275-tool-invocations-add-skill-id.test.ts +81 -0
  220. package/src/memory/migrations/275-tool-invocations-add-skill-id.ts +20 -0
  221. package/src/memory/migrations/276-tool-invocations-created-at-id-index.test.ts +68 -0
  222. package/src/memory/migrations/276-tool-invocations-created-at-id-index.ts +20 -0
  223. package/src/memory/migrations/277-add-memory-v3-ever-injected.ts +29 -0
  224. package/src/memory/migrations/278-tool-invocations-telemetry-columns.test.ts +96 -0
  225. package/src/memory/migrations/278-tool-invocations-telemetry-columns.ts +39 -0
  226. package/src/memory/migrations/279-create-skill-loaded-events.test.ts +84 -0
  227. package/src/memory/migrations/279-create-skill-loaded-events.ts +26 -0
  228. package/src/memory/migrations/280-conversations-surfaced-at.test.ts +88 -0
  229. package/src/memory/migrations/280-conversations-surfaced-at.ts +24 -0
  230. package/src/memory/migrations/index.ts +10 -0
  231. package/src/memory/migrations/registry.ts +8 -0
  232. package/src/memory/schema/conversations.ts +16 -0
  233. package/src/memory/schema/infrastructure.ts +26 -0
  234. package/src/memory/skill-loaded-events-store.test.ts +160 -0
  235. package/src/memory/skill-loaded-events-store.ts +95 -0
  236. package/src/memory/tool-executed-events-store.test.ts +219 -0
  237. package/src/memory/tool-executed-events-store.ts +102 -0
  238. package/src/memory/tool-usage-store.ts +15 -3
  239. package/src/memory/v2/__tests__/consolidation-job.test.ts +117 -12
  240. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +189 -0
  241. package/src/memory/v2/__tests__/injected-block-slugs.test.ts +90 -0
  242. package/src/memory/v2/__tests__/page-store.test.ts +33 -0
  243. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +88 -15
  244. package/src/memory/v2/activation-store.ts +50 -1
  245. package/src/memory/v2/consolidation-job.ts +113 -29
  246. package/src/memory/v2/injected-block-slugs.ts +79 -0
  247. package/src/memory/v2/injection.ts +6 -1
  248. package/src/memory/v2/prompts/consolidation.ts +414 -13
  249. package/src/memory/v2/router.ts +2 -28
  250. package/src/memory/v2/static-context.ts +1 -1
  251. package/src/memory/v2/types.ts +16 -0
  252. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  253. package/src/notifications/access-request-copy.ts +298 -0
  254. package/src/notifications/adapters/slack.ts +3 -3
  255. package/src/notifications/adapters/telegram.ts +2 -1
  256. package/src/notifications/copy-composer.ts +49 -267
  257. package/src/notifications/decision-engine.ts +16 -35
  258. package/src/notifications/home-feed-side-effect.ts +1 -6
  259. package/src/oauth/oauth-store.ts +0 -9
  260. package/src/permissions/checker.test.ts +83 -1
  261. package/src/permissions/checker.ts +25 -2
  262. package/src/permissions/gateway-threshold-reader.test.ts +182 -0
  263. package/src/permissions/gateway-threshold-reader.ts +80 -0
  264. package/src/platform/client.ts +1 -3
  265. package/src/platform/feature-gate.ts +3 -12
  266. package/src/plugin-api/constants.ts +4 -2
  267. package/src/plugin-api/index.ts +63 -11
  268. package/src/plugin-api/types.ts +236 -71
  269. package/src/plugins/defaults/compaction/compact.ts +66 -2
  270. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +240 -32
  271. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  272. package/src/{daemon/context-overflow-policy.ts → plugins/defaults/compaction/overflow-policy.ts} +1 -1
  273. package/src/plugins/defaults/compaction/window-manager.ts +303 -1
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +173 -0
  275. package/src/plugins/defaults/empty-response/hooks/stop.ts +11 -115
  276. package/src/plugins/defaults/empty-response/nudge-state-store.ts +46 -0
  277. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +50 -0
  278. package/src/plugins/defaults/history-repair/hooks/stop.ts +22 -0
  279. package/src/plugins/defaults/history-repair/repair-state-store.ts +51 -0
  280. package/src/plugins/defaults/history-repair/terminal.ts +39 -2
  281. package/src/plugins/defaults/image-recovery/detect.ts +25 -0
  282. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +73 -0
  283. package/src/plugins/defaults/image-recovery/hooks/stop.ts +22 -0
  284. package/src/plugins/defaults/image-recovery/image-recovery-state-store.ts +48 -0
  285. package/src/plugins/defaults/image-recovery/package.json +14 -0
  286. package/src/{daemon/persist-unsendable-image.ts → plugins/defaults/image-recovery/recover.ts} +67 -14
  287. package/src/plugins/defaults/index.ts +71 -5
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +76 -112
  289. package/src/plugins/defaults/memory-retrieval/hooks/{user-prompt-submit-temp.ts → user-prompt-submit.ts} +83 -74
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +14 -8
  291. package/src/plugins/defaults/memory-retrieval/injectors.ts +2 -18
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1157 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +683 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +161 -140
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +160 -0
  297. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +335 -316
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +145 -53
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +38 -1
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +18 -8
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +112 -71
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +192 -51
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +4 -16
  304. package/src/plugins/defaults/memory-v3-shadow/card.test.ts +173 -0
  305. package/src/plugins/defaults/memory-v3-shadow/card.ts +116 -0
  306. package/src/plugins/defaults/memory-v3-shadow/core-set.test.ts +104 -0
  307. package/src/plugins/defaults/memory-v3-shadow/core-set.ts +59 -0
  308. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +305 -0
  309. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +278 -0
  310. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +138 -0
  311. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +85 -0
  312. package/src/plugins/defaults/memory-v3-shadow/injector.ts +331 -24
  313. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +119 -13
  314. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +169 -114
  315. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +47 -16
  316. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +144 -66
  317. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +758 -0
  318. package/src/plugins/defaults/memory-v3-shadow/prune.ts +471 -0
  319. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +68 -16
  320. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +19 -12
  321. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +96 -43
  322. package/src/plugins/defaults/memory-v3-shadow/types.ts +34 -17
  323. package/src/plugins/defaults/title-generate/hooks/stop.ts +9 -11
  324. package/src/plugins/pipeline.ts +8 -5
  325. package/src/plugins/types.ts +5 -51
  326. package/src/providers/cache-control.ts +26 -0
  327. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -2
  328. package/src/providers/model-catalog.ts +13 -1
  329. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +147 -0
  330. package/src/providers/openai/chat-completions-provider.ts +46 -0
  331. package/src/providers/openai/responses-provider.ts +45 -0
  332. package/src/providers/registry.ts +0 -8
  333. package/src/runtime/__tests__/agent-wake.test.ts +0 -1
  334. package/src/runtime/agent-wake.ts +13 -0
  335. package/src/runtime/routes/__tests__/acp-routes.test.ts +151 -0
  336. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +12 -50
  337. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +322 -0
  338. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -62
  339. package/src/runtime/routes/__tests__/plugins-routes.test.ts +31 -11
  340. package/src/runtime/routes/acp-routes.test.ts +106 -0
  341. package/src/runtime/routes/acp-routes.ts +248 -2
  342. package/src/runtime/routes/browser-tabs-routes.ts +1 -1
  343. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  344. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +0 -14
  345. package/src/runtime/routes/consolidation-routes.ts +6 -82
  346. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  347. package/src/runtime/routes/conversation-management-routes.ts +71 -0
  348. package/src/runtime/routes/identity-routes.ts +8 -0
  349. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  350. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -45
  351. package/src/runtime/routes/plugins-routes.ts +34 -45
  352. package/src/runtime/routes/schedule-routes.ts +43 -5
  353. package/src/runtime/routes/settings-routes.ts +140 -15
  354. package/src/runtime/routes/skills-routes.ts +18 -6
  355. package/src/runtime/services/__tests__/conversation-serializer.test.ts +140 -0
  356. package/src/runtime/services/conversation-serializer.ts +38 -1
  357. package/src/runtime/verification-outbound-actions.ts +147 -2
  358. package/src/runtime/verification-templates.ts +29 -3
  359. package/src/schedule/schedule-store.ts +19 -0
  360. package/src/skills/catalog-install.ts +77 -13
  361. package/src/tasks/task-scheduler.ts +1 -0
  362. package/src/telemetry/types.ts +66 -1
  363. package/src/telemetry/usage-telemetry-reporter.test.ts +542 -13
  364. package/src/telemetry/usage-telemetry-reporter.ts +213 -20
  365. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +49 -2
  366. package/src/tools/browser/__tests__/browser-status.test.ts +29 -5
  367. package/src/tools/browser/browser-execution.ts +27 -9
  368. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +380 -4
  369. package/src/tools/browser/cdp-client/__tests__/host-bridge-cdp-client.test.ts +107 -0
  370. package/src/tools/browser/cdp-client/__tests__/types.test.ts +6 -1
  371. package/src/tools/browser/cdp-client/factory.ts +217 -17
  372. package/src/tools/browser/cdp-client/host-bridge-cdp-client.ts +67 -0
  373. package/src/tools/browser/cdp-client/types.ts +22 -2
  374. package/src/tools/credential-execution/make-authenticated-request.ts +2 -1
  375. package/src/tools/credential-execution/manage-secure-command-tool.ts +169 -164
  376. package/src/tools/credential-execution/run-authenticated-command.ts +2 -1
  377. package/src/tools/executor.ts +39 -7
  378. package/src/tools/registry.ts +387 -5
  379. package/src/tools/schedule/create.ts +16 -0
  380. package/src/tools/schedule/list.ts +12 -4
  381. package/src/tools/schedule/update.ts +12 -0
  382. package/src/tools/skills/load.ts +11 -6
  383. package/src/tools/terminal/safe-env.ts +2 -0
  384. package/src/tools/types.ts +65 -9
  385. package/src/tools/workspace-tools/loader.ts +673 -0
  386. package/src/usage/attribution.ts +28 -0
  387. package/src/util/device-id.ts +17 -3
  388. package/src/util/platform.ts +16 -0
  389. package/tsconfig.plugin-api.json +13 -0
  390. package/src/__tests__/plugin-external-api.test.ts +0 -68
  391. package/src/__tests__/plugin-skill-contribution.test.ts +0 -355
  392. package/src/daemon/message-types/browser.ts +0 -10
  393. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  394. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +0 -36
  395. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +0 -37
  396. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +0 -106
  397. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +0 -44
  398. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +0 -91
  399. package/src/plugins/external-api.ts +0 -114
  400. package/src/plugins/plugin-skill-contributions.ts +0 -292
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Tests for the ClickHouse compaction log writer.
3
+ *
4
+ * The writer is exercised with an injected `fetchImpl` so the tests pin the
5
+ * wire shape: lazy CREATE TABLE on first write, INSERT statements via the
6
+ * `query` URL param with JSONEachRow bodies, and the start/end row mappings
7
+ * (sentinels on the start row, full `ContextWindowResult` projection on the
8
+ * end row).
9
+ */
10
+ import { describe, expect, test } from "bun:test";
11
+
12
+ import type { ContextWindowResult } from "../../plugins/defaults/compaction/window-manager.js";
13
+ import {
14
+ ClickHouseCompactionLogWriter,
15
+ type CompactionEndEvent,
16
+ type CompactionStartEvent,
17
+ } from "../compaction-log-writer-clickhouse.js";
18
+
19
+ interface CapturedRequest {
20
+ url: URL;
21
+ body: string;
22
+ }
23
+
24
+ function createWriter(overrides?: {
25
+ fetchImpl?: (url: string, init?: RequestInit) => Promise<Response>;
26
+ }): { writer: ClickHouseCompactionLogWriter; requests: CapturedRequest[] } {
27
+ const requests: CapturedRequest[] = [];
28
+ const fetchImpl = (overrides?.fetchImpl ??
29
+ (async (url: string, init?: RequestInit) => {
30
+ requests.push({ url: new URL(url), body: String(init?.body ?? "") });
31
+ return new Response("", { status: 200 });
32
+ })) as typeof fetch;
33
+ const writer = new ClickHouseCompactionLogWriter(
34
+ { database: "analytics", table: "compaction_logs", user: "writer" },
35
+ {
36
+ resolveUrl: async () => "http://clickhouse.example.com:8123",
37
+ resolvePassword: async () => "secret",
38
+ resolveAssistantId: async () => "assistant-123",
39
+ fetchImpl,
40
+ },
41
+ );
42
+ return { writer, requests };
43
+ }
44
+
45
+ const startEvent: CompactionStartEvent = {
46
+ type: "context_compacting",
47
+ compactionId: "comp-1",
48
+ requestId: "req-1",
49
+ trigger: "budget",
50
+ startedAt: 1000,
51
+ messages: [
52
+ { role: "user", content: [{ type: "text", text: "hi" }] },
53
+ { role: "assistant", content: [{ type: "text", text: "hello" }] },
54
+ ],
55
+ };
56
+
57
+ const result: ContextWindowResult = {
58
+ messages: [],
59
+ compacted: true,
60
+ previousEstimatedInputTokens: 900,
61
+ estimatedInputTokens: 300,
62
+ maxInputTokens: 1000,
63
+ thresholdTokens: 850,
64
+ compactedMessages: 10,
65
+ compactedPersistedMessages: 8,
66
+ preservedTailMessages: 2,
67
+ summaryCalls: 1,
68
+ summaryInputTokens: 880,
69
+ summaryOutputTokens: 120,
70
+ summaryModel: "test-model",
71
+ summaryText: "summary text",
72
+ reason: "auto",
73
+ exhausted: false,
74
+ };
75
+
76
+ const endEvent: CompactionEndEvent = {
77
+ type: "compaction_completed",
78
+ compactionId: "comp-1",
79
+ requestId: "req-1",
80
+ trigger: "budget",
81
+ startedAt: 1000,
82
+ finishedAt: 1500,
83
+ result,
84
+ messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
85
+ };
86
+
87
+ describe("ClickHouseCompactionLogWriter", () => {
88
+ test("first write creates the table then inserts", async () => {
89
+ const { writer, requests } = createWriter();
90
+
91
+ await writer.writeStart("conv-1", startEvent);
92
+
93
+ expect(requests.length).toBe(2);
94
+ expect(requests[0]!.body).toContain("CREATE TABLE IF NOT EXISTS");
95
+ expect(requests[0]!.body).toContain("`compaction_logs`");
96
+ expect(requests[0]!.url.searchParams.get("database")).toBe("analytics");
97
+
98
+ const insert = requests[1]!;
99
+ expect(insert.url.searchParams.get("query")).toBe(
100
+ "INSERT INTO `compaction_logs` FORMAT JSONEachRow",
101
+ );
102
+ const row = JSON.parse(insert.body) as Record<string, unknown>;
103
+ expect(row.assistant_id).toBe("assistant-123");
104
+ expect(row.conversation_id).toBe("conv-1");
105
+ expect(row.compaction_id).toBe("comp-1");
106
+ expect(row.request_id).toBe("req-1");
107
+ expect(row.phase).toBe("start");
108
+ expect(row.trigger).toBe("budget");
109
+ expect(row.started_at).toBe(1000);
110
+ expect(row.pre_message_count).toBe(2);
111
+ // End-only fields stay at their sentinels on the start row.
112
+ expect(row.finished_at).toBe(0);
113
+ expect(row.duration_ms).toBe(-1);
114
+ expect(row.estimated_input_tokens).toBe(-1);
115
+ expect(row.summary_model).toBe("");
116
+ });
117
+
118
+ test("table creation happens once across writes", async () => {
119
+ const { writer, requests } = createWriter();
120
+
121
+ await writer.writeStart("conv-1", startEvent);
122
+ await writer.writeEnd("conv-1", endEvent);
123
+
124
+ const ddl = requests.filter((r) => r.body.includes("CREATE TABLE"));
125
+ expect(ddl.length).toBe(1);
126
+ expect(requests.length).toBe(3);
127
+ });
128
+
129
+ test("end row projects the full ContextWindowResult", async () => {
130
+ const { writer, requests } = createWriter();
131
+
132
+ await writer.writeEnd("conv-1", endEvent);
133
+
134
+ const row = JSON.parse(requests[1]!.body) as Record<string, unknown>;
135
+ expect(row.phase).toBe("end");
136
+ expect(row.finished_at).toBe(1500);
137
+ expect(row.duration_ms).toBe(500);
138
+ expect(row.basis_message_count).toBe(1);
139
+ expect(row.compacted).toBe(1);
140
+ expect(row.previous_estimated_input_tokens).toBe(900);
141
+ expect(row.estimated_input_tokens).toBe(300);
142
+ expect(row.max_input_tokens).toBe(1000);
143
+ expect(row.threshold_tokens).toBe(850);
144
+ expect(row.compacted_messages).toBe(10);
145
+ expect(row.compacted_persisted_messages).toBe(8);
146
+ expect(row.preserved_tail_messages).toBe(2);
147
+ expect(row.summary_calls).toBe(1);
148
+ expect(row.summary_input_tokens).toBe(880);
149
+ expect(row.summary_output_tokens).toBe(120);
150
+ expect(row.summary_model).toBe("test-model");
151
+ expect(row.summary_failed).toBe(-1);
152
+ expect(row.reason).toBe("auto");
153
+ expect(row.exhausted).toBe(0);
154
+ expect(row.summary_text).toBe("summary text");
155
+ });
156
+
157
+ test("end row maps explicit summaryFailed and omitted optionals", async () => {
158
+ const { writer, requests } = createWriter();
159
+
160
+ await writer.writeEnd("conv-1", {
161
+ ...endEvent,
162
+ result: {
163
+ ...result,
164
+ compacted: false,
165
+ summaryFailed: true,
166
+ preservedTailMessages: undefined,
167
+ reason: undefined,
168
+ exhausted: true,
169
+ },
170
+ });
171
+
172
+ const row = JSON.parse(requests[1]!.body) as Record<string, unknown>;
173
+ expect(row.compacted).toBe(0);
174
+ expect(row.summary_failed).toBe(1);
175
+ expect(row.preserved_tail_messages).toBe(-1);
176
+ expect(row.reason).toBe("");
177
+ expect(row.exhausted).toBe(1);
178
+ });
179
+
180
+ test("failed table creation retries on the next write", async () => {
181
+ let calls = 0;
182
+ const requests: CapturedRequest[] = [];
183
+ const { writer } = createWriter({
184
+ fetchImpl: async (url: string, init?: RequestInit) => {
185
+ calls++;
186
+ requests.push({ url: new URL(url), body: String(init?.body ?? "") });
187
+ if (calls === 1) return new Response("boom", { status: 500 });
188
+ return new Response("", { status: 200 });
189
+ },
190
+ });
191
+
192
+ await expect(writer.writeStart("conv-1", startEvent)).rejects.toThrow(
193
+ "ClickHouse compaction-log write failed",
194
+ );
195
+
196
+ await writer.writeStart("conv-1", startEvent);
197
+ const ddl = requests.filter((r) => r.body.includes("CREATE TABLE"));
198
+ expect(ddl.length).toBe(2);
199
+ });
200
+
201
+ test("write failures surface the HTTP status and body", async () => {
202
+ let calls = 0;
203
+ const { writer } = createWriter({
204
+ fetchImpl: async () => {
205
+ calls++;
206
+ if (calls === 1) return new Response("", { status: 200 });
207
+ return new Response("table is read-only", { status: 403 });
208
+ },
209
+ });
210
+
211
+ await expect(writer.writeEnd("conv-1", endEvent)).rejects.toThrow(
212
+ /HTTP 403.*table is read-only/,
213
+ );
214
+ });
215
+
216
+ test("long summary text is truncated", async () => {
217
+ const { writer, requests } = createWriter();
218
+
219
+ await writer.writeEnd("conv-1", {
220
+ ...endEvent,
221
+ result: { ...result, summaryText: "x".repeat(10_000) },
222
+ });
223
+
224
+ const row = JSON.parse(requests[1]!.body) as Record<string, unknown>;
225
+ expect((row.summary_text as string).length).toBe(4000);
226
+ });
227
+ });
@@ -17,6 +17,8 @@ import {
17
17
  getMessageRoleStatsByConversation,
18
18
  listConversations,
19
19
  listConversationsBySource,
20
+ listPinnedConversations,
21
+ searchConversations,
20
22
  } from "../conversation-queries.js";
21
23
  import { getDb } from "../db-connection.js";
22
24
  import { initializeDb } from "../db-init.js";
@@ -560,6 +562,180 @@ describe("listConversationsBySource", () => {
560
562
  });
561
563
  });
562
564
 
565
+ describe("searchConversations · surfaced conversations", () => {
566
+ beforeEach(() => {
567
+ resetTables();
568
+ });
569
+
570
+ function insertMessage(
571
+ conversationId: string,
572
+ content: string,
573
+ createdAt = 1000,
574
+ ): void {
575
+ rawRun(
576
+ "INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)",
577
+ `msg-${conversationId}-${createdAt}`,
578
+ conversationId,
579
+ "user",
580
+ content,
581
+ createdAt,
582
+ );
583
+ }
584
+
585
+ function setSurfaced(conversationId: string): void {
586
+ rawRun(
587
+ "UPDATE conversations SET surfaced_at = ? WHERE id = ?",
588
+ Date.now(),
589
+ conversationId,
590
+ );
591
+ }
592
+
593
+ test("a surfaced background conversation is found by title search", () => {
594
+ const surfaced = createConversation({
595
+ title: "Quarterly metrics rollup",
596
+ conversationType: "background",
597
+ });
598
+ setSurfaced(surfaced.id);
599
+
600
+ const results = searchConversations("Quarterly metrics");
601
+
602
+ expect(results.map((r) => r.conversationId)).toEqual([surfaced.id]);
603
+ });
604
+
605
+ test("a surfaced background conversation is found by content search", () => {
606
+ const surfaced = createConversation({
607
+ title: "bg-run",
608
+ conversationType: "background",
609
+ });
610
+ setSurfaced(surfaced.id);
611
+ insertMessage(surfaced.id, "the flux capacitor needs recalibration");
612
+
613
+ const results = searchConversations("flux capacitor");
614
+
615
+ expect(results.map((r) => r.conversationId)).toEqual([surfaced.id]);
616
+ expect(results[0]!.matchingMessages).toHaveLength(1);
617
+ });
618
+
619
+ test("a non-surfaced background conversation stays excluded from search", () => {
620
+ const background = createConversation({
621
+ title: "Quarterly metrics rollup",
622
+ conversationType: "background",
623
+ });
624
+ insertMessage(background.id, "the flux capacitor needs recalibration");
625
+
626
+ expect(searchConversations("Quarterly metrics")).toEqual([]);
627
+ expect(searchConversations("flux capacitor")).toEqual([]);
628
+ });
629
+
630
+ test("private conversations are never included, even with surfaced_at set", () => {
631
+ const priv = createConversation("Quarterly metrics rollup");
632
+ setConversationType(priv.id, "private");
633
+ setSurfaced(priv.id);
634
+ insertMessage(priv.id, "the flux capacitor needs recalibration");
635
+
636
+ expect(searchConversations("Quarterly metrics")).toEqual([]);
637
+ expect(searchConversations("flux capacitor")).toEqual([]);
638
+ });
639
+
640
+ test("surfaced subagent runs stay excluded from search", () => {
641
+ const subagent = createConversation({
642
+ title: "Quarterly metrics rollup",
643
+ conversationType: "background",
644
+ source: "subagent",
645
+ });
646
+ setSurfaced(subagent.id);
647
+ insertMessage(subagent.id, "the flux capacitor needs recalibration");
648
+
649
+ expect(searchConversations("Quarterly metrics")).toEqual([]);
650
+ expect(searchConversations("flux capacitor")).toEqual([]);
651
+ });
652
+
653
+ test("LIKE content fallback (non-FTS-tokenizable query) honors surfacing", () => {
654
+ // Single-char queries produce no FTS tokens, exercising the LIKE fallback.
655
+ const surfaced = createConversation({
656
+ title: "bg-run",
657
+ conversationType: "background",
658
+ });
659
+ setSurfaced(surfaced.id);
660
+ insertMessage(surfaced.id, "review the C§ draft");
661
+
662
+ const hidden = createConversation({
663
+ title: "bg-hidden",
664
+ conversationType: "background",
665
+ });
666
+ insertMessage(hidden.id, "another C§ mention", 2000);
667
+
668
+ const results = searchConversations("C§");
669
+
670
+ expect(results.map((r) => r.conversationId)).toEqual([surfaced.id]);
671
+ });
672
+ });
673
+
674
+ describe("listPinnedConversations · surfaced conversations", () => {
675
+ beforeEach(() => {
676
+ resetTables();
677
+ });
678
+
679
+ function setSurfaced(conversationId: string): void {
680
+ rawRun(
681
+ "UPDATE conversations SET surfaced_at = ? WHERE id = ?",
682
+ Date.now(),
683
+ conversationId,
684
+ );
685
+ }
686
+
687
+ function setPinned(conversationId: string): void {
688
+ rawRun(
689
+ "UPDATE conversations SET is_pinned = 1 WHERE id = ?",
690
+ conversationId,
691
+ );
692
+ }
693
+
694
+ test("a pinned surfaced background conversation is returned", () => {
695
+ const surfaced = createConversation({
696
+ title: "bg-pinned-surfaced",
697
+ conversationType: "background",
698
+ });
699
+ setSurfaced(surfaced.id);
700
+ setPinned(surfaced.id);
701
+
702
+ const results = listPinnedConversations();
703
+
704
+ expect(results.map((r) => r.id)).toEqual([surfaced.id]);
705
+ });
706
+
707
+ test("a pinned non-surfaced background conversation stays excluded", () => {
708
+ const background = createConversation({
709
+ title: "bg-pinned-hidden",
710
+ conversationType: "background",
711
+ });
712
+ setPinned(background.id);
713
+
714
+ expect(listPinnedConversations()).toEqual([]);
715
+ });
716
+
717
+ test("pinned private conversations are never included, even with surfaced_at set", () => {
718
+ const priv = createConversation("private-pinned");
719
+ setConversationType(priv.id, "private");
720
+ setSurfaced(priv.id);
721
+ setPinned(priv.id);
722
+
723
+ expect(listPinnedConversations()).toEqual([]);
724
+ });
725
+
726
+ test("pinned surfaced subagent runs stay excluded", () => {
727
+ const subagent = createConversation({
728
+ title: "subagent-pinned",
729
+ conversationType: "background",
730
+ source: "subagent",
731
+ });
732
+ setSurfaced(subagent.id);
733
+ setPinned(subagent.id);
734
+
735
+ expect(listPinnedConversations()).toEqual([]);
736
+ });
737
+ });
738
+
563
739
  describe("getMessageRoleStatsByConversation", () => {
564
740
  beforeEach(() => {
565
741
  resetTables();
@@ -71,22 +71,18 @@ const { maybeEnqueueGraphMaintenanceJobs } = await import("../jobs-worker.js");
71
71
  const CONSOLIDATE_CHECKPOINT_KEY = "memory_v2_consolidate_last_run";
72
72
 
73
73
  function buildConfig(overrides: {
74
+ memoryEnabled?: boolean;
74
75
  v2Enabled?: boolean;
75
- consolidationEnabled?: boolean;
76
76
  intervalHours?: number;
77
77
  maxBufferLines?: number | null;
78
78
  }) {
79
79
  const partial = applyNestedDefaults({});
80
+ if (overrides.memoryEnabled !== undefined) {
81
+ partial.memory.enabled = overrides.memoryEnabled;
82
+ }
80
83
  if (overrides.v2Enabled !== undefined) {
81
84
  partial.memory.v2.enabled = overrides.v2Enabled;
82
85
  }
83
- if (overrides.consolidationEnabled !== undefined) {
84
- (
85
- partial.memory.v2 as typeof partial.memory.v2 & {
86
- consolidation_enabled?: boolean;
87
- }
88
- ).consolidation_enabled = overrides.consolidationEnabled;
89
- }
90
86
  if (overrides.intervalHours !== undefined) {
91
87
  partial.memory.v2.consolidation_interval_hours = overrides.intervalHours;
92
88
  }
@@ -164,6 +160,20 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
164
160
  expect(countPendingJobs("graph_narrative_refine")).toBe(0);
165
161
  });
166
162
 
163
+ test("does not enqueue consolidate when global memory is disabled", () => {
164
+ const config = buildConfig({
165
+ memoryEnabled: false,
166
+ v2Enabled: true,
167
+ intervalHours: 1,
168
+ });
169
+ writeBuffer(15);
170
+
171
+ maybeEnqueueGraphMaintenanceJobs(config, Date.now());
172
+
173
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
174
+ expect(countPendingJobs("graph_consolidate")).toBe(0);
175
+ });
176
+
167
177
  test("does not enqueue consolidate before the interval has elapsed", () => {
168
178
  const config = buildConfig({ v2Enabled: true, intervalHours: 1 });
169
179
 
@@ -254,28 +264,6 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
254
264
  expect(countPendingJobs("graph_narrative_refine")).toBe(1);
255
265
  expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
256
266
  });
257
-
258
- test("automatic consolidation off suppresses the v2 schedule without re-enabling v1 maintenance", () => {
259
- const config = buildConfig({
260
- v2Enabled: true,
261
- consolidationEnabled: false,
262
- intervalHours: 1,
263
- });
264
-
265
- deleteMemoryCheckpoint("graph_maintenance:decay:last_run");
266
- deleteMemoryCheckpoint("graph_maintenance:consolidate:last_run");
267
- deleteMemoryCheckpoint("graph_maintenance:pattern_scan:last_run");
268
- deleteMemoryCheckpoint("graph_maintenance:narrative:last_run");
269
- deleteMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY);
270
-
271
- maybeEnqueueGraphMaintenanceJobs(config, Date.now());
272
-
273
- expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
274
- expect(countPendingJobs("graph_decay")).toBe(0);
275
- expect(countPendingJobs("graph_consolidate")).toBe(0);
276
- expect(countPendingJobs("graph_pattern_scan")).toBe(0);
277
- expect(countPendingJobs("graph_narrative_refine")).toBe(0);
278
- });
279
267
  });
280
268
 
281
269
  describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
@@ -415,10 +403,10 @@ describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
415
403
  expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
416
404
  });
417
405
 
418
- test("size trigger inert when automatic consolidation is disabled", () => {
406
+ test("size trigger inert when global memory is disabled", () => {
419
407
  const config = buildConfig({
408
+ memoryEnabled: false,
420
409
  v2Enabled: true,
421
- consolidationEnabled: false,
422
410
  intervalHours: 1,
423
411
  maxBufferLines: 1,
424
412
  });