@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091853.fbaa2ae

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 (475) 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 +263 -121
  12. package/package.json +2 -2
  13. package/src/__tests__/activation-early-marking.test.ts +120 -0
  14. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  15. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  16. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  17. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  18. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  19. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  20. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  21. package/src/__tests__/agent-loop.test.ts +441 -96
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  23. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  24. package/src/__tests__/anthropic-provider.test.ts +23 -8
  25. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  26. package/src/__tests__/app-control-flow.test.ts +1 -1
  27. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  28. package/src/__tests__/app-executors.test.ts +132 -0
  29. package/src/__tests__/approval-cascade.test.ts +6 -5
  30. package/src/__tests__/approval-routes-http.test.ts +4 -1
  31. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  32. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  33. package/src/__tests__/channel-approvals.test.ts +1 -1
  34. package/src/__tests__/compaction-circuit.test.ts +258 -0
  35. package/src/__tests__/compaction-direct.test.ts +146 -0
  36. package/src/__tests__/compaction-events.test.ts +7 -7
  37. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  38. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  39. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  40. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  41. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  42. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  43. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  44. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  45. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  46. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  47. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  48. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  49. package/src/__tests__/conversation-error.test.ts +15 -1
  50. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  51. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  52. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  53. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  54. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  55. package/src/__tests__/conversation-queue.test.ts +10 -10
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  57. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  58. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  59. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  60. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  61. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  62. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  64. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  65. package/src/__tests__/conversation-undo.test.ts +2 -2
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  67. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  69. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  70. package/src/__tests__/corrected-target.test.ts +93 -0
  71. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  72. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  73. package/src/__tests__/db-acp-history.test.ts +101 -0
  74. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  75. package/src/__tests__/empty-response-hook.test.ts +1 -1
  76. package/src/__tests__/file-write-tool.test.ts +63 -0
  77. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  78. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  79. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  80. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  81. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  82. package/src/__tests__/heartbeat-service.test.ts +1 -0
  83. package/src/__tests__/history-repair-hook.test.ts +5 -1
  84. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  85. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  86. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  87. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  88. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  89. package/src/__tests__/injector-background-turn.test.ts +13 -23
  90. package/src/__tests__/injector-chain.test.ts +268 -44
  91. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  92. package/src/__tests__/injector-document-comments.test.ts +97 -114
  93. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  94. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  95. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  96. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  97. package/src/__tests__/llm-resolver.test.ts +73 -0
  98. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  99. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  100. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  101. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  102. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  103. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  104. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  105. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  106. package/src/__tests__/plugin-registry.test.ts +3 -49
  107. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  108. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  109. package/src/__tests__/plugin-types.test.ts +0 -70
  110. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  111. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  112. package/src/__tests__/published-app-updater.test.ts +138 -0
  113. package/src/__tests__/reaction-persistence.test.ts +1 -1
  114. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  115. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  116. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  117. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  118. package/src/__tests__/subagent-detail.test.ts +25 -7
  119. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  120. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  121. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  122. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  123. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  124. package/src/__tests__/title-generate-hook.test.ts +5 -1
  125. package/src/__tests__/tool-error-hook.test.ts +1 -1
  126. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  127. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  128. package/src/__tests__/web-fetch.test.ts +45 -0
  129. package/src/acp/__tests__/agent-process.test.ts +161 -0
  130. package/src/acp/__tests__/client-handler.test.ts +40 -0
  131. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  132. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  133. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  134. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  135. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  136. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  137. package/src/acp/agent-process.ts +61 -1
  138. package/src/acp/auto-install.test.ts +280 -0
  139. package/src/acp/auto-install.ts +232 -0
  140. package/src/acp/client-handler.ts +31 -0
  141. package/src/acp/prepare-agent-env.ts +80 -27
  142. package/src/acp/resolve-agent.test.ts +188 -28
  143. package/src/acp/resolve-agent.ts +119 -42
  144. package/src/acp/resume-hint.ts +23 -0
  145. package/src/acp/session-manager.ts +507 -73
  146. package/src/agent/compaction-circuit.ts +60 -102
  147. package/src/agent/loop.ts +403 -251
  148. package/src/api/responses/conversation-message.ts +22 -2
  149. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  150. package/src/approvals/guardian-request-resolvers.ts +27 -1
  151. package/src/background-wake/next-wake.ts +1 -0
  152. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  153. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  154. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  155. package/src/cli/commands/memory-v3.ts +57 -199
  156. package/src/cli/commands/plugins.ts +43 -37
  157. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  158. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  159. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  160. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  161. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  162. package/src/cli/lib/install-from-github.ts +797 -60
  163. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  164. package/src/cli/lib/plugin-details.ts +416 -0
  165. package/src/cli/lib/plugin-marketplace.ts +215 -0
  166. package/src/cli/lib/search-plugins.ts +201 -29
  167. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  168. package/src/config/acp-defaults.test.ts +10 -0
  169. package/src/config/acp-defaults.ts +9 -3
  170. package/src/config/acp-schema.ts +1 -7
  171. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  172. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  173. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  174. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  175. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  176. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  177. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  178. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  179. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  180. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  181. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  182. package/src/config/bundled-tool-registry.ts +4 -0
  183. package/src/config/call-site-defaults.ts +0 -3
  184. package/src/config/feature-flag-registry.json +10 -16
  185. package/src/config/llm-resolver.ts +39 -7
  186. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  187. package/src/config/schemas/call-site-catalog.ts +0 -21
  188. package/src/config/schemas/heartbeat.ts +9 -0
  189. package/src/config/schemas/llm.ts +17 -3
  190. package/src/config/schemas/memory-v3.ts +58 -8
  191. package/src/config/seed-inference-profiles.ts +18 -0
  192. package/src/context/compactor.ts +22 -4
  193. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  194. package/src/context/strip-injections.ts +8 -2
  195. package/src/daemon/conversation-agent-loop-handlers.ts +18 -36
  196. package/src/daemon/conversation-agent-loop.ts +308 -1297
  197. package/src/daemon/conversation-error.ts +31 -4
  198. package/src/daemon/conversation-history.ts +1 -1
  199. package/src/daemon/conversation-lifecycle.ts +11 -255
  200. package/src/daemon/conversation-media-retry.ts +19 -6
  201. package/src/daemon/conversation-messaging.ts +17 -0
  202. package/src/daemon/conversation-process.ts +22 -141
  203. package/src/daemon/conversation-queue-manager.ts +8 -0
  204. package/src/daemon/conversation-registry.ts +159 -0
  205. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  206. package/src/daemon/conversation-store.ts +9 -90
  207. package/src/daemon/conversation-surfaces.ts +165 -11
  208. package/src/daemon/conversation-workspace.ts +17 -0
  209. package/src/daemon/conversation.ts +444 -62
  210. package/src/daemon/disk-pressure-policy.ts +0 -1
  211. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  212. package/src/daemon/handlers/config-channels.ts +11 -2
  213. package/src/daemon/handlers/conversations.ts +3 -1
  214. package/src/daemon/handlers/skills.ts +4 -1
  215. package/src/daemon/host-app-control-proxy.ts +72 -57
  216. package/src/daemon/host-proxy-preactivation.ts +1 -3
  217. package/src/daemon/lifecycle.ts +21 -7
  218. package/src/daemon/persist-unsendable-image.ts +62 -25
  219. package/src/daemon/process-message.ts +1 -1
  220. package/src/daemon/server.ts +2 -0
  221. package/src/daemon/tool-side-effects.ts +15 -0
  222. package/src/daemon/wake-conversation-ops.ts +269 -0
  223. package/src/embedded/plugin-api.ts +2 -2
  224. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  225. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  226. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  227. package/src/heartbeat/heartbeat-service.ts +26 -0
  228. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  229. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  230. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  231. package/src/ipc/skill-routes/memory.ts +4 -2
  232. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  233. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  234. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  235. package/src/memory/activation-session-store.ts +43 -0
  236. package/src/memory/conversation-crud.ts +29 -19
  237. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  238. package/src/memory/db-init.ts +6 -0
  239. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  240. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  241. package/src/memory/jobs-worker.ts +25 -1
  242. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  243. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  244. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  245. package/src/memory/migrations/index.ts +3 -0
  246. package/src/memory/onboarding-events-store.ts +66 -18
  247. package/src/memory/schema/acp.ts +4 -0
  248. package/src/memory/schema/infrastructure.ts +13 -0
  249. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  250. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  251. package/src/memory/v2/consolidation-job.ts +2 -63
  252. package/src/memory/v2/types.ts +5 -0
  253. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  254. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  255. package/src/notifications/access-request-copy.ts +298 -0
  256. package/src/notifications/adapters/slack.ts +3 -3
  257. package/src/notifications/adapters/telegram.ts +9 -2
  258. package/src/notifications/copy-composer.ts +49 -267
  259. package/src/notifications/decision-engine.ts +16 -35
  260. package/src/notifications/home-feed-side-effect.ts +1 -6
  261. package/src/plugin-api/constants.ts +4 -0
  262. package/src/plugin-api/index.ts +40 -11
  263. package/src/plugin-api/types.ts +108 -0
  264. package/src/plugins/defaults/compaction/compact.ts +106 -0
  265. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  266. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  267. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  268. package/src/plugins/defaults/compaction/package.json +1 -2
  269. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  270. package/src/plugins/defaults/empty-response/package.json +0 -1
  271. package/src/plugins/defaults/history-repair/package.json +0 -1
  272. package/src/plugins/defaults/index.ts +156 -26
  273. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  274. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  275. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  276. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  277. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  278. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  279. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  280. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  281. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  282. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  283. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  284. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  285. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  286. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  287. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  288. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  289. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  290. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  291. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  292. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  293. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  294. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  295. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  296. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  297. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  298. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  299. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  300. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  301. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  302. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  303. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  304. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  306. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  307. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  308. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  309. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  310. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  311. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  312. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  313. package/src/plugins/defaults/title-generate/package.json +0 -1
  314. package/src/plugins/defaults/tool-error/package.json +0 -1
  315. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  316. package/src/plugins/external-api.ts +12 -2
  317. package/src/plugins/pipeline.ts +6 -293
  318. package/src/plugins/registry.ts +9 -37
  319. package/src/plugins/types.ts +76 -381
  320. package/src/plugins/user-loader.ts +30 -127
  321. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  322. package/src/prompts/system-prompt.ts +61 -10
  323. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  324. package/src/providers/anthropic/client.ts +9 -10
  325. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  326. package/src/providers/inference/logit-bias.ts +55 -0
  327. package/src/providers/model-catalog.ts +34 -0
  328. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  329. package/src/providers/openai/chat-completions-provider.ts +44 -1
  330. package/src/providers/retry.ts +22 -0
  331. package/src/providers/types.ts +6 -0
  332. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  333. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  334. package/src/runtime/agent-wake.ts +108 -209
  335. package/src/runtime/assistant-event-hub.ts +1 -1
  336. package/src/runtime/channel-approvals.ts +1 -1
  337. package/src/runtime/interactive-ui.ts +1 -1
  338. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  339. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  340. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  341. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  342. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  343. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  344. package/src/runtime/routes/acp-routes.test.ts +185 -32
  345. package/src/runtime/routes/acp-routes.ts +328 -30
  346. package/src/runtime/routes/app-management-routes.ts +3 -0
  347. package/src/runtime/routes/approval-routes.ts +1 -1
  348. package/src/runtime/routes/browser-routes.ts +1 -1
  349. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  350. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  351. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  352. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  354. package/src/runtime/routes/conversation-routes.ts +30 -2
  355. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  356. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  357. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  358. package/src/runtime/routes/host-cu-routes.ts +1 -1
  359. package/src/runtime/routes/identity-routes.ts +18 -3
  360. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  361. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  362. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  363. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  364. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  365. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  366. package/src/runtime/routes/playground/helpers.ts +1 -1
  367. package/src/runtime/routes/plugins-routes.ts +337 -35
  368. package/src/runtime/routes/stt-routes.ts +45 -12
  369. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  370. package/src/runtime/routes/work-items-routes.ts +2 -4
  371. package/src/runtime/routes/workspace-routes.ts +50 -15
  372. package/src/runtime/services/conversation-serializer.ts +1 -1
  373. package/src/runtime/verification-outbound-actions.ts +147 -2
  374. package/src/runtime/verification-templates.ts +29 -3
  375. package/src/services/published-app-updater.ts +30 -8
  376. package/src/signals/cancel.ts +2 -4
  377. package/src/subagent/manager.ts +21 -5
  378. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  379. package/src/telemetry/activation-funnel.ts +167 -0
  380. package/src/telemetry/types.ts +13 -0
  381. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  382. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  383. package/src/tools/acp/context.ts +20 -0
  384. package/src/tools/acp/list-agents.test.ts +9 -19
  385. package/src/tools/acp/list-agents.ts +3 -15
  386. package/src/tools/acp/spawn.test.ts +173 -202
  387. package/src/tools/acp/spawn.ts +37 -172
  388. package/src/tools/acp/steer.test.ts +105 -8
  389. package/src/tools/acp/steer.ts +48 -17
  390. package/src/tools/apps/executors.ts +166 -50
  391. package/src/tools/browser/browser-execution.ts +12 -2
  392. package/src/tools/filesystem/write.ts +34 -0
  393. package/src/tools/network/web-fetch.ts +65 -24
  394. package/src/tools/skills/load.ts +1 -1
  395. package/src/tools/subagent/spawn.ts +2 -4
  396. package/src/tools/ui-surface/definitions.ts +32 -5
  397. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  398. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  399. package/docs/plugins.md +0 -832
  400. package/examples/plugins/echo/register.ts +0 -143
  401. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  402. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  403. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  404. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  405. package/src/__tests__/pipeline-runner.test.ts +0 -554
  406. package/src/daemon/wake-target-adapter.ts +0 -253
  407. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  408. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  409. package/src/memory/v3/__tests__/core.test.ts +0 -39
  410. package/src/memory/v3/__tests__/health.test.ts +0 -219
  411. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  412. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  413. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  414. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  415. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  416. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  417. package/src/memory/v3/__tests__/router.test.ts +0 -332
  418. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  419. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  420. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  421. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  422. package/src/memory/v3/assign.ts +0 -268
  423. package/src/memory/v3/capabilities.ts +0 -124
  424. package/src/memory/v3/core.ts +0 -26
  425. package/src/memory/v3/health.ts +0 -0
  426. package/src/memory/v3/maintain-job.ts +0 -314
  427. package/src/memory/v3/needle.ts +0 -115
  428. package/src/memory/v3/orchestrate.ts +0 -126
  429. package/src/memory/v3/page-content.ts +0 -34
  430. package/src/memory/v3/provider-blocks.ts +0 -26
  431. package/src/memory/v3/reconcile.ts +0 -523
  432. package/src/memory/v3/router.ts +0 -190
  433. package/src/memory/v3/selection-log-store.ts +0 -84
  434. package/src/memory/v3/selector.ts +0 -226
  435. package/src/memory/v3/shadow-plugin.ts +0 -411
  436. package/src/memory/v3/snapshot.ts +0 -209
  437. package/src/memory/v3/tree.ts +0 -174
  438. package/src/memory/v3/types.ts +0 -59
  439. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  440. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  441. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  442. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  443. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  444. package/src/plugins/defaults/compaction/register.ts +0 -35
  445. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  446. package/src/plugins/defaults/empty-response/register.ts +0 -23
  447. package/src/plugins/defaults/history-repair/register.ts +0 -24
  448. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  449. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  450. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  451. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  452. package/src/plugins/defaults/title-generate/register.ts +0 -35
  453. package/src/plugins/defaults/tool-error/register.ts +0 -23
  454. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  455. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  456. package/src/proactive-artifact/decision.test.ts +0 -226
  457. package/src/proactive-artifact/decision.ts +0 -165
  458. package/src/proactive-artifact/index.ts +0 -7
  459. package/src/proactive-artifact/job.test.ts +0 -962
  460. package/src/proactive-artifact/job.ts +0 -372
  461. package/src/proactive-artifact/message-copy.ts +0 -58
  462. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  463. package/src/proactive-artifact/trigger-state.ts +0 -123
  464. package/src/util/map-limit.ts +0 -27
  465. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  466. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  467. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  468. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  469. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  470. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  471. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  472. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  473. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  474. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  475. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -1,314 +0,0 @@
1
- /**
2
- * Memory v3 — `memory_v3_maintain` job handler.
3
- *
4
- * A flag-gated, best-effort self-maintenance pass over the v3 topic tree and
5
- * its page→leaf assignments. It runs three independent stages, in order:
6
- *
7
- * 1. **Classify-union** — `assignPages` over the delta: every page that is
8
- * still unassigned (empty `leaves:`) plus every page edited since the last
9
- * successful pass (the high-water mark below), UNIONing freshly classified
10
- * leaves into each page (never dropping existing picks). Re-touching
11
- * already-assigned-but-recently-edited pages lets the classifier enrich the
12
- * assistant's own in-consolidation labels with any leaves it missed.
13
- * 2. **Prune** — drop any frontmatter `leaves:` entry that points at a leaf
14
- * path no longer present in the tree (dangling references left behind when
15
- * a leaf is renamed or removed). Read + rewrite only the affected pages.
16
- * 3. **Needle rebuild** — `invalidateLanes()` so the next turn rebuilds the
17
- * leaf tree and BM25 needle from the freshly-updated assignments.
18
- *
19
- * Best-effort by construction: each stage is wrapped so a failure in one is
20
- * logged and recorded in the outcome but does NOT abort the others. The job is
21
- * a no-op (returns a disabled outcome) unless `memory-v3-shadow` OR
22
- * `memory-v3-live` is enabled — the same flags that gate the v3 plugin.
23
- *
24
- * Dependency-injectable: `deps` lets tests substitute the tree loader,
25
- * `assignPages`, and `invalidateLanes` without process-global module mocks.
26
- */
27
-
28
- import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
29
- import type { AssistantConfig } from "../../config/types.js";
30
- import { getLogger } from "../../util/logger.js";
31
- import { getWorkspaceDir } from "../../util/platform.js";
32
- import { getMemoryCheckpoint, setMemoryCheckpoint } from "../checkpoints.js";
33
- import type { MemoryJob } from "../jobs-store.js";
34
- import { getPageIndex } from "../v2/page-index.js";
35
- import { listPages, readPage, writePage } from "../v2/page-store.js";
36
- import { assignPages as realAssignPages } from "./assign.js";
37
- import { invalidateLanes as realInvalidateLanes } from "./shadow-plugin.js";
38
- import { loadLeafTree as realLoadLeafTree, resolveDataDir } from "./tree.js";
39
- import type { LeafPath, LeafTree, Slug } from "./types.js";
40
-
41
- const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
42
- const MEMORY_V3_LIVE = "memory-v3-live" as const;
43
-
44
- /**
45
- * Durable checkpoint holding the epoch-ms high-water mark of the last successful
46
- * classify-union pass. Pages whose mtime is past this mark are re-classified
47
- * (enrichment); the mark is advanced only after a pass completes, captured after
48
- * its writes so the pass's own frontmatter rewrites do not re-trigger it.
49
- * Distinct from `memory_v3_maintain_last_run` (the enqueue-cadence checkpoint in
50
- * `jobs-worker.ts`), which advances on every backstop enqueue rather than on an
51
- * actual maintenance run.
52
- */
53
- const MAINTAIN_ENRICH_HIGH_WATER_KEY =
54
- "memory_v3_maintain:enriched_through_ms" as const;
55
-
56
- const log = getLogger("memory-v3-maintain");
57
-
58
- /** Injectable collaborators; defaults wire the real implementations. */
59
- export interface MaintainJobDeps {
60
- /** Load the v3 leaf tree (page→leaf membership resolved from frontmatter). */
61
- loadTree: () => Promise<LeafTree>;
62
- /** Classify-union pass over pages. */
63
- assignPages: typeof realAssignPages;
64
- /**
65
- * The slugs to classify this pass: unassigned pages plus pages edited since
66
- * the last successful pass. See {@link computeClassifyTargets}.
67
- */
68
- selectClassifyTargets: () => Promise<Slug[]>;
69
- /**
70
- * Persist the enrichment high-water mark after a successful classify pass. The
71
- * value is captured after the pass's writes (see the key docstring).
72
- */
73
- commitClassifyHighWater: (highWaterMs: number) => void;
74
- /** Drop the memoized v3 lanes so the next turn rebuilds tree + needle. */
75
- invalidateLanes: () => void;
76
- /** Workspace root; pages live under `<workspaceDir>/memory/concepts/`. */
77
- workspaceDir: string;
78
- }
79
-
80
- /** Per-stage outcome surfaced in the structured log line. */
81
- export interface MaintainOutcome {
82
- /** True when both v3 flags were off and the job no-opped. */
83
- disabled: boolean;
84
- /** Pages newly assigned by the classify-union stage. */
85
- assigned: number;
86
- /** Pages whose dangling refs were pruned. */
87
- pruned: number;
88
- /** Dangling leaf references dropped across all pruned pages. */
89
- prunedRefs: number;
90
- /** Whether the needle/tree lanes were invalidated. */
91
- invalidated: boolean;
92
- /** Stages that threw (and were contained). */
93
- failures: string[];
94
- }
95
-
96
- /**
97
- * Load the v3 leaf tree the same way the live plugin does: resolve the data
98
- * dir, build the page→leaf membership map from the page index frontmatter, and
99
- * hand both to `loadLeafTree`.
100
- */
101
- async function loadTreeFromWorkspace(workspaceDir: string): Promise<LeafTree> {
102
- const pageIndex = await getPageIndex(workspaceDir);
103
- const pageLeaves = new Map<Slug, LeafPath[]>();
104
- for (const entry of pageIndex.entries) {
105
- pageLeaves.set(entry.slug, entry.leaves);
106
- }
107
- return realLoadLeafTree(resolveDataDir(), pageLeaves);
108
- }
109
-
110
- /** Page-index projection the classify-target selector reads. */
111
- export interface ClassifyCandidate {
112
- slug: Slug;
113
- /** File mtime in epoch ms; 0 for synthetic skill/CLI rows (excluded). */
114
- modifiedAt: number;
115
- /** Leaf assignments from frontmatter; `[]` when unassigned. */
116
- leaves: LeafPath[];
117
- }
118
-
119
- /**
120
- * Pick the pages the classify-union stage should run this pass:
121
- *
122
- * - **Unassigned** pages (empty `leaves:`) — always classified so a page is
123
- * never left permanently unrouted (the pre-enrichment behavior).
124
- * - **Recently edited** pages (mtime past `prevHighWaterMs`) — even when
125
- * already assigned, so the classifier can enrich the assistant's own
126
- * in-consolidation labels with leaves it missed. `assignPages` UNIONs, so a
127
- * page's existing picks are never dropped — only added to.
128
- *
129
- * Synthetic skill/CLI rows (`modifiedAt === 0`) are excluded: they are
130
- * capability entries, not topic-tree pages. On the first run (`prevHighWaterMs`
131
- * null) the recency arm is disabled, so a fresh or freshly-backfilled install
132
- * does a single unassigned-only pass instead of re-classifying the whole corpus.
133
- */
134
- export function computeClassifyTargets(
135
- pages: ReadonlyArray<ClassifyCandidate>,
136
- prevHighWaterMs: number | null,
137
- ): Slug[] {
138
- const targets: Slug[] = [];
139
- for (const page of pages) {
140
- if (page.modifiedAt <= 0) continue; // synthetic capability row
141
- const unassigned = page.leaves.length === 0;
142
- const recentlyEdited =
143
- prevHighWaterMs !== null && page.modifiedAt > prevHighWaterMs;
144
- if (unassigned || recentlyEdited) targets.push(page.slug);
145
- }
146
- return targets;
147
- }
148
-
149
- /** Read the persisted high-water mark, treating missing/garbage as first-run. */
150
- function readClassifyHighWater(): number | null {
151
- const raw = getMemoryCheckpoint(MAINTAIN_ENRICH_HIGH_WATER_KEY);
152
- if (raw === null) return null;
153
- const parsed = Number.parseInt(raw, 10);
154
- return Number.isNaN(parsed) ? null : parsed;
155
- }
156
-
157
- /** Default target selector: page index → {@link computeClassifyTargets}. */
158
- async function selectClassifyTargetsFromWorkspace(
159
- workspaceDir: string,
160
- ): Promise<Slug[]> {
161
- const index = await getPageIndex(workspaceDir);
162
- return computeClassifyTargets(index.entries, readClassifyHighWater());
163
- }
164
-
165
- function commitClassifyHighWater(highWaterMs: number): void {
166
- setMemoryCheckpoint(MAINTAIN_ENRICH_HIGH_WATER_KEY, String(highWaterMs));
167
- }
168
-
169
- function defaultDeps(): MaintainJobDeps {
170
- const workspaceDir = getWorkspaceDir();
171
- return {
172
- loadTree: () => loadTreeFromWorkspace(workspaceDir),
173
- assignPages: realAssignPages,
174
- selectClassifyTargets: () =>
175
- selectClassifyTargetsFromWorkspace(workspaceDir),
176
- commitClassifyHighWater,
177
- invalidateLanes: realInvalidateLanes,
178
- workspaceDir,
179
- };
180
- }
181
-
182
- /**
183
- * Prune dangling `leaves:` references: for every page, drop frontmatter leaf
184
- * paths that are not present in `tree`. Read + rewrite only pages that actually
185
- * change. Returns the number of pages rewritten and total refs dropped.
186
- */
187
- async function prunePages(
188
- tree: LeafTree,
189
- workspaceDir: string,
190
- ): Promise<{ pruned: number; prunedRefs: number }> {
191
- const validLeaves = tree.leaves;
192
- const slugs = await listPages(workspaceDir);
193
- let pruned = 0;
194
- let prunedRefs = 0;
195
- for (const slug of slugs) {
196
- const page = await readPage(workspaceDir, slug);
197
- const leaves = page?.frontmatter.leaves;
198
- if (!page || !leaves || leaves.length === 0) continue;
199
- const kept = leaves.filter((leaf) => validLeaves.has(leaf));
200
- if (kept.length === leaves.length) continue;
201
- prunedRefs += leaves.length - kept.length;
202
- pruned += 1;
203
- await writePage(workspaceDir, {
204
- ...page,
205
- frontmatter: { ...page.frontmatter, leaves: kept },
206
- });
207
- }
208
- return { pruned, prunedRefs };
209
- }
210
-
211
- /**
212
- * Run the v3 self-maintenance pass. Each stage is independently contained: a
213
- * thrown error is logged and recorded in `failures` without aborting the rest.
214
- * No-ops when both v3 flags are off.
215
- */
216
- export async function maintainJob(
217
- _job: MemoryJob,
218
- config: AssistantConfig,
219
- deps: MaintainJobDeps = defaultDeps(),
220
- ): Promise<MaintainOutcome> {
221
- const outcome: MaintainOutcome = {
222
- disabled: false,
223
- assigned: 0,
224
- pruned: 0,
225
- prunedRefs: 0,
226
- invalidated: false,
227
- failures: [],
228
- };
229
-
230
- const enabled =
231
- isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config) ||
232
- isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config);
233
- if (!enabled) {
234
- outcome.disabled = true;
235
- return outcome;
236
- }
237
-
238
- // The tree is shared input for both the assign and prune stages. If it can't
239
- // load, those two stages are skipped (recorded as a failure), but we still
240
- // invalidate the lanes so a transient load error doesn't wedge the next turn.
241
- let tree: LeafTree | null = null;
242
- try {
243
- tree = await deps.loadTree();
244
- } catch (err) {
245
- outcome.failures.push("load_tree");
246
- log.warn(
247
- { err: err instanceof Error ? err.message : String(err) },
248
- "memory-v3 maintain: tree load failed (non-fatal)",
249
- );
250
- }
251
-
252
- if (tree) {
253
- // Stage 1: classify-union over the delta (unassigned ∪ recently-edited).
254
- try {
255
- const targets = await deps.selectClassifyTargets();
256
- const results = await deps.assignPages({
257
- tree,
258
- workspaceDir: deps.workspaceDir,
259
- slugs: targets,
260
- });
261
- outcome.assigned = results.filter(
262
- (r) => !r.failed && r.after.length > r.before.length,
263
- ).length;
264
- // Advance the high-water mark only on success, captured AFTER the writes
265
- // above so pages this pass just rewrote (mtime now bumped) sit at-or-below
266
- // the mark and do not re-trigger themselves next pass.
267
- deps.commitClassifyHighWater(Date.now());
268
- } catch (err) {
269
- outcome.failures.push("assign");
270
- log.warn(
271
- { err: err instanceof Error ? err.message : String(err) },
272
- "memory-v3 maintain: classify-union failed (non-fatal)",
273
- );
274
- }
275
-
276
- // Stage 2: prune dangling refs.
277
- try {
278
- const { pruned, prunedRefs } = await prunePages(tree, deps.workspaceDir);
279
- outcome.pruned = pruned;
280
- outcome.prunedRefs = prunedRefs;
281
- } catch (err) {
282
- outcome.failures.push("prune");
283
- log.warn(
284
- { err: err instanceof Error ? err.message : String(err) },
285
- "memory-v3 maintain: prune failed (non-fatal)",
286
- );
287
- }
288
- }
289
-
290
- // Stage 3: rebuild tree + needle on the next turn.
291
- try {
292
- deps.invalidateLanes();
293
- outcome.invalidated = true;
294
- } catch (err) {
295
- outcome.failures.push("invalidate");
296
- log.warn(
297
- { err: err instanceof Error ? err.message : String(err) },
298
- "memory-v3 maintain: lane invalidation failed (non-fatal)",
299
- );
300
- }
301
-
302
- log.info(
303
- {
304
- assigned: outcome.assigned,
305
- pruned: outcome.pruned,
306
- prunedRefs: outcome.prunedRefs,
307
- invalidated: outcome.invalidated,
308
- failures: outcome.failures,
309
- },
310
- "memory-v3 maintain pass complete",
311
- );
312
-
313
- return outcome;
314
- }
@@ -1,115 +0,0 @@
1
- import type { LeafTree, Slug } from "./types.js";
2
-
3
- /**
4
- * Sparse "needle" arm for memory-v3 routing: a lexical BM25 search over page
5
- * titles, slug tokens, summaries, and the labels of the leaves each page
6
- * belongs to. It augments topical (tree) routing by surfacing pages that share
7
- * a literal term with the query even when topical routing would miss them.
8
- *
9
- * Implementation notes:
10
- * - Hand-rolled Okapi BM25 (no dependency). The corpus is bounded (one doc per
11
- * page), so a plain inverted index is plenty.
12
- * - The index is built once and held in memory. The orchestrator/plugin
13
- * lazy-inits it. Rebuilding on consolidation is a documented fast-follow and
14
- * intentionally out of scope here.
15
- */
16
-
17
- /** Okapi BM25 term-frequency saturation parameter. */
18
- export const k1 = 1.5;
19
- /** Okapi BM25 length-normalization parameter. */
20
- export const b = 0.75;
21
-
22
- export interface NeedleIndex {
23
- /** Returns up to `k` slugs ranked by BM25 score (descending, ties by slug). */
24
- query(text: string, k: number): Slug[];
25
- }
26
-
27
- /** Lowercase, split on non-alphanumeric, drop empties. */
28
- function tokenize(text: string): string[] {
29
- return text
30
- .toLowerCase()
31
- .split(/[^a-z0-9]+/)
32
- .filter((token) => token.length > 0);
33
- }
34
-
35
- interface Posting {
36
- doc: number;
37
- tf: number;
38
- }
39
-
40
- export async function buildNeedleIndex(
41
- tree: LeafTree,
42
- pageSummary: (slug: Slug) => Promise<string>,
43
- ): Promise<NeedleIndex> {
44
- const slugs: Slug[] = [...tree.byPage.keys()];
45
-
46
- // term -> postings (doc index + term frequency in that doc)
47
- const postings = new Map<string, Posting[]>();
48
- const docLengths: number[] = new Array(slugs.length).fill(0);
49
- let totalLength = 0;
50
-
51
- for (let doc = 0; doc < slugs.length; doc++) {
52
- const slug = slugs[doc]!;
53
-
54
- // Title = last path segment of the slug; also index the slug tokens.
55
- const segments = slug.split(/[/.]/);
56
- const title = segments[segments.length - 1] ?? "";
57
-
58
- const parts: string[] = [title, slug, await pageSummary(slug)];
59
-
60
- for (const leafPath of tree.byPage.get(slug) ?? []) {
61
- const leaf = tree.leaves.get(leafPath);
62
- if (leaf) parts.push(leaf.description);
63
- }
64
-
65
- const tokens = tokenize(parts.join(" "));
66
- docLengths[doc] = tokens.length;
67
- totalLength += tokens.length;
68
-
69
- const termFreqs = new Map<string, number>();
70
- for (const token of tokens) {
71
- termFreqs.set(token, (termFreqs.get(token) ?? 0) + 1);
72
- }
73
- for (const [term, tf] of termFreqs) {
74
- let list = postings.get(term);
75
- if (!list) {
76
- list = [];
77
- postings.set(term, list);
78
- }
79
- list.push({ doc, tf });
80
- }
81
- }
82
-
83
- const docCount = slugs.length;
84
- const avgDocLength = docCount > 0 ? totalLength / docCount : 0;
85
-
86
- function query(text: string, k: number): Slug[] {
87
- if (k <= 0 || docCount === 0) return [];
88
-
89
- const queryTerms = new Set(tokenize(text));
90
- const scores = new Map<number, number>();
91
-
92
- // O(query-terms x matching-docs): walk only the postings of query terms.
93
- for (const term of queryTerms) {
94
- const list = postings.get(term);
95
- if (!list) continue;
96
-
97
- const idf = Math.log(
98
- 1 + (docCount - list.length + 0.5) / (list.length + 0.5),
99
- );
100
-
101
- for (const { doc, tf } of list) {
102
- const norm = tf * (k1 + 1);
103
- const denom = tf + k1 * (1 - b + b * (docLengths[doc]! / avgDocLength));
104
- scores.set(doc, (scores.get(doc) ?? 0) + idf * (norm / denom));
105
- }
106
- }
107
-
108
- return [...scores.entries()]
109
- .sort((a, c) => c[1] - a[1] || slugs[a[0]]!.localeCompare(slugs[c[0]]!))
110
- .slice(0, k)
111
- .map(([doc]) => slugs[doc]!);
112
- }
113
-
114
- return { query };
115
- }
@@ -1,126 +0,0 @@
1
- /**
2
- * Memory v3 — orchestrator composing the four routing lanes into one turn.
3
- *
4
- * Each turn runs:
5
- * 1. L1 topical routing (`routeL1`) and the lexical BM25 needle
6
- * (`NeedleIndex.query`) IN PARALLEL. Routing is the slow LLM arm; the
7
- * needle is a synchronous in-memory lookup, so we wrap it in a resolved
8
- * promise and let them settle together.
9
- * 2. Open set = unique union of routed leaves ∪ always-on core leaves ∪ the
10
- * leaves that own each needle hit. Every lane only ever ADDS leaves — the
11
- * union is recall-safe by construction.
12
- * 3. Bounded per-leaf L2 selection (`selectAcrossLeaves`) over the open set,
13
- * then dedup by slug (a page assigned to multiple opened leaves comes back
14
- * once per leaf) ORing the pinned flag so a page pinned anywhere stays
15
- * pinned.
16
- * 4. Age the carry-forward working set to this turn (evict core slugs, stale
17
- * non-pinned entries, then the cap) and snapshot it — the pages carried in
18
- * from EARLIER turns.
19
- * 5. Final injection = unique union of this turn's selected slugs and that
20
- * carried-forward set, so pages selected on earlier turns carry forward
21
- * even when this turn does not re-select them.
22
- * 6. Record this turn's selections into the working set for LATER turns. This
23
- * runs AFTER the snapshot so the cap is spent on genuinely carried pages,
24
- * not on this turn's selections (which are injected directly) — otherwise a
25
- * turn selecting more pages than the cap would evict the entire carry.
26
- */
27
-
28
- import type { NeedleIndex } from "./needle.js";
29
- import { routeL1 } from "./router.js";
30
- import type { SelectedPage } from "./selector.js";
31
- import { selectAcrossLeaves } from "./selector.js";
32
- import { coreSlugs, leavesOf } from "./tree.js";
33
- import type { LeafPath, LeafTree, Slug, TurnContext } from "./types.js";
34
- import { WorkingSet } from "./working-set.js";
35
-
36
- /** Default number of needle hits to fold into the open set when unspecified. */
37
- export const DEFAULT_NEEDLE_K = 10;
38
-
39
- export interface OrchestrateDeps {
40
- tree: LeafTree;
41
- core: Set<LeafPath>;
42
- needle: NeedleIndex;
43
- workingSet: WorkingSet;
44
- pageSummary: (slug: Slug) => Promise<string>;
45
- /** Number of BM25 needle hits to fold in. Defaults to {@link DEFAULT_NEEDLE_K}. */
46
- needleK?: number;
47
- /** Bounded fan-out for per-leaf L2 selection. */
48
- l2Concurrency?: number;
49
- }
50
-
51
- export interface OrchestrateResult {
52
- /** The unique open set: routed ∪ core ∪ needle-owning leaves. */
53
- openedLeaves: LeafPath[];
54
- /** This turn's L2 selections, deduped by slug (pinned flags ORed). */
55
- currentSelections: SelectedPage[];
56
- /** The carried-forward set: selections from EARLIER turns, aged to this turn
57
- * (snapshotted before this turn's selections are recorded). */
58
- workingSetUnion: Set<Slug>;
59
- /** Slugs to inject: this turn's selections ∪ the carried-forward working set. */
60
- finalInjection: Slug[];
61
- }
62
-
63
- /** Stable-order de-duplication preserving first occurrence. */
64
- function unique<T>(items: Iterable<T>): T[] {
65
- return [...new Set(items)];
66
- }
67
-
68
- export async function orchestrate(
69
- turn: TurnContext,
70
- deps: OrchestrateDeps,
71
- ): Promise<OrchestrateResult> {
72
- // Step 1: routing (LLM) and needle (sync BM25) run in parallel.
73
- const needleK = deps.needleK ?? DEFAULT_NEEDLE_K;
74
- const [routed, needled] = await Promise.all([
75
- routeL1(turn, deps.tree),
76
- Promise.resolve(deps.needle.query(turn.currentMessage, needleK)),
77
- ]);
78
-
79
- // Step 2: open set = routed ∪ core ∪ leaves owning each needle hit.
80
- const openedLeaves = unique<LeafPath>([
81
- ...routed,
82
- ...deps.core,
83
- ...needled.flatMap((slug) => leavesOf(deps.tree, slug)),
84
- ]);
85
-
86
- // Step 3: per-leaf L2 selection, then dedup by slug ORing pinned flags.
87
- const selected = await selectAcrossLeaves(
88
- openedLeaves,
89
- turn,
90
- deps.tree,
91
- deps.pageSummary,
92
- deps.l2Concurrency,
93
- );
94
- const bySlug = new Map<Slug, SelectedPage>();
95
- for (const page of selected) {
96
- const existing = bySlug.get(page.slug);
97
- bySlug.set(page.slug, {
98
- slug: page.slug,
99
- pinned: (existing?.pinned ?? false) || page.pinned,
100
- });
101
- }
102
- const currentSelections = [...bySlug.values()];
103
-
104
- // Step 4: age the carry-forward set to this turn (drop core slugs, stale
105
- // non-pinned entries, then the cap) and snapshot it. This is the set carried
106
- // in from EARLIER turns; recording this turn happens afterward (step 6) so the
107
- // cap is spent on genuinely carried pages, not on this turn's selections
108
- // (which are injected directly anyway).
109
- deps.workingSet.evict(turn.turnNumber, coreSlugs(deps.tree, deps.core));
110
- const workingSetUnion = deps.workingSet.union();
111
-
112
- // Step 5: final injection = this turn's selections ∪ the carried-forward set,
113
- // so pages selected on earlier turns carry forward even when this turn does
114
- // not re-select them.
115
- const finalInjection = unique<Slug>([
116
- ...currentSelections.map((s) => s.slug),
117
- ...workingSetUnion,
118
- ]);
119
-
120
- // Step 6: record this turn's selections so they carry forward to LATER turns.
121
- for (const sel of currentSelections) {
122
- deps.workingSet.recordSelection(sel.slug, turn.turnNumber, sel.pinned);
123
- }
124
-
125
- return { openedLeaves, currentSelections, workingSetUnion, finalInjection };
126
- }
@@ -1,34 +0,0 @@
1
- import { getWorkspaceDir } from "../../util/platform.js";
2
- import { readPage, renderPageContent } from "../v2/page-store.js";
3
- import { renderCapabilityContent } from "./capabilities.js";
4
- import type { Slug } from "./types.js";
5
-
6
- /**
7
- * Render a selected page's full content for the v3 `<memory>` block. Mirrors
8
- * the v2 dynamic-memory layout (`# memory/concepts/<slug>.md\n<frontmatter+body>`)
9
- * so the working-set block reads like v2's. A missing page (or any read
10
- * failure) degrades to "" — `renderMemoryBlock` still emits a line for the
11
- * slug, and a blank section is preferable to throwing into the turn.
12
- *
13
- * Synthetic capability slugs (skills, `assistant` CLI commands) have no on-disk
14
- * page; they resolve through {@link renderCapabilityContent} instead of
15
- * `readPage`. A non-null result (including "") means the slug was a capability
16
- * slug and was handled here.
17
- *
18
- * Shared by the live injector (`shadow-plugin.ts`) and the inspector
19
- * selection-log store (`selection-log-store.ts`) so the inspector's rendered
20
- * block is byte-identical to what live injection produces.
21
- */
22
- export async function renderV3PageContent(slug: Slug): Promise<string> {
23
- const capability = renderCapabilityContent(slug);
24
- if (capability !== null) return capability;
25
- try {
26
- const page = await readPage(getWorkspaceDir(), slug);
27
- if (!page) return "";
28
- const content = renderPageContent(page).trim();
29
- if (content.length === 0) return "";
30
- return `# memory/concepts/${slug}.md\n${content}`;
31
- } catch {
32
- return "";
33
- }
34
- }
@@ -1,26 +0,0 @@
1
- import type { ContentBlock } from "../../providers/types.js";
2
-
3
- /**
4
- * Text content block carrying a `cache_control` breakpoint with a 1-hour TTL.
5
- * Shared by the v3 router (the static leaf-tree block) and selector (each
6
- * leaf's static `<pages>` block): these prefixes are stable across turns — the
7
- * leaf tree is byte-identical every turn, and a leaf's pages block changes only
8
- * when its pages/summaries do — while v3 turns are frequently more than the
9
- * default 5-minute cache window apart. A 1h TTL keeps the prefix warm across
10
- * those gaps so it is read from cache rather than re-created every turn; the
11
- * volatile current-message block is rendered after this one and left un-cached.
12
- * Haiku does not support the extended-cache-ttl beta, so the Anthropic provider
13
- * strips this `ttl` for Haiku models.
14
- *
15
- * Our internal `TextContent` type omits `cache_control` (only the Anthropic
16
- * provider transforms it onto the wire), so we reach through a `Record` cast to
17
- * keep the core types provider-agnostic.
18
- */
19
- export function cachedTextBlock(text: string): ContentBlock {
20
- const block: ContentBlock = { type: "text", text };
21
- (block as unknown as Record<string, unknown>).cache_control = {
22
- type: "ephemeral",
23
- ttl: "1h",
24
- };
25
- return block;
26
- }