@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -1,174 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { readdir, readFile } from "node:fs/promises";
3
- import { dirname, join, relative, sep } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
-
6
- import { parse as parseYaml } from "yaml";
7
-
8
- import { getWorkspaceDir } from "../../util/platform.js";
9
- import type {
10
- LeafFrontmatter,
11
- LeafNode,
12
- LeafPath,
13
- LeafTree,
14
- Slug,
15
- } from "./types.js";
16
-
17
- const HERE = dirname(fileURLToPath(import.meta.url));
18
-
19
- /** Bundled stub data shipped alongside the loader. */
20
- const BUNDLED_DATA_DIR = join(HERE, "data");
21
-
22
- /**
23
- * Resolve the directory the loaders should read leaf-tree artifacts from.
24
- *
25
- * Prefers a maintainer's per-instance workspace override
26
- * (`<workspace>/memory/v3/data/`) when present, otherwise falls back to the
27
- * generic bundled stub shipped in this package.
28
- *
29
- * The public {@link loadLeafTree} API still takes an explicit `dataDir` for
30
- * testability; orchestrators that want the runtime default call this helper.
31
- */
32
- export function resolveDataDir(): string {
33
- const workspaceData = join(getWorkspaceDir(), "memory", "v3", "data");
34
- if (existsSync(workspaceData)) return workspaceData;
35
- return BUNDLED_DATA_DIR;
36
- }
37
-
38
- /** Recursively collect every `*.md` file under `dir`. */
39
- async function collectMarkdownFiles(dir: string): Promise<string[]> {
40
- const entries = await readdir(dir, { withFileTypes: true });
41
- const files: string[] = [];
42
- for (const entry of entries) {
43
- const full = join(dir, entry.name);
44
- if (entry.isDirectory()) {
45
- files.push(...(await collectMarkdownFiles(full)));
46
- } else if (entry.isFile() && entry.name.endsWith(".md")) {
47
- files.push(full);
48
- }
49
- }
50
- return files;
51
- }
52
-
53
- /**
54
- * Split a leaf `.md` file into its YAML frontmatter and body.
55
- *
56
- * Frontmatter is the `---`-delimited block at the top of the file; everything
57
- * after the closing delimiter is the description body.
58
- */
59
- function splitFrontmatter(raw: string): { frontmatter: string; body: string } {
60
- const normalized = raw.replace(/^/, "");
61
- const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(normalized);
62
- if (!match) {
63
- throw new Error("leaf markdown is missing YAML frontmatter");
64
- }
65
- return { frontmatter: match[1], body: match[2] };
66
- }
67
-
68
- function parseLeafFrontmatter(yaml: string, file: string): LeafFrontmatter {
69
- const parsed = parseYaml(yaml) as unknown;
70
- if (parsed === null || typeof parsed !== "object") {
71
- throw new Error(`leaf ${file} frontmatter is not a mapping`);
72
- }
73
- const record = parsed as Record<string, unknown>;
74
- if (typeof record.path !== "string") {
75
- throw new Error(`leaf ${file} frontmatter is missing a string \`path\``);
76
- }
77
- if (typeof record.in_core !== "boolean") {
78
- throw new Error(
79
- `leaf ${file} frontmatter is missing a boolean \`in_core\``,
80
- );
81
- }
82
- return {
83
- path: record.path,
84
- in_core: record.in_core,
85
- ...(typeof record.id === "string" ? { id: record.id } : {}),
86
- };
87
- }
88
-
89
- /** Derive the canonical leaf path from a file's location under `leaves/`. */
90
- function pathFromLocation(leavesDir: string, file: string): LeafPath {
91
- return relative(leavesDir, file).replace(/\.md$/, "").split(sep).join("/");
92
- }
93
-
94
- /**
95
- * Load the leaf tree from `dataDir`. READ-ONLY: walks `leaves/**\/*.md` and
96
- * reads `assignments.json` without mutating anything on disk.
97
- *
98
- * Builds:
99
- * - `leaves`: leaf path → {@link LeafNode} (frontmatter, description, domain,
100
- * and the slugs assigned to it).
101
- * - `byPage`: slug → the leaf paths it is assigned to (inverted assignments).
102
- *
103
- * Page→leaf membership precedence is per-page: when `pageLeaves` supplies a
104
- * non-empty array for a slug, those frontmatter-derived leaves win for that
105
- * page; slugs absent from `pageLeaves` (or mapped to an empty array) fall back
106
- * to `assignments.json`. Omitting `pageLeaves` reproduces the legacy
107
- * assignments.json-only behavior exactly (used by the bundled stub and tests);
108
- * orchestrators supply `pageLeaves` from the page index.
109
- */
110
- export async function loadLeafTree(
111
- dataDir: string,
112
- pageLeaves?: Map<Slug, LeafPath[]>,
113
- ): Promise<LeafTree> {
114
- const leavesDir = join(dataDir, "leaves");
115
- const files = await collectMarkdownFiles(leavesDir);
116
-
117
- const nodes = await Promise.all(
118
- files.map(async (file): Promise<LeafNode> => {
119
- const raw = await readFile(file, "utf8");
120
- const { frontmatter, body } = splitFrontmatter(raw);
121
- const path = pathFromLocation(leavesDir, file);
122
- return {
123
- path,
124
- frontmatter: parseLeafFrontmatter(frontmatter, file),
125
- description: body.trim(),
126
- members: [],
127
- domain: path.split("/")[0],
128
- };
129
- }),
130
- );
131
-
132
- const leaves = new Map<LeafPath, LeafNode>(
133
- nodes.map((node) => [node.path, node]),
134
- );
135
-
136
- const assignmentsRaw = await readFile(
137
- join(dataDir, "assignments.json"),
138
- "utf8",
139
- );
140
- const assignments = JSON.parse(assignmentsRaw) as Record<Slug, LeafPath[]>;
141
-
142
- const slugs = new Set<Slug>(Object.keys(assignments));
143
- if (pageLeaves) for (const slug of pageLeaves.keys()) slugs.add(slug);
144
-
145
- const byPage = new Map<Slug, LeafPath[]>();
146
- for (const slug of slugs) {
147
- const fromFrontmatter = pageLeaves?.get(slug);
148
- const leafPaths =
149
- fromFrontmatter && fromFrontmatter.length > 0
150
- ? fromFrontmatter
151
- : (assignments[slug] ?? []);
152
- byPage.set(slug, [...leafPaths]);
153
- for (const leafPath of leafPaths) {
154
- leaves.get(leafPath)?.members.push(slug);
155
- }
156
- }
157
-
158
- return { leaves, byPage };
159
- }
160
-
161
- /** The slugs assigned to a leaf. */
162
- export function membersOf(tree: LeafTree, leaf: LeafPath): Slug[] {
163
- return tree.leaves.get(leaf)?.members ?? [];
164
- }
165
-
166
- /** The leaf paths a slug is assigned to. */
167
- export function leavesOf(tree: LeafTree, slug: Slug): LeafPath[] {
168
- return tree.byPage.get(slug) ?? [];
169
- }
170
-
171
- /** The unique slugs owned by every leaf in `core` (expand leaf-paths → slugs). */
172
- export function coreSlugs(tree: LeafTree, core: Set<LeafPath>): Set<Slug> {
173
- return new Set([...core].flatMap((leaf) => membersOf(tree, leaf)));
174
- }
@@ -1,59 +0,0 @@
1
- export type LeafPath = string; // dot- or slash-pathed taxonomy node
2
- export type Slug = string;
3
-
4
- /**
5
- * Injection-block id for the v3 live `<memory>` block. Shared between the
6
- * producer (the v3 injector in `shadow-plugin.ts`) and the v2-suppression
7
- * consumer (`conversation-runtime-assembly.ts`), which keys off this id to
8
- * detect that v3 actually produced a block this turn. Keeping it in one place
9
- * makes a rename a compile error on both sides instead of a silent
10
- * suppression bypass.
11
- */
12
- export const MEMORY_V3_BLOCK_ID = "memory-v3" as const;
13
-
14
- export interface LeafFrontmatter {
15
- path: LeafPath;
16
- in_core: boolean;
17
- /**
18
- * Optional stable identifier for the leaf, independent of its taxonomy path.
19
- * Older leaves predate this field and omit it, so it is optional.
20
- */
21
- id?: string;
22
- }
23
-
24
- export interface LeafNode {
25
- path: LeafPath;
26
- frontmatter: LeafFrontmatter;
27
- description: string;
28
- members: Slug[];
29
- domain: string;
30
- }
31
-
32
- export interface LeafTree {
33
- leaves: Map<LeafPath, LeafNode>;
34
- byPage: Map<Slug, LeafPath[]>;
35
- }
36
-
37
- export interface WorkingSetEntry {
38
- slug: Slug;
39
- selectedAtTurn: number;
40
- pinned: boolean;
41
- lastSeenTurn: number;
42
- }
43
-
44
- export interface TurnContext {
45
- conversationId: string;
46
- turnNumber: number;
47
- currentMessage: string;
48
- recentContext: string;
49
- /**
50
- * Optional situational signal — the current date plus the live NOW.md
51
- * scratchpad — so a leaf or page can be routed/selected on a date or
52
- * live-state cue the message itself never names (e.g. a person whose
53
- * anniversary is today). Omitted when unavailable; the router and selector
54
- * render nothing for an undefined value.
55
- */
56
- situationalContext?: string;
57
- }
58
-
59
- export type SelectionSource = "l1+l2" | "core+l2" | "needle" | "carry-forward";
@@ -1,187 +0,0 @@
1
- /**
2
- * Verifies that `emitNotificationSignal` invokes the home-feed side
3
- * effect after dispatching, and that the side effect's background-only
4
- * filter correctly suppresses interactive signals.
5
- *
6
- * The side effect itself is unit-tested in `home-feed-side-effect.test.ts`;
7
- * this test exercises the wire-up boundary in `emit-signal.ts` by mocking
8
- * at the `appendFeedItem` / `getConversation` boundary so the real
9
- * background-filter logic runs end-to-end.
10
- */
11
- import { beforeEach, describe, expect, mock, test } from "bun:test";
12
-
13
- import type { FeedItem } from "../../home/feed-types.js";
14
- import type {
15
- NotificationDecision,
16
- NotificationDeliveryResult,
17
- } from "../types.js";
18
-
19
- // ── Module mocks ───────────────────────────────────────────────────────
20
- //
21
- // `mock.module` is hoisted, so these intercepts apply before the module
22
- // under test resolves its imports. Closures over module-scoped state
23
- // let each test reset and inspect captured calls afterwards.
24
-
25
- const appendCalls: FeedItem[] = [];
26
- let conversationRow: { conversationType: string } | null = null;
27
-
28
- mock.module("../../home/feed-writer.js", () => ({
29
- appendFeedItem: async (item: FeedItem) => {
30
- appendCalls.push(item);
31
- },
32
- }));
33
-
34
- // home-feed-side-effect.ts only consumes `getConversation`.
35
- mock.module("../../memory/conversation-crud.js", () => ({
36
- getConversation: () => conversationRow,
37
- reserveMessage: mock(async () => ({ id: "msg-reserve" })),
38
- }));
39
-
40
- // Stub the broadcaster so emit-signal's `getBroadcaster()` does not need
41
- // to build real adapters or pull in `conversation-pairing.ts` transitively
42
- // (which would force us to mirror the full `conversation-crud.js` surface).
43
- class StubBroadcaster {
44
- setOnConversationCreated() {}
45
- async broadcastDecision() {
46
- return [];
47
- }
48
- }
49
- mock.module("../broadcaster.js", () => ({
50
- NotificationBroadcaster: StubBroadcaster,
51
- }));
52
-
53
- mock.module("../adapters/macos.js", () => ({
54
- VellumAdapter: class {},
55
- isGuardianSensitiveEvent: () => false,
56
- }));
57
- mock.module("../adapters/slack.js", () => ({
58
- SlackAdapter: class {},
59
- }));
60
- mock.module("../adapters/telegram.js", () => ({
61
- TelegramAdapter: class {},
62
- }));
63
-
64
- // Stub out the persistence + channel resolution layers so emitNotificationSignal
65
- // can run end-to-end without touching the DB / contacts store / LLM.
66
-
67
- mock.module("../events-store.js", () => ({
68
- createEvent: (params: { id: string }) => ({
69
- id: params.id,
70
- sourceEventName: "schedule.notify",
71
- sourceChannel: "scheduler",
72
- sourceContextId: "conv-source-1",
73
- attentionHintsJson: "{}",
74
- payloadJson: "{}",
75
- dedupeKey: null,
76
- createdAt: 0,
77
- updatedAt: 0,
78
- }),
79
- updateEventDedupeKey: () => {},
80
- }));
81
-
82
- mock.module("../decisions-store.js", () => ({
83
- updateDecision: () => {},
84
- }));
85
-
86
- mock.module("../../contacts/contact-store.js", () => ({
87
- findGuardianForChannel: () => null,
88
- listGuardianChannels: () => [],
89
- }));
90
-
91
- const stubDecision: NotificationDecision = {
92
- shouldNotify: true,
93
- selectedChannels: ["vellum"],
94
- reasoningSummary: "test",
95
- renderedCopy: {
96
- vellum: { title: "Background job done", body: "Summary of what happened." },
97
- },
98
- dedupeKey: "dk-1",
99
- confidence: 1,
100
- fallbackUsed: false,
101
- };
102
-
103
- mock.module("../decision-engine.js", () => ({
104
- evaluateSignal: async () => stubDecision,
105
- // Pass the decision through unchanged — emit-signal calls this after
106
- // evaluateSignal and only re-persists when the reference changes.
107
- enforceRoutingIntent: (decision: NotificationDecision) => decision,
108
- }));
109
-
110
- mock.module("../deterministic-checks.js", () => ({
111
- runDeterministicChecks: async () => ({ passed: true }),
112
- }));
113
-
114
- const stubDeliveryResults: NotificationDeliveryResult[] = [
115
- {
116
- channel: "vellum",
117
- destination: "vellum-client",
118
- status: "sent",
119
- conversationId: "conv-vellum-1",
120
- },
121
- ];
122
-
123
- mock.module("../runtime-dispatch.js", () => ({
124
- dispatchDecision: async () => ({
125
- dispatched: true,
126
- reason: "Dispatched to 1/1 channels",
127
- deliveryResults: stubDeliveryResults,
128
- }),
129
- }));
130
-
131
- const { emitNotificationSignal } = await import("../emit-signal.js");
132
-
133
- // ── Tests ──────────────────────────────────────────────────────────────
134
-
135
- beforeEach(() => {
136
- appendCalls.length = 0;
137
- conversationRow = null;
138
- });
139
-
140
- describe("emitNotificationSignal home-feed wire-up", () => {
141
- test("background-conversation signal triggers appendFeedItem", async () => {
142
- conversationRow = { conversationType: "background" };
143
-
144
- const result = await emitNotificationSignal({
145
- sourceEventName: "schedule.notify",
146
- sourceChannel: "scheduler",
147
- sourceContextId: "conv-source-1",
148
- contextPayload: { title: "Background job done" },
149
- attentionHints: {
150
- requiresAction: false,
151
- urgency: "medium",
152
- isAsyncBackground: false,
153
- visibleInSourceNow: false,
154
- },
155
- });
156
-
157
- expect(result.dispatched).toBe(true);
158
- expect(appendCalls).toHaveLength(1);
159
- const appended = appendCalls[0]!;
160
- expect(appended.id).toBe(`notif:${result.signalId}`);
161
- expect(appended.title).toBe("Background job done");
162
- expect(appended.summary).toBe("Summary of what happened.");
163
- // The feed item's conversationId points to the source conversation
164
- // that emitted the signal, not the conversation the notification
165
- // pipeline spawned to handle it.
166
- expect(appended.conversationId).toBe("conv-source-1");
167
- });
168
-
169
- test("interactive standard conversation does NOT trigger appendFeedItem", async () => {
170
- conversationRow = { conversationType: "standard" };
171
-
172
- const result = await emitNotificationSignal({
173
- sourceEventName: "schedule.notify",
174
- sourceChannel: "scheduler",
175
- sourceContextId: "conv-source-1",
176
- attentionHints: {
177
- requiresAction: false,
178
- urgency: "medium",
179
- isAsyncBackground: false,
180
- visibleInSourceNow: true,
181
- },
182
- });
183
-
184
- expect(result.dispatched).toBe(true);
185
- expect(appendCalls).toHaveLength(0);
186
- });
187
- });
@@ -1,93 +0,0 @@
1
- import type {
2
- CircuitBreakerArgs,
3
- CircuitBreakerResult,
4
- Middleware,
5
- } from "../../../types.js";
6
-
7
- /**
8
- * Consecutive failures required to trip the breaker. Matches the legacy
9
- * `COMPACTION_CIRCUIT_FAILURE_THRESHOLD` in `conversation-agent-loop.ts`.
10
- */
11
- export const COMPACTION_CIRCUIT_FAILURE_THRESHOLD = 3;
12
-
13
- /**
14
- * Cooldown window after the breaker trips, during which auto-compaction is
15
- * suspended. Matches the legacy `COMPACTION_CIRCUIT_COOLDOWN_MS`.
16
- */
17
- export const COMPACTION_CIRCUIT_COOLDOWN_MS = 60 * 60 * 1000;
18
-
19
- /**
20
- * Default middleware for the `circuitBreaker` pipeline. A thin wrapper over the
21
- * state container passed in `CircuitBreakerArgs.state`:
22
- *
23
- * - `{ key }` — query. Defers to `next` for the current
24
- * `{ open, cooldownRemainingMs? }`.
25
- * - `{ key, outcome }` — update state based on outcome, then defer to `next`
26
- * for the post-update decision. A run of three failures trips the breaker;
27
- * any non-failure outcome resets both the counter and the cooldown timestamp.
28
- *
29
- * Event emission preserves the existing `trackCompactionOutcome` behavior:
30
- * `compaction_circuit_open` fires once when the counter first reaches the
31
- * threshold while the circuit is dormant; `compaction_circuit_closed` fires
32
- * only on the open→closed transition.
33
- */
34
- const circuitBreaker: Middleware<CircuitBreakerArgs, CircuitBreakerResult> =
35
- async function circuitBreaker(args, next) {
36
- const { outcome, state, onEvent } = args;
37
-
38
- // Update branch — mutate state first, then defer to the downstream
39
- // chain (or terminal) for the decision so outer observers still see
40
- // the fully-processed outcome. Separating state mutation from
41
- // decision computation also keeps this middleware composable: an
42
- // outer plugin may wrap the invocation to observe both the pre-update
43
- // args and the post-update result.
44
- if (outcome !== undefined) {
45
- if (outcome === "failure") {
46
- state.consecutiveCompactionFailures += 1;
47
- // Treat a stale/expired open-until timestamp the same as null so
48
- // a new 3-strike window can re-open the circuit after the prior
49
- // cooldown elapses. Without this, subsequent trips would no-op
50
- // because `compactionCircuitOpenUntil` remains set to a past
51
- // timestamp even though the breaker is effectively closed.
52
- const circuitDormant =
53
- state.compactionCircuitOpenUntil === null ||
54
- Date.now() >= state.compactionCircuitOpenUntil;
55
- if (
56
- state.consecutiveCompactionFailures >=
57
- COMPACTION_CIRCUIT_FAILURE_THRESHOLD &&
58
- circuitDormant
59
- ) {
60
- const openUntil = Date.now() + COMPACTION_CIRCUIT_COOLDOWN_MS;
61
- state.compactionCircuitOpenUntil = openUntil;
62
- if (onEvent) {
63
- onEvent({
64
- type: "compaction_circuit_open",
65
- conversationId: state.conversationId,
66
- reason: "3_consecutive_failures",
67
- openUntil,
68
- });
69
- }
70
- }
71
- } else {
72
- // Emit only on the open→closed transition; firing on the common
73
- // closed→closed case would be noise.
74
- const wasOpen = state.compactionCircuitOpenUntil !== null;
75
- state.consecutiveCompactionFailures = 0;
76
- state.compactionCircuitOpenUntil = null;
77
- if (wasOpen && onEvent) {
78
- onEvent({
79
- type: "compaction_circuit_closed",
80
- conversationId: state.conversationId,
81
- });
82
- }
83
- }
84
- }
85
-
86
- // Defer to downstream (the terminal, in the default registration, but
87
- // potentially another plugin in a customized chain) for the final
88
- // decision. The terminal's implementation is the canonical read of
89
- // the (now-updated) state container.
90
- return next(args);
91
- };
92
-
93
- export default circuitBreaker;
@@ -1,15 +0,0 @@
1
- {
2
- "name": "default-circuit-breaker",
3
- "version": "1.0.0",
4
- "description": "First-party default plugin wrapping the assistant's built-in circuit-breaker pipeline with a passthrough implementation.",
5
- "private": true,
6
- "license": "MIT",
7
- "type": "module",
8
- "main": "./register.ts",
9
- "engines": {
10
- "node": ">=20.12.0"
11
- },
12
- "peerDependencies": {
13
- "@vellumai/plugin-api": "^0.8.0"
14
- }
15
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * Default `circuitBreaker` plugin.
3
- *
4
- * Replicates the inline compaction circuit-breaker logic that previously
5
- * lived in `daemon/conversation-agent-loop.ts`: three consecutive summary-LLM
6
- * failures open the circuit for a one-hour cooldown, and any successful
7
- * compaction resets the counter.
8
- *
9
- * The plugin is a thin wrapper over the state container passed in
10
- * `CircuitBreakerArgs.state`. The {@link Conversation} owns the underlying
11
- * fields (`consecutiveCompactionFailures`, `compactionCircuitOpenUntil`)
12
- * because dev-only playground routes (`POST /playground/reset-compaction-circuit`,
13
- * `POST /playground/inject-compaction-failures`) read and mutate them
14
- * directly. Keeping ownership on the conversation lets this plugin stay a
15
- * pure wrapper while preserving those hatches.
16
- *
17
- * The `key` parameter is carried through for multi-circuit futures but the
18
- * default plugin currently bundles all circuit state into the `state`
19
- * container; the key is attached to the log record via the pipeline runner.
20
- */
21
-
22
- import { type Plugin } from "../../types.js";
23
- import circuitBreaker from "./middlewares/circuitBreaker.js";
24
- import pkg from "./package.json" with { type: "json" };
25
-
26
- /**
27
- * Default plugin registered at daemon startup. Consumers negotiate against
28
- * `circuitBreakerApi@v1` via the registry's capability table.
29
- */
30
- export const defaultCircuitBreakerPlugin: Plugin = {
31
- manifest: {
32
- name: pkg.name,
33
- version: pkg.version,
34
- },
35
-
36
- middleware: {
37
- circuitBreaker,
38
- },
39
- };
@@ -1,25 +0,0 @@
1
- import type {
2
- CompactionArgs,
3
- CompactionResult,
4
- Middleware,
5
- } from "../../../types.js";
6
-
7
- /**
8
- * Passthrough middleware for the `compaction` pipeline. Forwards to
9
- * `next(args)` so any custom plugins layered outside still run; when this is
10
- * the only middleware, `next` is the terminal handler (`../terminal.ts`) and
11
- * returns the real compaction output.
12
- *
13
- * Defaults register at the OUTERMOST onion position, so deciding here without
14
- * calling `next` would shadow every later-registered plugin. Routing through
15
- * `next(args)` lets user middleware participate normally.
16
- */
17
- const defaultCompactionMiddleware: Middleware<
18
- CompactionArgs,
19
- CompactionResult
20
- > = async function defaultCompaction(args, next, ctx) {
21
- void ctx;
22
- return next(args);
23
- };
24
-
25
- export default defaultCompactionMiddleware;
@@ -1,35 +0,0 @@
1
- /**
2
- * Default `compaction` plugin.
3
- *
4
- * The plugin's middleware is a passthrough — it calls `next(args)` and returns
5
- * the result unchanged. The actual compaction lives in the terminal handler in
6
- * `./terminal.ts`, which is wired in as the pipeline's `terminal` argument by
7
- * the `runPipeline` call site in `daemon/conversation-agent-loop.ts`. This
8
- * separation matters: the default plugin is registered before any user plugin
9
- * (defaults load first in `bootstrapPlugins()`), which puts it at the
10
- * OUTERMOST position of the onion chain. If the default middleware were to
11
- * invoke the terminal directly without calling `next`, it would shadow every
12
- * later-registered plugin. Routing through `next(args)` lets user middleware
13
- * participate normally.
14
- *
15
- * Design doc: `.private/plans/agent-plugin-system.md` (PR 25).
16
- */
17
-
18
- import { type Plugin } from "../../types.js";
19
- import defaultCompactionMiddleware from "./middlewares/compaction.js";
20
- import pkg from "./package.json" with { type: "json" };
21
-
22
- /**
23
- * Manifest + middleware wiring for the default compaction plugin. The
24
- * registration happens in `daemon/external-plugins-bootstrap.ts` before
25
- * {@link bootstrapPlugins} fires plugin `init()` hooks.
26
- */
27
- export const defaultCompactionPlugin: Plugin = {
28
- manifest: {
29
- name: pkg.name,
30
- version: pkg.version,
31
- },
32
- middleware: {
33
- compaction: defaultCompactionMiddleware,
34
- },
35
- };