@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
@@ -1,190 +0,0 @@
1
- /**
2
- * Memory v3 — L1 leaf router.
3
- *
4
- * One forced-tool LLM call per turn that picks which leaves of the topic tree
5
- * to open for the next reply. The design mirrors `../v2/router.ts`:
6
- * - resolve the configured provider via `getConfiguredProvider`,
7
- * - call `provider.sendMessage` with a forced `tool_choice`,
8
- * - validate the tool input via Zod,
9
- * - map numbered IDs back to leaf paths.
10
- *
11
- * Cache strategy. The numbered leaf block is the single largest input and is
12
- * STABLE across turns — it changes only when leaves are added/removed/edited.
13
- * We render it first in the user message and tag it with an ephemeral
14
- * `cache_control` breakpoint so the provider can serve it from the prompt
15
- * cache turn after turn. The trailing recent-context / current-message block
16
- * changes every turn, so it carries no breakpoint.
17
- *
18
- * Failure handling. A *model-call* failure is not the same as the model
19
- * choosing to open everything, so the two no longer share an outcome:
20
- * - explicit `ids` → open exactly those leaves,
21
- * - explicit empty array (`ids: []`) → open nothing (deliberate abstention),
22
- * - omitted `ids` → open nothing: the router must name the leaves it wants,
23
- * never the whole tree (~137 leaves would fan out a full L2 pass per turn),
24
- * - infrastructure failure (provider unavailable, a throw that survived the
25
- * provider's own retries, no usable `tool_use`, or a schema mismatch) →
26
- * open nothing after a short re-prompt retry, degrading to the deterministic
27
- * recall lanes (always-on core, the BM25 needle, the carry-forward working
28
- * set) that the orchestrator unions in regardless.
29
- */
30
-
31
- import { z } from "zod";
32
-
33
- import {
34
- extractToolUse,
35
- getConfiguredProvider,
36
- } from "../../providers/provider-send-message.js";
37
- import type { Message, ToolDefinition } from "../../providers/types.js";
38
- import { getLogger } from "../../util/logger.js";
39
- import { retryForResult } from "./llm-retry.js";
40
- import { cachedTextBlock } from "./provider-blocks.js";
41
- import type { LeafPath, LeafTree, TurnContext } from "./types.js";
42
-
43
- const log = getLogger("memory-v3-router");
44
-
45
- /** Tool name forced via `tool_choice`. Shared constant so tests can match it. */
46
- const OPEN_LEAVES_TOOL_NAME = "open_leaves";
47
-
48
- const OpenLeavesSchema = z.object({
49
- // Optional so the field can be absent on the wire, but an omitted `ids` opens
50
- // nothing — the router must name the leaves it wants, never the whole tree.
51
- ids: z.array(z.number().int()).optional(),
52
- });
53
-
54
- const OPEN_LEAVES_TOOL: ToolDefinition = {
55
- name: OPEN_LEAVES_TOOL_NAME,
56
- description:
57
- "Open the leaves whose contents could plausibly bear on the next reply. " +
58
- "Lean toward inclusion — a missed relevant leaf is a worse error than an " +
59
- "unused one. Pass the chosen IDs explicitly; return `[]` only when nothing " +
60
- "in the tree could possibly help.",
61
- input_schema: {
62
- type: "object",
63
- properties: {
64
- ids: {
65
- type: "array",
66
- items: { type: "integer" },
67
- },
68
- },
69
- },
70
- };
71
-
72
- const SYSTEM_PROMPT = `You route a conversation turn to the leaves of a topic tree that should be opened for the next reply.
73
-
74
- Each leaf has a numbered ID, a path, and a description of what it holds. Decide which leaves to open by weighing four signals:
75
-
76
- - Topic — entities, projects, and events named or implied by the turn.
77
- - Register — the affect and mode of the message (e.g. playful, distressed, formal). A register signal is enough to open a leaf even when no entity is named.
78
- - Recent context — the immediately preceding exchange, which resolves references like "this", "that", or "the same thing" to concrete topics.
79
- - Situation — the current date and a live scratchpad of what is salient right now. A date or state cue can make a leaf relevant even when the message never names it (e.g. a person whose anniversary is today, an active thread).
80
-
81
- Include on doubt: open every leaf that could plausibly hold something useful. Missing a relevant leaf is a worse error than opening an unused one. Call \`open_leaves\` with the chosen IDs explicitly; return \`[]\` only when nothing in the tree could possibly help.`;
82
-
83
- /** Leaves sorted deterministically by path so the numbered block is stable. */
84
- function sortedLeaves(tree: LeafTree): LeafPath[] {
85
- return [...tree.leaves.keys()].sort();
86
- }
87
-
88
- /**
89
- * Render the STATIC numbered leaf block from a pre-sorted path list. Identical
90
- * across turns for any given tree, which is what makes the prompt-cache
91
- * breakpoint pay off.
92
- */
93
- function renderLeafBlockFromPaths(tree: LeafTree, paths: LeafPath[]): string {
94
- const lines = paths.map((path, i) => {
95
- const description = tree.leaves.get(path)?.description ?? "";
96
- // Collapse the (possibly multi-line) description to a single line so each
97
- // leaf is exactly one numbered entry.
98
- const oneLine = description.replace(/\s+/g, " ").trim();
99
- return `[${i + 1}] ${path} — ${oneLine}`;
100
- });
101
- return `<leaves>\n${lines.join("\n")}\n</leaves>`;
102
- }
103
-
104
- /**
105
- * Render the static numbered leaf block for a tree. Exported for the test that
106
- * locks the byte-identical cache invariant; `routeL1` renders from its already
107
- * sorted path list to avoid sorting twice.
108
- */
109
- export function renderLeafBlock(tree: LeafTree): string {
110
- return renderLeafBlockFromPaths(tree, sortedLeaves(tree));
111
- }
112
-
113
- /**
114
- * Run the L1 router for one turn. Returns the leaf paths to open — only ever the
115
- * leaves the model names explicitly. An omitted `ids`, an explicit `[]`, or an
116
- * infrastructure failure (after a short re-prompt retry) all open nothing,
117
- * degrading to the deterministic recall lanes the orchestrator unions in.
118
- */
119
- export async function routeL1(
120
- turn: TurnContext,
121
- tree: LeafTree,
122
- ): Promise<LeafPath[]> {
123
- const paths = sortedLeaves(tree);
124
- if (paths.length === 0) return [];
125
-
126
- const provider = await getConfiguredProvider("memoryV3RouteL1");
127
- if (!provider) {
128
- log.warn(
129
- "L1 router provider unavailable; degrading to deterministic lanes",
130
- );
131
- return [];
132
- }
133
-
134
- const userMsg: Message = {
135
- role: "user",
136
- content: [
137
- cachedTextBlock(renderLeafBlockFromPaths(tree, paths)),
138
- {
139
- type: "text",
140
- text:
141
- (turn.situationalContext
142
- ? `<situation>${turn.situationalContext}</situation>\n`
143
- : "") +
144
- `<recent_context>${turn.recentContext}</recent_context>\n` +
145
- `<current_message>${turn.currentMessage}</current_message>`,
146
- },
147
- ],
148
- };
149
-
150
- // One forced-tool call, retried a few times so a transient malformed response
151
- // (no usable tool_use, or tool input that fails the schema) re-prompts before
152
- // we give up. `null` from an attempt means "unusable, retry"; the provider
153
- // layer already backs off transient throws, so this loop adds no delay.
154
- const parsed = await retryForResult(async () => {
155
- const response = await provider.sendMessage([userMsg], {
156
- tools: [OPEN_LEAVES_TOOL],
157
- systemPrompt: SYSTEM_PROMPT,
158
- config: {
159
- callSite: "memoryV3RouteL1" as const,
160
- tool_choice: { type: "tool" as const, name: OPEN_LEAVES_TOOL_NAME },
161
- },
162
- });
163
- const toolBlock = extractToolUse(response);
164
- if (!toolBlock || toolBlock.name !== OPEN_LEAVES_TOOL_NAME) return null;
165
- const result = OpenLeavesSchema.safeParse(toolBlock.input);
166
- return result.success ? result.data : null;
167
- });
168
-
169
- if (parsed === null) {
170
- log.warn(
171
- "L1 router could not obtain a selection after retries; degrading to deterministic lanes",
172
- );
173
- return [];
174
- }
175
-
176
- // An omitted `ids` field means the model named no leaves — open nothing rather
177
- // than the whole tree. Only explicitly listed IDs open leaves.
178
- if (parsed.ids === undefined) return [];
179
-
180
- // Map 1-based IDs back to leaf paths, dropping out-of-range IDs without
181
- // throwing. De-duplicate while preserving model-returned order.
182
- const seen = new Set<number>();
183
- const selected: LeafPath[] = [];
184
- for (const id of parsed.ids) {
185
- if (id < 1 || id > paths.length || seen.has(id)) continue;
186
- seen.add(id);
187
- selected.push(paths[id - 1]);
188
- }
189
- return selected;
190
- }
@@ -1,84 +0,0 @@
1
- /**
2
- * Read-side store for the inspector's Memory V3 section. Reads the persisted
3
- * `memory_v3_selections` rows for a turn and re-renders the `<memory>` block
4
- * the v3 working set selected, so the inspector can show what v3 chose (and,
5
- * in live mode, what it actually injected) without re-running orchestration —
6
- * which would be wrong anyway, since the working set is stateful (carry-forward
7
- * across turns) and can't be reproduced after the fact.
8
- */
9
-
10
- import type { MemoryV3SelectionLog } from "../../api/responses/memory-v3-selection-log.js";
11
- import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
12
- import { getConfig } from "../../config/loader.js";
13
- import { getDb, getSqliteFrom } from "../db-connection.js";
14
- import { renderV3PageContent } from "./page-content.js";
15
- import { renderMemoryBlock } from "./render-injection.js";
16
- import type { Slug } from "./types.js";
17
-
18
- const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
19
- const MEMORY_V3_LIVE = "memory-v3-live" as const;
20
-
21
- interface SelectionRow {
22
- slug: string;
23
- source: string;
24
- pinned: number;
25
- }
26
-
27
- function rowsForTurn(conversationId: string, turn: number): SelectionRow[] {
28
- return getSqliteFrom(getDb())
29
- .query(
30
- /*sql*/ `
31
- SELECT slug, source, pinned FROM memory_v3_selections
32
- WHERE conversation_id = ? AND turn = ?
33
- ORDER BY rowid
34
- `,
35
- )
36
- .all(conversationId, turn) as SelectionRow[];
37
- }
38
-
39
- /**
40
- * Build the inspector's v3 selection log for one turn of a conversation.
41
- *
42
- * `turn` is the inspected message's turn (the v2-activation log's turn). The
43
- * selection is returned ONLY for that exact turn; when there are no v3 rows for
44
- * it — including when `turn` is null (the message has no v2-activation turn) —
45
- * this returns `null` rather than falling back to a different turn. A fallback
46
- * would attribute another turn's selection (e.g. a later turn's pages and
47
- * rendered block) to the inspected message, which corrupts shadow validation.
48
- *
49
- * Caveat: v3 rows are keyed by the orchestrator turn counter (`ctx.turnCount`)
50
- * while `turn` here is the v2 memory-tracker turn. They coincide for normal
51
- * turns, but if they diverge this simply yields `null` (no section) rather than
52
- * wrong data. Tying v3 rows to a message id for exact per-message attribution
53
- * regardless of counter drift is a documented follow-up.
54
- *
55
- * Selection rows are stored in `finalInjection` order (this turn's L2
56
- * selections, then carry-forward), so rendering them in row order reproduces
57
- * the block v3 would inject.
58
- */
59
- export async function getMemoryV3SelectionForInspector(
60
- conversationId: string,
61
- turn: number | null | undefined,
62
- ): Promise<MemoryV3SelectionLog | null> {
63
- if (turn == null) return null;
64
-
65
- const rows = rowsForTurn(conversationId, turn);
66
- if (rows.length === 0) return null;
67
-
68
- const config = getConfig();
69
- const selections = rows.map((r) => ({
70
- slug: r.slug,
71
- source: r.source,
72
- pinned: r.pinned === 1,
73
- }));
74
- const slugs: Slug[] = selections.map((s) => s.slug);
75
- const injectedText = await renderMemoryBlock(slugs, renderV3PageContent);
76
-
77
- return {
78
- turn,
79
- live: isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config),
80
- shadow: isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config),
81
- selections,
82
- injectedText,
83
- };
84
- }
@@ -1,226 +0,0 @@
1
- /**
2
- * Memory v3 — L2 per-leaf page selector.
3
- *
4
- * After the L1 router (`./router.ts`) decides which leaves to open, the L2
5
- * selector runs ONE forced-tool LLM call PER opened leaf to pick which pages
6
- * inside that leaf are relevant for the next reply. `selectAcrossLeaves` fans
7
- * the per-leaf calls out with bounded concurrency.
8
- *
9
- * Cache strategy. Each leaf's `<pages>` block — the numbered list of its member
10
- * pages with their full summaries — is STABLE for that leaf: it changes only
11
- * when pages are added/removed or a summary is rewritten, never per turn. We
12
- * render it FIRST in the per-leaf user message and tag it with an ephemeral
13
- * `cache_control` breakpoint so the provider serves it from the prompt cache
14
- * turn after turn. The trailing recent-context / current-message block changes
15
- * every turn and carries no breakpoint. This mirrors `./router.ts`.
16
- *
17
- * Failure handling. A deliberate "select everything" and a model-call failure
18
- * are different events with different outcomes:
19
- * - explicit `ids` → select exactly those pages,
20
- * - explicit empty `ids: []` → select nothing (deliberate abstention),
21
- * - omitted `ids` → select ALL members of the leaf (the recall-safe "this
22
- * whole leaf is relevant" signal, e.g. "give me all of X"); bounded to one
23
- * leaf, so unlike the router this stays a select-all,
24
- * - infrastructure failure (provider unavailable, a throw that survived the
25
- * provider's own retries, no usable `tool_use`, or a schema mismatch) →
26
- * select nothing after a short re-prompt retry, degrading to the
27
- * deterministic recall lanes (core, needle, carry-forward working set) the
28
- * orchestrator unions in regardless.
29
- */
30
-
31
- import { z } from "zod";
32
-
33
- import {
34
- extractToolUse,
35
- getConfiguredProvider,
36
- } from "../../providers/provider-send-message.js";
37
- import type { Message, ToolDefinition } from "../../providers/types.js";
38
- import { getLogger } from "../../util/logger.js";
39
- import { mapLimit } from "../../util/map-limit.js";
40
- import { retryForResult } from "./llm-retry.js";
41
- import { cachedTextBlock } from "./provider-blocks.js";
42
- import { membersOf } from "./tree.js";
43
- import type { LeafPath, LeafTree, Slug, TurnContext } from "./types.js";
44
-
45
- const log = getLogger("memory-v3-selector");
46
-
47
- /** A page selected from an opened leaf, with whether the turn centers on it. */
48
- export interface SelectedPage {
49
- slug: Slug;
50
- pinned: boolean;
51
- }
52
-
53
- /** Tool name forced via `tool_choice`. Shared constant so tests can match it. */
54
- const SELECT_PAGES_TOOL_NAME = "select_pages";
55
-
56
- const SelectPagesSchema = z.object({
57
- // Optional: an omitted `ids` field is the recall-safe "select everything"
58
- // signal, distinct from an explicit empty array (deliberate abstention).
59
- ids: z.array(z.number().int()).optional(),
60
- pinned_ids: z.array(z.number().int()).optional(),
61
- });
62
-
63
- const SELECT_PAGES_TOOL: ToolDefinition = {
64
- name: SELECT_PAGES_TOOL_NAME,
65
- description:
66
- "Select the pages in this leaf whose content the reply would directly " +
67
- "draw on. Be selective — prefer a few precisely-relevant pages over many " +
68
- "loosely-related ones; a leaf opened on a weak signal may yield none. " +
69
- "Pass `pinned_ids` for pages the conversation is centrally about. Omit " +
70
- "`ids` only as a recall-safe fallback when you cannot judge the leaf " +
71
- "(selects every page); return `[]` when pages are present but none are " +
72
- "directly relevant.",
73
- input_schema: {
74
- type: "object",
75
- properties: {
76
- ids: {
77
- type: "array",
78
- items: { type: "integer" },
79
- },
80
- pinned_ids: {
81
- type: "array",
82
- items: { type: "integer" },
83
- },
84
- },
85
- },
86
- };
87
-
88
- const SYSTEM_PROMPT = `This leaf of the topic tree is potentially relevant to the conversation. Select ONLY the pages whose content the reply to THIS message would directly draw on.
89
-
90
- Be selective: exclude pages that are merely topically adjacent, part of the ever-present background, or only loosely related. Most opened leaves should contribute a few precisely-relevant pages, not most of their contents — a leaf opened on a weak signal may yield none.
91
-
92
- A page can also be directly relevant because of the current situation — the date or the live scratchpad — not only the message: keep a page the situation makes pertinent (e.g. a person whose anniversary is today).
93
-
94
- If the conversation is centrally ABOUT a page (rather than only peripherally relevant to it), mark that page as pinned. Call \`select_pages\` with the chosen IDs. Omit \`ids\` only as a recall-safe fallback when you cannot judge the leaf (selects every page); return \`[]\` when the pages are present but none are directly relevant.`;
95
-
96
- /**
97
- * Render the STATIC numbered `<pages>` block for a leaf from its member slugs.
98
- * Identical across turns for a given leaf, which is what makes the per-leaf
99
- * prompt-cache breakpoint pay off. Summaries are rendered in full (no
100
- * truncation) so the selector sees each page's complete description.
101
- */
102
- async function renderPagesBlock(
103
- members: Slug[],
104
- pageSummary: (slug: Slug) => Promise<string>,
105
- ): Promise<string> {
106
- const lines = await Promise.all(
107
- members.map(async (slug, i) => {
108
- const summary = await pageSummary(slug);
109
- return `[${i + 1}] ${slug} — ${summary}`;
110
- }),
111
- );
112
- return `<pages>\n${lines.join("\n")}\n</pages>`;
113
- }
114
-
115
- /**
116
- * Run the L2 selector for a single opened leaf. Returns the pages to inject.
117
- *
118
- * An omitted `ids` selects ALL members (the recall-safe "whole leaf is
119
- * relevant" signal); an explicit `[]` selects none; an infrastructure failure
120
- * (after a short re-prompt retry) selects none, degrading to the deterministic
121
- * recall lanes the orchestrator unions in.
122
- */
123
- export async function selectFromLeaf(
124
- leaf: LeafPath,
125
- turn: TurnContext,
126
- tree: LeafTree,
127
- pageSummary: (slug: Slug) => Promise<string>,
128
- ): Promise<SelectedPage[]> {
129
- const members = membersOf(tree, leaf);
130
- if (members.length === 0) return [];
131
-
132
- const allMembers = (): SelectedPage[] =>
133
- members.map((slug) => ({ slug, pinned: false }));
134
-
135
- const provider = await getConfiguredProvider("memoryV3SelectL2");
136
- if (!provider) {
137
- log.warn(
138
- { leaf },
139
- "L2 selector provider unavailable; degrading to deterministic lanes",
140
- );
141
- return [];
142
- }
143
-
144
- const userMsg: Message = {
145
- role: "user",
146
- content: [
147
- cachedTextBlock(
148
- `<leaf>${leaf}</leaf>\n` +
149
- (await renderPagesBlock(members, pageSummary)),
150
- ),
151
- {
152
- type: "text",
153
- text:
154
- (turn.situationalContext
155
- ? `<situation>${turn.situationalContext}</situation>\n`
156
- : "") +
157
- `<recent_context>${turn.recentContext}</recent_context>\n` +
158
- `<current_message>${turn.currentMessage}</current_message>`,
159
- },
160
- ],
161
- };
162
-
163
- // One forced-tool call, retried a few times so a transient malformed response
164
- // (no usable tool_use, or tool input that fails the schema) re-prompts before
165
- // we give up. `null` from an attempt means "unusable, retry"; the provider
166
- // layer already backs off transient throws, so this loop adds no delay.
167
- const parsed = await retryForResult(async () => {
168
- const response = await provider.sendMessage([userMsg], {
169
- tools: [SELECT_PAGES_TOOL],
170
- systemPrompt: SYSTEM_PROMPT,
171
- config: {
172
- callSite: "memoryV3SelectL2" as const,
173
- tool_choice: { type: "tool" as const, name: SELECT_PAGES_TOOL_NAME },
174
- },
175
- });
176
- const toolBlock = extractToolUse(response);
177
- if (!toolBlock || toolBlock.name !== SELECT_PAGES_TOOL_NAME) return null;
178
- const result = SelectPagesSchema.safeParse(toolBlock.input);
179
- return result.success ? result.data : null;
180
- });
181
-
182
- if (parsed === null) {
183
- log.warn(
184
- { leaf },
185
- "L2 selector could not obtain a selection after retries; degrading to deterministic lanes",
186
- );
187
- return [];
188
- }
189
-
190
- // Omitted `ids` is the recall-safe "this whole leaf is relevant" signal.
191
- // Bounded to one leaf, so it stays a select-all (unlike the L1 router).
192
- if (parsed.ids === undefined) return allMembers();
193
-
194
- const pinned = new Set(parsed.pinned_ids ?? []);
195
-
196
- // Map 1-based IDs back to member slugs, dropping out-of-range IDs without
197
- // throwing. De-duplicate while preserving model-returned order.
198
- const seen = new Set<number>();
199
- const selected: SelectedPage[] = [];
200
- for (const id of parsed.ids) {
201
- if (id < 1 || id > members.length || seen.has(id)) continue;
202
- seen.add(id);
203
- selected.push({ slug: members[id - 1]!, pinned: pinned.has(id) });
204
- }
205
- return selected;
206
- }
207
-
208
- /**
209
- * Run the L2 selector across every opened leaf with bounded concurrency and
210
- * flatten the per-leaf selections.
211
- *
212
- * A page assigned to more than one opened leaf may appear more than once in the
213
- * result; de-duplication across leaves is the orchestrator's job in a later PR.
214
- */
215
- export async function selectAcrossLeaves(
216
- leaves: LeafPath[],
217
- turn: TurnContext,
218
- tree: LeafTree,
219
- pageSummary: (slug: Slug) => Promise<string>,
220
- concurrency = 4,
221
- ): Promise<SelectedPage[]> {
222
- const perLeaf = await mapLimit(leaves, concurrency, (leaf) =>
223
- selectFromLeaf(leaf, turn, tree, pageSummary),
224
- );
225
- return perLeaf.flat();
226
- }