@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,253 +0,0 @@
1
- /**
2
- * Adapter that wraps a live {@link Conversation} as a {@link WakeTarget}
3
- * for `wakeAgentForOpportunity()`.
4
- *
5
- * Extracted from `server.ts` so that `runtime/agent-wake.ts` can import
6
- * the resolver directly instead of going through a DI callback registered
7
- * at daemon startup.
8
- */
9
-
10
- import type { AgentEvent } from "../agent/loop.js";
11
- import {
12
- addMessage,
13
- getConversation,
14
- provenanceFromTrustContext,
15
- } from "../memory/conversation-crud.js";
16
- import { syncMessageToDisk } from "../memory/conversation-disk-view.js";
17
- import { backfillMessageIdOnLogs } from "../memory/llm-request-log-store.js";
18
- import type { WakeTarget } from "../runtime/agent-wake.js";
19
- import { broadcastMessage } from "../runtime/assistant-event-hub.js";
20
- import { getLogger } from "../util/logger.js";
21
- import type { Conversation } from "./conversation.js";
22
- import type { ServerMessage } from "./message-protocol.js";
23
-
24
- const log = getLogger("wake-target-adapter");
25
-
26
- /**
27
- * Translate a raw {@link AgentEvent} from the agent loop into the
28
- * corresponding {@link ServerMessage} wire frame. The normal user-turn
29
- * path does this via the full state-aware handler in
30
- * `conversation-agent-loop-handlers.ts`; the wake path has no tool
31
- * accounting, title generation, or activity-state tracking to worry
32
- * about, so we only need the subset that produces client-visible
33
- * frames. Events that have no client-visible wire shape (usage, error,
34
- * preview/input-json deltas, etc.) are dropped — they produce no UI.
35
- *
36
- * Keeping this translator co-located with the wake adapter preserves
37
- * the runtime/daemon layering: `runtime/agent-wake.ts` never imports
38
- * `message-protocol.ts` or wire shapes, and the daemon owns all
39
- * translation from agent-loop semantics to client frames.
40
- */
41
- function translateAgentEventToServerMessage(
42
- event: AgentEvent,
43
- conversationId: string,
44
- ): ServerMessage | null {
45
- switch (event.type) {
46
- case "text_delta":
47
- return {
48
- type: "assistant_text_delta",
49
- text: event.text,
50
- conversationId,
51
- };
52
- case "thinking_delta":
53
- return {
54
- type: "assistant_thinking_delta",
55
- thinking: event.thinking,
56
- conversationId,
57
- };
58
- case "tool_use":
59
- return {
60
- type: "tool_use_start",
61
- toolName: event.name,
62
- input: event.input,
63
- conversationId,
64
- toolUseId: event.id,
65
- };
66
- case "tool_use_preview_start":
67
- return {
68
- type: "tool_use_preview_start",
69
- toolUseId: event.toolUseId,
70
- toolName: event.toolName,
71
- conversationId,
72
- };
73
- case "tool_output_chunk":
74
- return {
75
- type: "tool_output_chunk",
76
- chunk: event.chunk,
77
- conversationId,
78
- toolUseId: event.toolUseId,
79
- };
80
- case "tool_result": {
81
- const imageBlocks = event.contentBlocks?.filter(
82
- (b): b is Extract<typeof b, { type: "image" }> => b.type === "image",
83
- );
84
- const imageDataList = imageBlocks?.length
85
- ? imageBlocks.map((b) => b.source.data)
86
- : undefined;
87
- return {
88
- type: "tool_result",
89
- toolName: "",
90
- result: event.content,
91
- isError: event.isError,
92
- diff: event.diff,
93
- status: event.status,
94
- conversationId,
95
- imageData: imageDataList?.[0],
96
- imageDataList,
97
- toolUseId: event.toolUseId,
98
- };
99
- }
100
- case "server_tool_start":
101
- return {
102
- type: "tool_use_start",
103
- toolName: event.name,
104
- input: event.input,
105
- conversationId,
106
- toolUseId: event.toolUseId,
107
- };
108
- case "server_tool_complete": {
109
- let resultText = "";
110
- if (Array.isArray(event.content) && event.content.length > 0) {
111
- resultText = (event.content as unknown[])
112
- .filter(
113
- (r): r is { type: string; title: string; url: string } =>
114
- typeof r === "object" &&
115
- r != null &&
116
- (r as { type?: string }).type === "web_search_result",
117
- )
118
- .map((r) => `${r.title}\n${r.url}`)
119
- .join("\n\n");
120
- }
121
- return {
122
- type: "tool_result",
123
- toolName: "web_search",
124
- result: resultText,
125
- isError: event.isError,
126
- conversationId,
127
- toolUseId: event.toolUseId,
128
- };
129
- }
130
- case "message_complete":
131
- return {
132
- type: "message_complete",
133
- conversationId,
134
- };
135
- case "input_json_delta":
136
- case "usage":
137
- case "error":
138
- case "provider_error":
139
- case "max_tokens_reached":
140
- case "context_compacting":
141
- case "compaction_circuit_open":
142
- case "compaction_circuit_closed":
143
- case "compaction_completed":
144
- case "history_stripped":
145
- case "agent_loop_exit":
146
- return null;
147
- case "llm_call_started":
148
- // The wake path persists its assistant tail via `persistTailMessage`
149
- // (an `addMessage`-shaped call below) rather than via the main
150
- // event-handler's `reserve` → `updateContent` pipeline, so there is
151
- // no row to reserve here. Translation returns null and the wake
152
- // path's existing end-of-turn persist continues to mint the row.
153
- // Following up with full wake-path pre-allocation parity is tracked
154
- // as a B3 follow-up.
155
- return null;
156
- }
157
- }
158
-
159
- /**
160
- * Adapt a live {@link Conversation} to the narrow {@link WakeTarget}
161
- * surface expected by `wakeAgentForOpportunity()`.
162
- */
163
- export function conversationToWakeTarget(
164
- conversation: Conversation,
165
- ): WakeTarget {
166
- return {
167
- conversationId: conversation.conversationId,
168
- agentLoop: conversation.agentLoop,
169
- getMessages: () => conversation.getMessages(),
170
- pushMessage: (msg) => {
171
- conversation.messages.push(msg);
172
- },
173
- onWakeProducedOutput: (source, hint, surfaceId) => {
174
- broadcastMessage({
175
- type: "ui_surface_show",
176
- conversationId: conversation.conversationId,
177
- surfaceId,
178
- surfaceType: "card",
179
- data: {
180
- title: "Conversation Woke",
181
- body: hint,
182
- metadata: [{ label: "Source", value: source }],
183
- },
184
- display: "inline",
185
- });
186
- },
187
- emitAgentEvent: (event) => {
188
- const frame = translateAgentEventToServerMessage(
189
- event,
190
- conversation.conversationId,
191
- );
192
- if (!frame) return;
193
- broadcastMessage(frame);
194
- },
195
- isProcessing: () => conversation.isProcessing(),
196
- markProcessing: (on) => {
197
- conversation.setProcessing(on);
198
- },
199
- setTrustContext: (ctx) => conversation.setTrustContext(ctx),
200
- setWakeAllowedTools: (tools) => {
201
- const previous = conversation.subagentAllowedTools;
202
- conversation.setSubagentAllowedTools(new Set(tools));
203
- return () => {
204
- conversation.setSubagentAllowedTools(previous);
205
- };
206
- },
207
- persistTailMessage: async (message) => {
208
- const turnChannelCtx = conversation.getTurnChannelContext();
209
- const turnInterfaceCtx = conversation.getTurnInterfaceContext();
210
- const metadata: Record<string, unknown> = {
211
- ...provenanceFromTrustContext(conversation.trustContext),
212
- userMessageChannel: turnChannelCtx?.userMessageChannel ?? "vellum",
213
- assistantMessageChannel:
214
- turnChannelCtx?.assistantMessageChannel ?? "vellum",
215
- userMessageInterface: turnInterfaceCtx?.userMessageInterface ?? "web",
216
- assistantMessageInterface:
217
- turnInterfaceCtx?.assistantMessageInterface ?? "web",
218
- };
219
- const persisted = await addMessage(
220
- conversation.conversationId,
221
- message.role,
222
- JSON.stringify(message.content),
223
- { metadata },
224
- );
225
- if (message.role === "assistant") {
226
- try {
227
- backfillMessageIdOnLogs(conversation.conversationId, persisted.id);
228
- } catch (err) {
229
- log.warn(
230
- { err, conversationId: conversation.conversationId },
231
- "wake adapter: backfill messageId on LLM logs failed (non-fatal)",
232
- );
233
- }
234
- }
235
- try {
236
- const convRow = getConversation(conversation.conversationId);
237
- if (convRow) {
238
- syncMessageToDisk(
239
- conversation.conversationId,
240
- persisted.id,
241
- convRow.createdAt,
242
- );
243
- }
244
- } catch (err) {
245
- log.warn(
246
- { err, conversationId: conversation.conversationId },
247
- "wake adapter: syncMessageToDisk failed (non-fatal)",
248
- );
249
- }
250
- },
251
- drainQueue: () => conversation.drainQueue(),
252
- };
253
- }
@@ -1,242 +0,0 @@
1
- /**
2
- * Tests for the v3 page→leaf classifier. Uses a stub provider so no live LLM
3
- * is hit. Pages are written into a temp workspace.
4
- */
5
-
6
- import { mkdtemp, rm } from "node:fs/promises";
7
- import { tmpdir } from "node:os";
8
- import { join } from "node:path";
9
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
10
-
11
- import type {
12
- Message,
13
- Provider,
14
- ProviderResponse,
15
- SendMessageOptions,
16
- ToolUseContent,
17
- } from "../../../providers/types.js";
18
- import { readPage, writePage } from "../../v2/page-store.js";
19
- import type { ConceptPageFrontmatter } from "../../v2/types.js";
20
- import type { LeafNode, LeafTree } from "../types.js";
21
-
22
- // Stub the provider layer before importing `assign.js` so its static import
23
- // chain (which transitively pulls in CES/credential workspace packages that
24
- // aren't built in a fresh worktree) never loads. The classifier is
25
- // provider-injectable, so every test passes its own stub provider — the real
26
- // `getConfiguredProvider` is never exercised here.
27
- mock.module("../../../providers/provider-send-message.js", () => ({
28
- getConfiguredProvider: async () => null,
29
- extractToolUse: (response: ProviderResponse) =>
30
- response.content.find((b): b is ToolUseContent => b.type === "tool_use"),
31
- userMessage: (text: string): Message => ({
32
- role: "user",
33
- content: [{ type: "text", text }],
34
- }),
35
- }));
36
-
37
- const { assignPages } = await import("../assign.js");
38
-
39
- function makeLeaf(path: string, description: string): LeafNode {
40
- return {
41
- path,
42
- frontmatter: { path, in_core: false },
43
- description,
44
- members: [],
45
- domain: path.split("/")[0],
46
- };
47
- }
48
-
49
- function makeTree(leaves: LeafNode[]): LeafTree {
50
- return {
51
- leaves: new Map(leaves.map((l) => [l.path, l])),
52
- byPage: new Map(),
53
- };
54
- }
55
-
56
- /** Sorted by path: [1] domain-a/topic-x, [2] domain-a/topic-y, [3] domain-b/topic-z */
57
- function threeLeafTree(): LeafTree {
58
- return makeTree([
59
- makeLeaf("domain-b/topic-z", "about z"),
60
- makeLeaf("domain-a/topic-x", "about x"),
61
- makeLeaf("domain-a/topic-y", "about y"),
62
- ]);
63
- }
64
-
65
- function stubProvider(
66
- handler: (
67
- messages: Message[],
68
- options?: SendMessageOptions,
69
- ) => ProviderResponse | Promise<ProviderResponse>,
70
- ): Provider {
71
- return {
72
- name: "stub",
73
- sendMessage: async (messages, options) => handler(messages, options),
74
- } as Provider;
75
- }
76
-
77
- function response(content: ProviderResponse["content"]): ProviderResponse {
78
- return {
79
- content,
80
- model: "stub-model",
81
- stopReason: "tool_use",
82
- usage: { inputTokens: 0, outputTokens: 0 },
83
- };
84
- }
85
-
86
- function toolResponse(ids: unknown[]): ProviderResponse {
87
- return response([
88
- { type: "tool_use", id: "tu-1", name: "assign_leaves", input: { ids } },
89
- ]);
90
- }
91
-
92
- function textResponse(text: string): ProviderResponse {
93
- return response([{ type: "text", text }]);
94
- }
95
-
96
- let workspaceDir: string;
97
-
98
- beforeEach(async () => {
99
- workspaceDir = await mkdtemp(join(tmpdir(), "v3-assign-"));
100
- });
101
-
102
- afterEach(async () => {
103
- await rm(workspaceDir, { recursive: true, force: true });
104
- });
105
-
106
- async function makePage(
107
- slug: string,
108
- frontmatter: Partial<ConceptPageFrontmatter>,
109
- body = "page body",
110
- ): Promise<void> {
111
- await writePage(workspaceDir, {
112
- slug,
113
- frontmatter: { edges: [], ref_files: [], ref_urls: [], ...frontmatter },
114
- body,
115
- });
116
- }
117
-
118
- describe("assignPages", () => {
119
- test("unions classified picks with prior picks, never overwriting", async () => {
120
- await makePage("page-a", { leaves: ["domain-a/topic-x"] });
121
- // Classifier returns [2] -> domain-a/topic-y and [1] -> already present.
122
- const provider = stubProvider(() => toolResponse([2, 1]));
123
-
124
- const results = await assignPages({
125
- tree: threeLeafTree(),
126
- workspaceDir,
127
- slugs: ["page-a"],
128
- provider,
129
- throttleMs: 0,
130
- });
131
-
132
- expect(results).toEqual([
133
- {
134
- slug: "page-a",
135
- before: ["domain-a/topic-x"],
136
- after: ["domain-a/topic-x", "domain-a/topic-y"],
137
- failed: false,
138
- },
139
- ]);
140
-
141
- const written = await readPage(workspaceDir, "page-a");
142
- expect(written?.frontmatter.leaves).toEqual([
143
- "domain-a/topic-x",
144
- "domain-a/topic-y",
145
- ]);
146
- });
147
-
148
- test("classification failure leaves the page's leaves unchanged", async () => {
149
- await makePage("page-a", { leaves: ["domain-b/topic-z"] });
150
-
151
- // (a) provider throws
152
- const throwing = stubProvider(() => {
153
- throw new Error("boom");
154
- });
155
- let results = await assignPages({
156
- tree: threeLeafTree(),
157
- workspaceDir,
158
- slugs: ["page-a"],
159
- provider: throwing,
160
- throttleMs: 0,
161
- });
162
- expect(results[0]).toEqual({
163
- slug: "page-a",
164
- before: ["domain-b/topic-z"],
165
- after: ["domain-b/topic-z"],
166
- failed: true,
167
- });
168
- expect(
169
- (await readPage(workspaceDir, "page-a"))?.frontmatter.leaves,
170
- ).toEqual(["domain-b/topic-z"]);
171
-
172
- // (b) no tool use
173
- results = await assignPages({
174
- tree: threeLeafTree(),
175
- workspaceDir,
176
- slugs: ["page-a"],
177
- provider: stubProvider(() => textResponse("no tool here")),
178
- throttleMs: 0,
179
- });
180
- expect(results[0].failed).toBe(true);
181
- expect(
182
- (await readPage(workspaceDir, "page-a"))?.frontmatter.leaves,
183
- ).toEqual(["domain-b/topic-z"]);
184
-
185
- // (c) empty ids
186
- results = await assignPages({
187
- tree: threeLeafTree(),
188
- workspaceDir,
189
- slugs: ["page-a"],
190
- provider: stubProvider(() => toolResponse([])),
191
- throttleMs: 0,
192
- });
193
- expect(results[0].failed).toBe(true);
194
- expect(
195
- (await readPage(workspaceDir, "page-a"))?.frontmatter.leaves,
196
- ).toEqual(["domain-b/topic-z"]);
197
- });
198
-
199
- test("deterministic id->path mapping, dropping out-of-range and 0 ids", async () => {
200
- await makePage("page-a", {});
201
- // 0 and 99 are invalid; 3 -> domain-b/topic-z; 1 -> domain-a/topic-x.
202
- const provider = stubProvider(() => toolResponse([0, 99, 3, 1, -1, 2.5]));
203
-
204
- const results = await assignPages({
205
- tree: threeLeafTree(),
206
- workspaceDir,
207
- slugs: ["page-a"],
208
- provider,
209
- throttleMs: 0,
210
- });
211
-
212
- expect(results[0].after).toEqual(["domain-b/topic-z", "domain-a/topic-x"]);
213
- expect(results[0].failed).toBe(false);
214
- });
215
-
216
- test("defaults to pages with empty or missing leaves", async () => {
217
- await makePage("page-empty", { leaves: [] });
218
- await makePage("page-missing", {});
219
- await makePage("page-classified", { leaves: ["domain-a/topic-x"] });
220
-
221
- const seen: string[] = [];
222
- const provider = stubProvider((messages) => {
223
- const text = messages[0]?.content
224
- .map((b) => (b.type === "text" ? b.text : ""))
225
- .join("");
226
- seen.push(text);
227
- return toolResponse([2]);
228
- });
229
-
230
- const results = await assignPages({
231
- tree: threeLeafTree(),
232
- workspaceDir,
233
- provider,
234
- throttleMs: 0,
235
- });
236
-
237
- const slugs = results.map((r) => r.slug).sort();
238
- expect(slugs).toEqual(["page-empty", "page-missing"]);
239
- // The classified page was never sent to the provider.
240
- expect(seen.length).toBe(2);
241
- });
242
- });
@@ -1,118 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
-
3
- import {
4
- CAPABILITIES_LEAF_PATH,
5
- type CapabilityResolvers,
6
- injectCapabilitiesLeaf,
7
- isCapabilitySlug,
8
- renderCapabilityContent,
9
- } from "../capabilities.js";
10
- import { buildNeedleIndex } from "../needle.js";
11
- import type { LeafPath, LeafTree, Slug } from "../types.js";
12
-
13
- function emptyTree(): LeafTree {
14
- return { leaves: new Map(), byPage: new Map<Slug, LeafPath[]>() };
15
- }
16
-
17
- describe("isCapabilitySlug", () => {
18
- test("true for skill and CLI-command slugs, false otherwise", () => {
19
- expect(isCapabilitySlug("skills/meet-join")).toBe(true);
20
- expect(isCapabilitySlug("cli-commands/schedules")).toBe(true);
21
- expect(isCapabilitySlug("relationship/vows")).toBe(false);
22
- expect(isCapabilitySlug("some-page")).toBe(false);
23
- });
24
- });
25
-
26
- describe("injectCapabilitiesLeaf", () => {
27
- test("registers an always-on leaf with the synthetic slugs as members", () => {
28
- const tree = emptyTree();
29
- const core = new Set<LeafPath>();
30
- injectCapabilitiesLeaf(tree, core, ["skills/foo", "cli-commands/bar"]);
31
-
32
- const leaf = tree.leaves.get(CAPABILITIES_LEAF_PATH);
33
- expect(leaf?.frontmatter.in_core).toBe(true);
34
- expect(leaf?.members).toEqual(["skills/foo", "cli-commands/bar"]);
35
- expect(core.has(CAPABILITIES_LEAF_PATH)).toBe(true);
36
- });
37
-
38
- test("unions the leaf into each member's byPage entry without dropping existing leaves", () => {
39
- const tree = emptyTree();
40
- tree.byPage.set("skills/foo", ["other/leaf"]);
41
- injectCapabilitiesLeaf(tree, new Set<LeafPath>(), [
42
- "skills/foo",
43
- "cli-commands/bar",
44
- ]);
45
-
46
- expect(tree.byPage.get("skills/foo")).toEqual([
47
- "other/leaf",
48
- CAPABILITIES_LEAF_PATH,
49
- ]);
50
- expect(tree.byPage.get("cli-commands/bar")).toEqual([
51
- CAPABILITIES_LEAF_PATH,
52
- ]);
53
- });
54
-
55
- test("is idempotent — re-injecting does not duplicate the byPage entry", () => {
56
- const tree = emptyTree();
57
- const core = new Set<LeafPath>();
58
- injectCapabilitiesLeaf(tree, core, ["skills/foo"]);
59
- injectCapabilitiesLeaf(tree, core, ["skills/foo"]);
60
- expect(tree.byPage.get("skills/foo")).toEqual([CAPABILITIES_LEAF_PATH]);
61
- });
62
-
63
- test("stays always-on even with no installed skills/commands", () => {
64
- const tree = emptyTree();
65
- const core = new Set<LeafPath>();
66
- injectCapabilitiesLeaf(tree, core, []);
67
- expect(tree.leaves.get(CAPABILITIES_LEAF_PATH)?.members).toEqual([]);
68
- expect(core.has(CAPABILITIES_LEAF_PATH)).toBe(true);
69
- });
70
- });
71
-
72
- describe("renderCapabilityContent", () => {
73
- const resolvers: CapabilityResolvers = {
74
- skill: (slug) =>
75
- slug === "skills/foo" ? { id: "foo", content: "foo capability" } : null,
76
- cli: (slug) =>
77
- slug === "cli-commands/bar"
78
- ? { id: "bar", content: "bar capability" }
79
- : null,
80
- };
81
-
82
- test("renders a skill slug with a Skill header", () => {
83
- expect(renderCapabilityContent("skills/foo", resolvers)).toBe(
84
- "# Skill: foo\nfoo capability",
85
- );
86
- });
87
-
88
- test("renders a CLI-command slug with a CLI header", () => {
89
- expect(renderCapabilityContent("cli-commands/bar", resolvers)).toBe(
90
- "# CLI command: bar\nbar capability",
91
- );
92
- });
93
-
94
- test("degrades to '' for a capability slug the cache cannot resolve", () => {
95
- expect(renderCapabilityContent("skills/missing", resolvers)).toBe("");
96
- });
97
-
98
- test("returns null for a non-capability slug so the caller reads the on-disk page", () => {
99
- expect(renderCapabilityContent("relationship/vows", resolvers)).toBeNull();
100
- });
101
- });
102
-
103
- describe("needle indexes injected capability members", () => {
104
- test("a skill slug is lexically retrievable by its title and summary", async () => {
105
- const tree = emptyTree();
106
- injectCapabilitiesLeaf(tree, new Set<LeafPath>(), ["skills/meet-join"]);
107
-
108
- const needle = await buildNeedleIndex(
109
- tree,
110
- async () => "Join and transcribe a video meeting",
111
- );
112
-
113
- // By slug-derived title token.
114
- expect(needle.query("meet", 5)).toContain("skills/meet-join");
115
- // By summary token.
116
- expect(needle.query("transcribe", 5)).toContain("skills/meet-join");
117
- });
118
- });
@@ -1,39 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterEach, describe, expect, test } from "bun:test";
5
-
6
- import { loadCore } from "../core.js";
7
-
8
- const BUNDLED_DATA_DIR = join(import.meta.dir, "..", "data");
9
-
10
- describe("loadCore", () => {
11
- let tmpDirs: string[] = [];
12
-
13
- afterEach(async () => {
14
- await Promise.all(
15
- tmpDirs.map((d) => rm(d, { recursive: true, force: true })),
16
- );
17
- tmpDirs = [];
18
- });
19
-
20
- async function makeTmpDir(): Promise<string> {
21
- const dir = await mkdtemp(join(tmpdir(), "v3-core-"));
22
- tmpDirs.push(dir);
23
- return dir;
24
- }
25
-
26
- test("loads alwaysOn from the supplied dataDir's core.json into a Set", async () => {
27
- const core = await loadCore(BUNDLED_DATA_DIR);
28
- expect(core).toBeInstanceOf(Set);
29
- expect(core.has("domain-a/topic-x")).toBe(true);
30
- expect(core.size).toBe(1);
31
- });
32
-
33
- test("returns empty set when core.json is missing", async () => {
34
- const emptyDataDir = await makeTmpDir();
35
- const core = await loadCore(emptyDataDir);
36
- expect(core).toBeInstanceOf(Set);
37
- expect(core.size).toBe(0);
38
- });
39
- });