@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,192 +0,0 @@
1
- import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
6
-
7
- import { leavesOf, loadLeafTree, membersOf, resolveDataDir } from "../tree.js";
8
-
9
- const HERE = dirname(fileURLToPath(import.meta.url));
10
- const BUNDLED_DATA_DIR = join(HERE, "..", "data");
11
-
12
- describe("loadLeafTree", () => {
13
- test("loads leaves with frontmatter, description, and domain", async () => {
14
- const tree = await loadLeafTree(BUNDLED_DATA_DIR);
15
-
16
- expect([...tree.leaves.keys()].sort()).toEqual([
17
- "domain-a/topic-x",
18
- "domain-a/topic-y",
19
- "domain-b/topic-z",
20
- ]);
21
-
22
- const topicX = tree.leaves.get("domain-a/topic-x");
23
- expect(topicX).toBeDefined();
24
- expect(topicX?.path).toBe("domain-a/topic-x");
25
- expect(topicX?.frontmatter).toEqual({
26
- path: "domain-a/topic-x",
27
- in_core: true,
28
- });
29
- expect(topicX?.domain).toBe("domain-a");
30
- expect(topicX?.description.length).toBeGreaterThan(0);
31
- expect(topicX?.description.startsWith("---")).toBe(false);
32
-
33
- const topicZ = tree.leaves.get("domain-b/topic-z");
34
- expect(topicZ?.frontmatter.in_core).toBe(false);
35
- expect(topicZ?.domain).toBe("domain-b");
36
-
37
- // Bundled leaves predate the optional `id` field.
38
- expect(topicX?.frontmatter.id).toBeUndefined();
39
- });
40
-
41
- test("parses the optional stable id when present, omits it otherwise", async () => {
42
- const dataDir = await mkdtemp(join(tmpdir(), "v3-leaf-id-"));
43
- try {
44
- await mkdir(join(dataDir, "leaves", "domain-a"), { recursive: true });
45
- await writeFile(
46
- join(dataDir, "leaves", "domain-a", "topic-x.md"),
47
- "---\npath: domain-a/topic-x\nin_core: true\nid: leaf-123\n---\n\nWith id.\n",
48
- );
49
- await writeFile(
50
- join(dataDir, "leaves", "domain-a", "topic-y.md"),
51
- "---\npath: domain-a/topic-y\nin_core: false\n---\n\nNo id.\n",
52
- );
53
- await writeFile(
54
- join(dataDir, "assignments.json"),
55
- JSON.stringify({ "page-a": ["domain-a/topic-x"] }),
56
- );
57
-
58
- const tree = await loadLeafTree(dataDir);
59
- expect(tree.leaves.get("domain-a/topic-x")?.frontmatter.id).toBe(
60
- "leaf-123",
61
- );
62
- expect(
63
- tree.leaves.get("domain-a/topic-y")?.frontmatter.id,
64
- ).toBeUndefined();
65
- } finally {
66
- await rm(dataDir, { recursive: true, force: true });
67
- }
68
- });
69
-
70
- test("builds members and byPage from assignments", async () => {
71
- const tree = await loadLeafTree(BUNDLED_DATA_DIR);
72
-
73
- // byPage is the inverted assignment map.
74
- expect(tree.byPage.get("page-a")).toEqual(["domain-a/topic-x"]);
75
- expect(tree.byPage.get("page-b")).toEqual([
76
- "domain-a/topic-x",
77
- "domain-a/topic-y",
78
- ]);
79
- expect(tree.byPage.get("page-c")).toEqual(["domain-b/topic-z"]);
80
-
81
- // members are the slugs assigned to each leaf.
82
- expect(membersOf(tree, "domain-a/topic-x").sort()).toEqual([
83
- "page-a",
84
- "page-b",
85
- ]);
86
- expect(membersOf(tree, "domain-a/topic-y")).toEqual(["page-b"]);
87
- expect(membersOf(tree, "domain-b/topic-z")).toEqual(["page-c"]);
88
- });
89
-
90
- test("membersOf and leavesOf return empty arrays for unknown keys", async () => {
91
- const tree = await loadLeafTree(BUNDLED_DATA_DIR);
92
- expect(membersOf(tree, "nope/missing")).toEqual([]);
93
- expect(leavesOf(tree, "missing-slug")).toEqual([]);
94
- });
95
-
96
- test("leavesOf mirrors byPage", async () => {
97
- const tree = await loadLeafTree(BUNDLED_DATA_DIR);
98
- expect(leavesOf(tree, "page-b")).toEqual([
99
- "domain-a/topic-x",
100
- "domain-a/topic-y",
101
- ]);
102
- });
103
-
104
- test("frontmatter pageLeaves win over assignments.json per page", async () => {
105
- const tree = await loadLeafTree(
106
- BUNDLED_DATA_DIR,
107
- new Map([["page-a", ["domain-a/topic-y"]]]),
108
- );
109
-
110
- // page-a is overridden by frontmatter; assignments.json said topic-x.
111
- expect(leavesOf(tree, "page-a")).toEqual(["domain-a/topic-y"]);
112
- expect(membersOf(tree, "domain-a/topic-y").sort()).toEqual([
113
- "page-a",
114
- "page-b",
115
- ]);
116
- expect(membersOf(tree, "domain-a/topic-x")).toEqual(["page-b"]);
117
- });
118
-
119
- test("pages absent from pageLeaves fall back to assignments.json", async () => {
120
- // page-a override + a page-with-empty-frontmatter that must fall back.
121
- const tree = await loadLeafTree(
122
- BUNDLED_DATA_DIR,
123
- new Map([
124
- ["page-a", ["domain-a/topic-y"]],
125
- ["page-c", []],
126
- ]),
127
- );
128
-
129
- // page-b never appeared in pageLeaves → assignments.json.
130
- expect(leavesOf(tree, "page-b")).toEqual([
131
- "domain-a/topic-x",
132
- "domain-a/topic-y",
133
- ]);
134
- // page-c had an empty frontmatter array → falls back to assignments.json.
135
- expect(leavesOf(tree, "page-c")).toEqual(["domain-b/topic-z"]);
136
- });
137
-
138
- test("omitting pageLeaves preserves assignments.json behavior", async () => {
139
- const withMap = await loadLeafTree(BUNDLED_DATA_DIR, new Map());
140
- const without = await loadLeafTree(BUNDLED_DATA_DIR);
141
-
142
- // An empty map is equivalent to omitting it: pure assignments.json.
143
- for (const slug of ["page-a", "page-b", "page-c"]) {
144
- expect(leavesOf(withMap, slug)).toEqual(leavesOf(without, slug));
145
- }
146
- expect(leavesOf(without, "page-a")).toEqual(["domain-a/topic-x"]);
147
- });
148
- });
149
-
150
- describe("resolveDataDir", () => {
151
- let tmpRoot: string;
152
- const prevWorkspace = process.env.VELLUM_WORKSPACE_DIR;
153
-
154
- beforeEach(async () => {
155
- tmpRoot = await mkdtemp(join(tmpdir(), "v3-tree-"));
156
- });
157
-
158
- afterEach(async () => {
159
- if (prevWorkspace === undefined) delete process.env.VELLUM_WORKSPACE_DIR;
160
- else process.env.VELLUM_WORKSPACE_DIR = prevWorkspace;
161
- await rm(tmpRoot, { recursive: true, force: true });
162
- });
163
-
164
- test("falls back to bundled stub when no workspace override exists", () => {
165
- process.env.VELLUM_WORKSPACE_DIR = join(tmpRoot, "workspace");
166
- expect(resolveDataDir()).toBe(BUNDLED_DATA_DIR);
167
- });
168
-
169
- test("prefers workspace override when <workspace>/memory/v3/data exists", async () => {
170
- const workspace = join(tmpRoot, "workspace");
171
- const workspaceData = join(workspace, "memory", "v3", "data");
172
- const leafDir = join(workspaceData, "leaves", "domain-w");
173
- await mkdir(leafDir, { recursive: true });
174
- await writeFile(
175
- join(leafDir, "topic-real.md"),
176
- "---\npath: domain-w/topic-real\nin_core: false\n---\n\nReal workspace leaf.\n",
177
- );
178
- await writeFile(
179
- join(workspaceData, "assignments.json"),
180
- JSON.stringify({ "real-page": ["domain-w/topic-real"] }),
181
- );
182
-
183
- process.env.VELLUM_WORKSPACE_DIR = workspace;
184
-
185
- expect(resolveDataDir()).toBe(workspaceData);
186
-
187
- const tree = await loadLeafTree(resolveDataDir());
188
- expect([...tree.leaves.keys()]).toEqual(["domain-w/topic-real"]);
189
- expect(membersOf(tree, "domain-w/topic-real")).toEqual(["real-page"]);
190
- expect(leavesOf(tree, "real-page")).toEqual(["domain-w/topic-real"]);
191
- });
192
- });
@@ -1,268 +0,0 @@
1
- /**
2
- * v3 page→leaf classifier: assigns pages to leaf topics and UNIONS the result
3
- * into each page's `leaves:` frontmatter.
4
- *
5
- * This ports an offline classifier into a daemon module. For each target page
6
- * it runs a single tool-forced LLM call against the cache-stable numbered leaf
7
- * index (system prompt) with the page content in the user message, maps the
8
- * returned 1-based ids back to leaf paths, and writes back the UNION of the
9
- * page's existing picks and the freshly classified picks.
10
- *
11
- * Recall-safe by construction:
12
- * - UNION semantics never drop a page's existing leaf assignments.
13
- * - A classification that fails (provider unavailable/throws, no tool use, or
14
- * empty result) leaves the page's `leaves:` frontmatter UNCHANGED.
15
- *
16
- * Provider-injectable: pass `opts.provider` to bypass the configured-provider
17
- * lookup (used by tests and callers that force a specific provider). When
18
- * omitted, resolves the `memoryV3RouteL1` callsite provider.
19
- */
20
-
21
- import {
22
- extractToolUse,
23
- getConfiguredProvider,
24
- userMessage,
25
- } from "../../providers/provider-send-message.js";
26
- import type { Provider, ToolDefinition } from "../../providers/types.js";
27
- import { getLogger } from "../../util/logger.js";
28
- import { listPages, readPage, writePage } from "../v2/page-store.js";
29
- import type { ConceptPage } from "../v2/types.js";
30
- import type { LeafPath, LeafTree, Slug } from "./types.js";
31
-
32
- const log = getLogger("memory-v3-assign");
33
-
34
- const ASSIGN_TOOL_NAME = "assign_leaves";
35
-
36
- /** Default delay between classification calls to avoid hammering the provider. */
37
- const DEFAULT_THROTTLE_MS = 200;
38
-
39
- /** Description length cap in the cache-stable leaf index lines. */
40
- const DESCRIPTION_CAP = 450;
41
-
42
- /** Bounded output budget — the tool only emits a small id array. */
43
- const MAX_TOKENS = 512;
44
-
45
- export interface AssignPagesOptions {
46
- /** The leaf tree the page is classified against. */
47
- tree: LeafTree;
48
- /** Workspace root; pages live under `<workspaceDir>/memory/concepts/`. */
49
- workspaceDir: string;
50
- /**
51
- * Slugs to classify. When omitted, defaults to every page whose `leaves:`
52
- * frontmatter is empty or missing (the unclassified set).
53
- */
54
- slugs?: Slug[];
55
- /**
56
- * Provider override. When omitted, resolves the `memoryV3RouteL1` callsite
57
- * provider once and reuses it across all pages.
58
- */
59
- provider?: Provider;
60
- /** Delay between calls in ms. Defaults to {@link DEFAULT_THROTTLE_MS}. */
61
- throttleMs?: number;
62
- }
63
-
64
- /** Per-page classification outcome, for the job + health report to consume. */
65
- export interface AssignPageResult {
66
- slug: Slug;
67
- /** The page's leaf assignments before this run. */
68
- before: LeafPath[];
69
- /** The page's leaf assignments after this run (== before when failed). */
70
- after: LeafPath[];
71
- /** True when classification failed and the page was left unchanged. */
72
- failed: boolean;
73
- }
74
-
75
- /**
76
- * Build the cache-stable system prompt: a numbered list of every leaf path with
77
- * its (trimmed) description. Stable ordering (sorted by path) keeps the prompt
78
- * prefix identical across calls so the provider can cache it.
79
- */
80
- function buildLeafIndexSystemPrompt(
81
- sortedLeafPaths: LeafPath[],
82
- tree: LeafTree,
83
- ): string {
84
- const lines = sortedLeafPaths.map((path, i) => {
85
- const description = tree.leaves.get(path)?.description.trim() ?? "";
86
- const summary = description.slice(0, DESCRIPTION_CAP);
87
- return `[${i + 1}] ${path} — ${summary}`;
88
- });
89
- return [
90
- "You are a memory classifier. Given a page's content, pick the leaf topics",
91
- "the page belongs to. A page may belong to several leaves; pick every leaf",
92
- "whose topic the page meaningfully covers. Return the leaf numbers via the",
93
- "assign_leaves tool.",
94
- "",
95
- "Leaf index:",
96
- ...lines,
97
- ].join("\n");
98
- }
99
-
100
- const ASSIGN_TOOL: ToolDefinition = {
101
- name: ASSIGN_TOOL_NAME,
102
- description: "Return the leaf numbers this page belongs to.",
103
- input_schema: {
104
- type: "object",
105
- properties: {
106
- ids: {
107
- type: "array",
108
- items: { type: "integer" },
109
- },
110
- },
111
- },
112
- };
113
-
114
- /** Map 1-based ids to sorted leaf paths, dropping out-of-range/0/non-integer ids. */
115
- function idsToLeafPaths(ids: unknown, sortedLeafPaths: LeafPath[]): LeafPath[] {
116
- if (!Array.isArray(ids)) return [];
117
- const out: LeafPath[] = [];
118
- for (const id of ids) {
119
- if (typeof id !== "number" || !Number.isInteger(id)) continue;
120
- const idx = id - 1;
121
- if (idx < 0 || idx >= sortedLeafPaths.length) continue;
122
- const leafPath = sortedLeafPaths[idx];
123
- if (!out.includes(leafPath)) out.push(leafPath);
124
- }
125
- return out;
126
- }
127
-
128
- /** Stable union of two leaf-path lists (existing order first, then new). */
129
- function unionLeafPaths(existing: LeafPath[], added: LeafPath[]): LeafPath[] {
130
- const out = [...existing];
131
- for (const leaf of added) {
132
- if (!out.includes(leaf)) out.push(leaf);
133
- }
134
- return out;
135
- }
136
-
137
- /** A page's existing `leaves:` frontmatter, or `[]` when empty/missing. */
138
- function pageLeaves(page: ConceptPage): LeafPath[] {
139
- return page.frontmatter.leaves ?? [];
140
- }
141
-
142
- /** The flat text a page contributes to the classifier user message. */
143
- function pageClassifierInput(page: ConceptPage): string {
144
- const { summary } = page.frontmatter;
145
- return [summary ?? "", page.body]
146
- .filter((s) => s.trim().length > 0)
147
- .join("\n\n");
148
- }
149
-
150
- const sleep = (ms: number): Promise<void> =>
151
- new Promise((resolve) => setTimeout(resolve, ms));
152
-
153
- /**
154
- * Classify pages into leaf topics and UNION the result into each page's
155
- * `leaves:` frontmatter. See the module docstring for the recall-safety
156
- * guarantees.
157
- */
158
- export async function assignPages(
159
- opts: AssignPagesOptions,
160
- ): Promise<AssignPageResult[]> {
161
- const { tree, workspaceDir } = opts;
162
- const throttleMs = opts.throttleMs ?? DEFAULT_THROTTLE_MS;
163
-
164
- const sortedLeafPaths = [...tree.leaves.keys()].sort((a, b) =>
165
- a.localeCompare(b),
166
- );
167
- const systemPrompt = buildLeafIndexSystemPrompt(sortedLeafPaths, tree);
168
-
169
- const targetSlugs = opts.slugs ?? (await unclassifiedSlugs(workspaceDir));
170
-
171
- // Resolve the provider once and reuse it across pages.
172
- const provider =
173
- opts.provider ?? (await getConfiguredProvider("memoryV3RouteL1"));
174
-
175
- const results: AssignPageResult[] = [];
176
- for (let i = 0; i < targetSlugs.length; i++) {
177
- const slug = targetSlugs[i];
178
- const page = await readPage(workspaceDir, slug);
179
- if (!page) {
180
- log.warn({ slug }, "assign: page not found, skipping");
181
- results.push({ slug, before: [], after: [], failed: true });
182
- continue;
183
- }
184
-
185
- const before = pageLeaves(page);
186
-
187
- if (!provider) {
188
- log.warn(
189
- { slug },
190
- "assign: no provider available, leaving page unchanged",
191
- );
192
- results.push({ slug, before, after: before, failed: true });
193
- continue;
194
- }
195
-
196
- const classified = await classifyPage(
197
- provider,
198
- systemPrompt,
199
- pageClassifierInput(page),
200
- sortedLeafPaths,
201
- );
202
-
203
- if (!classified) {
204
- // Non-destructive: leave the page's existing picks untouched.
205
- results.push({ slug, before, after: before, failed: true });
206
- } else {
207
- const after = unionLeafPaths(before, classified);
208
- if (after.length !== before.length) {
209
- await writePage(workspaceDir, {
210
- ...page,
211
- frontmatter: { ...page.frontmatter, leaves: after },
212
- });
213
- }
214
- results.push({ slug, before, after, failed: false });
215
- }
216
-
217
- if (throttleMs > 0 && i < targetSlugs.length - 1) {
218
- await sleep(throttleMs);
219
- }
220
- }
221
-
222
- return results;
223
- }
224
-
225
- /** Pages whose `leaves:` frontmatter is empty or missing — the default targets. */
226
- async function unclassifiedSlugs(workspaceDir: string): Promise<Slug[]> {
227
- const slugs = await listPages(workspaceDir);
228
- const unclassified: Slug[] = [];
229
- for (const slug of slugs) {
230
- const page = await readPage(workspaceDir, slug);
231
- if (page && pageLeaves(page).length === 0) unclassified.push(slug);
232
- }
233
- return unclassified;
234
- }
235
-
236
- /**
237
- * Run a single tool-forced classification call. Returns the classified leaf
238
- * paths, or `null` when the call fails (throws, no tool use, or empty ids) so
239
- * the caller can treat it as non-destructive.
240
- */
241
- async function classifyPage(
242
- provider: Provider,
243
- systemPrompt: string,
244
- pageInput: string,
245
- sortedLeafPaths: LeafPath[],
246
- ): Promise<LeafPath[] | null> {
247
- let response;
248
- try {
249
- response = await provider.sendMessage([userMessage(pageInput)], {
250
- systemPrompt,
251
- tools: [ASSIGN_TOOL],
252
- config: {
253
- callSite: "memoryV3RouteL1",
254
- maxTokens: MAX_TOKENS,
255
- tool_choice: { type: "tool", name: ASSIGN_TOOL_NAME },
256
- },
257
- });
258
- } catch (err) {
259
- log.warn({ err }, "assign: classification provider call failed");
260
- return null;
261
- }
262
-
263
- const toolUse = extractToolUse(response);
264
- if (!toolUse || toolUse.name !== ASSIGN_TOOL_NAME) return null;
265
-
266
- const leafPaths = idsToLeafPaths(toolUse.input.ids, sortedLeafPaths);
267
- return leafPaths.length > 0 ? leafPaths : null;
268
- }
@@ -1,124 +0,0 @@
1
- /**
2
- * Memory v3 — synthetic "capabilities" leaf (skills + `assistant` CLI commands).
3
- *
4
- * v2 surfaces the assistant's invokable capabilities — installed/catalog skills
5
- * and top-level CLI subcommands — by seeding them as synthetic concept-collection
6
- * rows (`skills/<id>`, `cli-commands/<name>`) into the unified router pool, then
7
- * rendering the router-selected ones under `### Skills You Can Use` / `### CLI
8
- * Commands You Can Use`. They are NOT always-injected — they are router-selected
9
- * per turn, same as concept pages.
10
- *
11
- * v3 reproduces that behavior with one always-on leaf:
12
- * - The leaf is synthesized in code (not a `leaves/*.md` data file) and injected
13
- * ONLY into the live lane tree (see `shadow-plugin.ts`). Because the classifier
14
- * builds its own tree without this injection, concept pages are never routed
15
- * INTO the capabilities leaf.
16
- * - Its members are the synthetic skill/CLI slugs, so the BM25 needle indexes
17
- * them for free (the needle corpus is `tree.byPage`).
18
- * - It is added to the always-on core set, so L1 always opens it and the per-leaf
19
- * L2 selects the relevant subset each turn — the semantic equivalent of v2's
20
- * "always in the pool, selected per turn".
21
- *
22
- * Page summaries for synthetic slugs already resolve through the existing
23
- * `pageSummary` lane (the v2 page index appends skill/CLI rows with a summary),
24
- * so only full-content rendering for the live `<memory>` block needs a synthetic
25
- * fallback — see {@link renderCapabilityContent}.
26
- */
27
-
28
- import {
29
- getCliCommandCapability,
30
- isCliCommandSlug,
31
- } from "../v2/cli-command-store.js";
32
- import { getSkillCapability, isSkillSlug } from "../v2/skill-store.js";
33
- import type { LeafNode, LeafPath, LeafTree, Slug } from "./types.js";
34
-
35
- /** Path of the always-on synthetic leaf that owns skill + CLI capability rows. */
36
- export const CAPABILITIES_LEAF_PATH: LeafPath = "capabilities";
37
-
38
- /** L1/needle label for the capabilities leaf. */
39
- export const CAPABILITIES_LEAF_DESCRIPTION =
40
- "Tools the assistant can invoke: installed and available skills, and the " +
41
- "top-level `assistant` CLI subcommands — what the assistant can DO and how " +
42
- "to reach for each capability.";
43
-
44
- /** True iff the slug is a synthetic skill or CLI-command capability row. */
45
- export function isCapabilitySlug(slug: Slug): boolean {
46
- return isSkillSlug(slug) || isCliCommandSlug(slug);
47
- }
48
-
49
- /**
50
- * Inject the synthetic capabilities leaf into a live lane tree: register the leaf
51
- * node with `syntheticSlugs` as members, add the leaf to each member's `byPage`
52
- * entry (UNION — never drops existing leaves), and mark the leaf always-on by
53
- * adding its path to `core`. Mutates `tree` and `core` in place. Idempotent.
54
- *
55
- * Must run BEFORE the needle is built so the synthetic members land in the needle
56
- * corpus (`tree.byPage`).
57
- */
58
- export function injectCapabilitiesLeaf(
59
- tree: LeafTree,
60
- core: Set<LeafPath>,
61
- syntheticSlugs: Slug[],
62
- ): void {
63
- const node: LeafNode = {
64
- path: CAPABILITIES_LEAF_PATH,
65
- frontmatter: { path: CAPABILITIES_LEAF_PATH, in_core: true },
66
- description: CAPABILITIES_LEAF_DESCRIPTION,
67
- members: [...syntheticSlugs],
68
- domain: CAPABILITIES_LEAF_PATH,
69
- };
70
- tree.leaves.set(CAPABILITIES_LEAF_PATH, node);
71
-
72
- for (const slug of syntheticSlugs) {
73
- const existing = tree.byPage.get(slug) ?? [];
74
- if (!existing.includes(CAPABILITIES_LEAF_PATH)) {
75
- tree.byPage.set(slug, [...existing, CAPABILITIES_LEAF_PATH]);
76
- }
77
- }
78
-
79
- // Always-on: L1 always opens it, L2 selects the relevant subset per turn.
80
- core.add(CAPABILITIES_LEAF_PATH);
81
- }
82
-
83
- interface CapabilityEntry {
84
- id: string;
85
- content: string;
86
- }
87
-
88
- export interface CapabilityResolvers {
89
- skill: (idOrSlug: string) => CapabilityEntry | null;
90
- cli: (idOrSlug: string) => CapabilityEntry | null;
91
- }
92
-
93
- const defaultResolvers: CapabilityResolvers = {
94
- skill: getSkillCapability,
95
- cli: getCliCommandCapability,
96
- };
97
-
98
- /**
99
- * Render a synthetic skill/CLI slug's full capability content for the live
100
- * `<memory>` block, mirroring {@link renderV3PageContent}'s `# header\n<content>`
101
- * shape. Returns:
102
- * - the rendered block when the slug is a capability slug and resolves;
103
- * - `""` when it is a capability slug but the cache has no entry (degrade to a
104
- * blank section rather than throwing or falling through to an on-disk read
105
- * that would also miss);
106
- * - `null` when the slug is NOT a capability slug, so the caller falls through
107
- * to its normal on-disk page rendering.
108
- *
109
- * `resolvers` is injectable for tests; production uses the v2 store caches.
110
- */
111
- export function renderCapabilityContent(
112
- slug: Slug,
113
- resolvers: CapabilityResolvers = defaultResolvers,
114
- ): string | null {
115
- if (isSkillSlug(slug)) {
116
- const entry = resolvers.skill(slug);
117
- return entry ? `# Skill: ${entry.id}\n${entry.content}` : "";
118
- }
119
- if (isCliCommandSlug(slug)) {
120
- const entry = resolvers.cli(slug);
121
- return entry ? `# CLI command: ${entry.id}\n${entry.content}` : "";
122
- }
123
- return null;
124
- }
@@ -1,26 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
-
4
- import { LeafPath } from "./types.js";
5
-
6
- /**
7
- * Loads the always-on core leaf set from `<dataDir>/core.json`.
8
- *
9
- * The caller is responsible for resolving `dataDir` (including any
10
- * workspace-local override — see `resolveDataDir` in `tree.ts`). A missing
11
- * `core.json` yields an empty set (new workspaces may have no curated core).
12
- */
13
- export async function loadCore(dataDir: string): Promise<Set<LeafPath>> {
14
- const path = join(dataDir, "core.json");
15
- let raw: string;
16
- try {
17
- raw = await readFile(path, "utf8");
18
- } catch (err) {
19
- if ((err as NodeJS.ErrnoException).code === "ENOENT") {
20
- return new Set();
21
- }
22
- throw err;
23
- }
24
- const parsed = JSON.parse(raw) as { alwaysOn?: LeafPath[] };
25
- return new Set(parsed.alwaysOn ?? []);
26
- }
Binary file