@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,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
- };