@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8

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 (262) hide show
  1. package/bun.lock +2 -2
  2. package/docs/plugins.md +832 -0
  3. package/examples/plugins/echo/README.md +60 -61
  4. package/examples/plugins/echo/package.json +2 -1
  5. package/examples/plugins/echo/register.ts +143 -0
  6. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
  7. package/openapi.yaml +5 -15
  8. package/package.json +2 -2
  9. package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
  10. package/src/__tests__/anthropic-provider.test.ts +1 -1
  11. package/src/__tests__/app-control-flow.test.ts +1 -1
  12. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  13. package/src/__tests__/approval-routes-http.test.ts +1 -4
  14. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  15. package/src/__tests__/channel-approvals.test.ts +1 -1
  16. package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
  17. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  18. package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
  19. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
  20. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
  21. package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
  22. package/src/__tests__/conversation-agent-loop.test.ts +39 -42
  23. package/src/__tests__/conversation-clean-command.test.ts +2 -5
  24. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
  25. package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
  26. package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
  27. package/src/__tests__/conversation-starter-routes.test.ts +6 -14
  28. package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
  29. package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
  30. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
  31. package/src/__tests__/db-acp-history.test.ts +0 -101
  32. package/src/__tests__/dynamic-page-surface.test.ts +0 -31
  33. package/src/__tests__/file-write-tool.test.ts +0 -63
  34. package/src/__tests__/gateway-only-guard.test.ts +2 -12
  35. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  36. package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
  37. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  38. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
  39. package/src/__tests__/heartbeat-service.test.ts +0 -1
  40. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  41. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  42. package/src/__tests__/injector-background-turn.test.ts +1 -1
  43. package/src/__tests__/injector-chain.test.ts +6 -34
  44. package/src/__tests__/injector-disk-pressure.test.ts +34 -77
  45. package/src/__tests__/injector-document-comments.test.ts +1 -1
  46. package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
  47. package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
  48. package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
  49. package/src/__tests__/pipeline-runner.test.ts +554 -0
  50. package/src/__tests__/plugin-api-shim.test.ts +6 -3
  51. package/src/__tests__/plugin-bootstrap.test.ts +23 -12
  52. package/src/__tests__/plugin-registry.test.ts +49 -3
  53. package/src/__tests__/plugin-types.test.ts +70 -0
  54. package/src/__tests__/reaction-persistence.test.ts +1 -1
  55. package/src/__tests__/send-endpoint-busy.test.ts +1 -4
  56. package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
  57. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  58. package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
  59. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  60. package/src/__tests__/subagent-manager-notify.test.ts +3 -1
  61. package/src/__tests__/subagent-notify-parent.test.ts +3 -1
  62. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  63. package/src/__tests__/user-plugin-loader.test.ts +286 -54
  64. package/src/acp/__tests__/client-handler.test.ts +0 -40
  65. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
  66. package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
  67. package/src/acp/agent-process.ts +1 -61
  68. package/src/acp/client-handler.ts +0 -31
  69. package/src/acp/prepare-agent-env.ts +29 -83
  70. package/src/acp/resolve-agent.test.ts +7 -320
  71. package/src/acp/resolve-agent.ts +18 -182
  72. package/src/acp/session-manager.ts +73 -495
  73. package/src/acp/types.ts +0 -8
  74. package/src/agent/compaction-circuit.ts +102 -60
  75. package/src/agent/loop.ts +59 -32
  76. package/src/api/responses/conversation-message.ts +1 -7
  77. package/src/approvals/guardian-request-resolvers.ts +1 -1
  78. package/src/background-wake/next-wake.ts +0 -1
  79. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  80. package/src/config/acp-defaults.test.ts +0 -10
  81. package/src/config/acp-defaults.ts +0 -6
  82. package/src/config/bundled-skills/acp/SKILL.md +31 -83
  83. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  84. package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
  85. package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
  86. package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
  87. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  88. package/src/config/bundled-tool-registry.ts +0 -2
  89. package/src/config/feature-flag-registry.json +5 -14
  90. package/src/config/schemas/heartbeat.ts +0 -9
  91. package/src/context/strip-injections.ts +2 -8
  92. package/src/context/window-manager.ts +1 -2
  93. package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
  94. package/src/daemon/conversation-agent-loop.ts +279 -62
  95. package/src/daemon/conversation-runtime-assembly.ts +69 -106
  96. package/src/daemon/conversation-store.ts +90 -9
  97. package/src/daemon/conversation-workspace.ts +0 -17
  98. package/src/daemon/conversation.ts +6 -0
  99. package/src/daemon/external-plugins-bootstrap.ts +11 -11
  100. package/src/daemon/handlers/conversations.ts +1 -3
  101. package/src/daemon/handlers/skills.ts +1 -4
  102. package/src/daemon/lifecycle.ts +0 -21
  103. package/src/daemon/server.ts +0 -2
  104. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
  105. package/src/heartbeat/heartbeat-run-store.ts +1 -23
  106. package/src/heartbeat/heartbeat-service.ts +0 -26
  107. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  108. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  109. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -15
  110. package/src/ipc/skill-routes/memory.ts +2 -4
  111. package/src/memory/conversation-starter-checkpoints.ts +0 -1
  112. package/src/memory/db-init.ts +0 -2
  113. package/src/memory/job-handlers/conversation-starters.ts +2 -13
  114. package/src/memory/jobs-worker.ts +1 -1
  115. package/src/memory/migrations/index.ts +0 -1
  116. package/src/memory/schema/acp.ts +0 -4
  117. package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
  118. package/src/memory/v2/consolidation-job.ts +4 -13
  119. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
  120. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
  121. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
  122. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
  123. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
  124. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
  125. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
  126. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
  127. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
  128. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
  129. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
  130. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
  131. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
  132. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
  133. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
  134. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
  135. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
  136. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
  137. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
  138. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
  139. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
  140. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
  141. package/src/plugin-api/index.ts +5 -0
  142. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
  143. package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
  144. package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
  145. package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
  146. package/src/plugins/defaults/compaction/package.json +1 -1
  147. package/src/plugins/defaults/compaction/register.ts +19 -8
  148. package/src/plugins/defaults/compaction/terminal.ts +73 -0
  149. package/src/plugins/defaults/index.ts +5 -3
  150. package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
  151. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
  152. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  153. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
  154. package/src/plugins/defaults/overflow-reduce/package.json +15 -0
  155. package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
  156. package/src/plugins/external-api.ts +2 -2
  157. package/src/plugins/pipeline.ts +293 -6
  158. package/src/plugins/registry.ts +37 -9
  159. package/src/plugins/types.ts +336 -32
  160. package/src/plugins/user-loader.ts +127 -30
  161. package/src/proactive-artifact/aux-message-injector.ts +1 -1
  162. package/src/proactive-artifact/job.test.ts +1 -1
  163. package/src/prompts/__tests__/system-prompt.test.ts +0 -6
  164. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
  165. package/src/runtime/__tests__/agent-wake.test.ts +5 -5
  166. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  167. package/src/runtime/agent-wake.ts +3 -0
  168. package/src/runtime/assistant-event-hub.ts +1 -1
  169. package/src/runtime/channel-approvals.ts +1 -1
  170. package/src/runtime/interactive-ui.ts +1 -1
  171. package/src/runtime/routes/__tests__/acp-routes.test.ts +55 -283
  172. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  173. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
  174. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
  175. package/src/runtime/routes/acp-routes.test.ts +25 -89
  176. package/src/runtime/routes/acp-routes.ts +29 -81
  177. package/src/runtime/routes/approval-routes.ts +1 -1
  178. package/src/runtime/routes/browser-routes.ts +1 -1
  179. package/src/runtime/routes/browser-tabs-routes.ts +10 -6
  180. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  181. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  182. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  183. package/src/runtime/routes/conversation-routes.ts +2 -15
  184. package/src/runtime/routes/conversation-starter-routes.ts +7 -13
  185. package/src/runtime/routes/conversations-import-routes.ts +7 -24
  186. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  187. package/src/runtime/routes/host-cu-routes.ts +1 -1
  188. package/src/runtime/routes/identity-routes.ts +3 -18
  189. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  190. package/src/runtime/routes/memory-v3-routes.ts +6 -16
  191. package/src/runtime/routes/playground/helpers.ts +1 -1
  192. package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
  193. package/src/runtime/routes/work-items-routes.ts +4 -2
  194. package/src/runtime/services/conversation-serializer.ts +1 -1
  195. package/src/signals/cancel.ts +4 -2
  196. package/src/subagent/manager.ts +5 -17
  197. package/src/tools/acp/list-agents.test.ts +1 -7
  198. package/src/tools/acp/spawn.test.ts +55 -158
  199. package/src/tools/acp/spawn.ts +72 -47
  200. package/src/tools/acp/steer.test.ts +8 -105
  201. package/src/tools/acp/steer.ts +17 -48
  202. package/src/tools/apps/executors.ts +8 -13
  203. package/src/tools/filesystem/write.ts +0 -34
  204. package/src/tools/subagent/spawn.ts +4 -2
  205. package/src/tools/ui-surface/definitions.ts +4 -25
  206. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
  207. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
  208. package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
  209. package/examples/plugins/echo/hooks/stop.ts +0 -16
  210. package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
  211. package/examples/plugins/echo/src/emit.ts +0 -19
  212. package/src/__tests__/compaction-circuit.test.ts +0 -258
  213. package/src/__tests__/compaction-direct.test.ts +0 -132
  214. package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
  215. package/src/acp/__tests__/agent-process.test.ts +0 -161
  216. package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
  217. package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
  218. package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
  219. package/src/acp/auto-install.test.ts +0 -196
  220. package/src/acp/auto-install.ts +0 -177
  221. package/src/acp/feature-gate.test.ts +0 -48
  222. package/src/acp/feature-gate.ts +0 -34
  223. package/src/acp/resume-hint.ts +0 -25
  224. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
  225. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
  226. package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
  227. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
  228. package/src/daemon/conversation-registry.ts +0 -159
  229. package/src/daemon/overflow-reduction-loop.ts +0 -230
  230. package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
  231. package/src/plugins/defaults/compaction/compact.ts +0 -59
  232. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
  233. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
  234. package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
  235. package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
  236. package/src/tools/acp/context.ts +0 -20
  237. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
  238. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
  239. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
  240. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
  241. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
  242. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
  243. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
  244. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
  245. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
  246. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
  247. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
  248. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
  249. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
  250. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
  251. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
  252. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
  253. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
  254. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
  255. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
  256. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
  257. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
  258. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
  259. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
  260. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
  261. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
  262. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
@@ -2,19 +2,26 @@
2
2
  * Tests for the plugin registry (PR 13).
3
3
  *
4
4
  * Covers successful registration, required-field and duplicate-name
5
- * validation, capability-version negotiation error messaging, and
6
- * registration order.
5
+ * validation, capability-version negotiation error messaging, injector
6
+ * ordering, and middleware collection order.
7
7
  */
8
8
 
9
9
  import { beforeEach, describe, expect, test } from "bun:test";
10
10
 
11
11
  import {
12
12
  closeRegistration,
13
+ getMiddlewaresFor,
13
14
  getRegisteredPlugins,
14
15
  registerPlugin,
15
16
  resetPluginRegistryForTests,
16
17
  } from "../plugins/registry.js";
17
- import { type Plugin, PluginExecutionError } from "../plugins/types.js";
18
+ import {
19
+ type CompactionArgs,
20
+ type CompactionResult,
21
+ type Middleware,
22
+ type Plugin,
23
+ PluginExecutionError,
24
+ } from "../plugins/types.js";
18
25
 
19
26
  /** Build a minimal, valid plugin with the given name and optional extras. */
20
27
  function buildPlugin(
@@ -140,6 +147,45 @@ describe("plugin registry", () => {
140
147
  expect(() => registerPlugin(bad)).toThrow(/manifest\.version is required/);
141
148
  });
142
149
 
150
+ test("getMiddlewaresFor returns middleware in registration order", () => {
151
+ const firstMw: Middleware<CompactionArgs, CompactionResult> = async (
152
+ args,
153
+ next,
154
+ ) => next(args);
155
+ const secondMw: Middleware<CompactionArgs, CompactionResult> = async (
156
+ args,
157
+ next,
158
+ ) => next(args);
159
+
160
+ registerPlugin(
161
+ buildPlugin("plugin-first", { middleware: { compaction: firstMw } }),
162
+ );
163
+ registerPlugin(
164
+ buildPlugin("plugin-second", { middleware: { compaction: secondMw } }),
165
+ );
166
+
167
+ const middlewares = getMiddlewaresFor("compaction");
168
+ expect(middlewares).toHaveLength(2);
169
+ // Identity comparison proves the middleware instances come back in
170
+ // registration order — outer→inner composition semantics belong to the
171
+ // pipeline runner (PR 12), not the registry.
172
+ expect(middlewares[0]).toBe(firstMw);
173
+ expect(middlewares[1]).toBe(secondMw);
174
+ });
175
+
176
+ test("getMiddlewaresFor skips plugins without a middleware for the pipeline", () => {
177
+ const mw: Middleware<CompactionArgs, CompactionResult> = async (
178
+ args,
179
+ next,
180
+ ) => next(args);
181
+ registerPlugin(buildPlugin("bare"));
182
+ registerPlugin(buildPlugin("has-mw", { middleware: { compaction: mw } }));
183
+
184
+ const middlewares = getMiddlewaresFor("compaction");
185
+ expect(middlewares).toHaveLength(1);
186
+ expect(middlewares[0]).toBe(mw);
187
+ });
188
+
143
189
  test("getRegisteredPlugins reflects registration order", () => {
144
190
  registerPlugin(buildPlugin("one"));
145
191
  registerPlugin(buildPlugin("two"));
@@ -13,10 +13,18 @@ import { describe, expect, test } from "bun:test";
13
13
  import type { TrustContext } from "../daemon/trust-context.js";
14
14
  import { RiskLevel } from "../permissions/types.js";
15
15
  import {
16
+ type CircuitBreakerArgs,
17
+ type CircuitBreakerResult,
18
+ type CompactionArgs,
19
+ type CompactionResult,
20
+ type Middleware,
21
+ type OverflowReduceArgs,
22
+ type OverflowReduceResult,
16
23
  type Plugin,
17
24
  PluginExecutionError,
18
25
  type PluginInitContext,
19
26
  type PluginManifest,
27
+ PluginTimeoutError,
20
28
  type TurnContext,
21
29
  } from "../plugins/types.js";
22
30
  import type { Tool } from "../tools/types.js";
@@ -30,6 +38,7 @@ const sampleTurnContext: TurnContext = {
30
38
  requestId: "req-abc",
31
39
  conversationId: "conv-xyz",
32
40
  turnIndex: 0,
41
+ pluginName: "sample-plugin",
33
42
  trust: sampleTrust,
34
43
  };
35
44
 
@@ -43,6 +52,43 @@ describe("plugin core types", () => {
43
52
  config: { parse: (input: unknown) => input },
44
53
  };
45
54
 
55
+ // `overflowReduce` has a concrete arg/result shape (PR 23). Uses a
56
+ // dedicated passthrough that returns a structurally-correct result so
57
+ // `satisfies Plugin` keeps verifying the signature.
58
+ const overflowReducePassthrough: Middleware<
59
+ OverflowReduceArgs,
60
+ OverflowReduceResult
61
+ > = async (args, _next, _ctx) => ({
62
+ messages: args.messages,
63
+ runMessages: args.runMessages,
64
+ injectionMode: "full",
65
+ reducerState: {
66
+ appliedTiers: [],
67
+ injectionMode: "full",
68
+ exhausted: true,
69
+ },
70
+ reducerCompacted: false,
71
+ attempts: 0,
72
+ });
73
+
74
+ // Slot-specific passthrough for the `compaction` pipeline — PR 25
75
+ // narrowed its args/result away from the generic `{ input: unknown }`
76
+ // placeholder, so the generic `passthrough` no longer satisfies its
77
+ // middleware signature. This dedicated middleware keeps the shape-only
78
+ // assertion for the slot without forcing every other slot to narrow.
79
+ const compactionPassthrough: Middleware<
80
+ CompactionArgs,
81
+ CompactionResult
82
+ > = async (args, next, _ctx) => next(args);
83
+
84
+ // `circuitBreaker` carries a concrete arg shape (pipeline wrapping
85
+ // landed ahead of the other slots) so it needs its own passthrough
86
+ // rather than reusing the generic placeholder.
87
+ const circuitPassthrough: Middleware<
88
+ CircuitBreakerArgs,
89
+ CircuitBreakerResult
90
+ > = async (args, next, _ctx) => next(args);
91
+
46
92
  const sampleTool: Tool = {
47
93
  name: "sample-tool",
48
94
  description: "Sample plugin tool",
@@ -86,10 +132,34 @@ describe("plugin core types", () => {
86
132
  body: "## Sample\n\nPlugin-provided skill body.",
87
133
  },
88
134
  ],
135
+ middleware: {
136
+ compaction: compactionPassthrough,
137
+ overflowReduce: overflowReducePassthrough,
138
+ circuitBreaker: circuitPassthrough,
139
+ },
89
140
  } satisfies Plugin;
90
141
 
91
142
  // Minimal runtime check so the test body is non-empty.
92
143
  expect(plugin.manifest.name).toBe("sample-plugin");
144
+ expect(plugin.middleware.compaction).toBe(compactionPassthrough);
145
+ });
146
+
147
+ test("PluginTimeoutError carries pipeline, plugin, and elapsed fields", () => {
148
+ const err = new PluginTimeoutError("compaction", "sample-plugin", 30000);
149
+ expect(err).toBeInstanceOf(Error);
150
+ expect(err.name).toBe("PluginTimeoutError");
151
+ expect(err.pipeline).toBe("compaction");
152
+ expect(err.pluginName).toBe("sample-plugin");
153
+ expect(err.elapsedMs).toBe(30000);
154
+ expect(err.message).toContain("compaction");
155
+ expect(err.message).toContain("30000");
156
+ expect(err.message).toContain("sample-plugin");
157
+ });
158
+
159
+ test("PluginTimeoutError omits plugin suffix when unknown", () => {
160
+ const err = new PluginTimeoutError("circuitBreaker", undefined, 1234);
161
+ expect(err.pluginName).toBeUndefined();
162
+ expect(err.message).not.toContain("offending plugin");
93
163
  });
94
164
 
95
165
  test("PluginExecutionError carries the plugin name and message", () => {
@@ -27,7 +27,7 @@ mock.module("../config/env.js", () => ({
27
27
  }));
28
28
 
29
29
  const _conversationMocks = new Map<string, unknown>();
30
- mock.module("../daemon/conversation-registry.js", () => ({
30
+ mock.module("../daemon/conversation-store.js", () => ({
31
31
  findConversation: (id: string) => _conversationMocks.get(id),
32
32
  }));
33
33
 
@@ -91,14 +91,11 @@ mock.module("../config/loader.js", () => ({
91
91
  let _conversationFactory: (() => Conversation) | undefined;
92
92
  let _approvalGenerator: unknown;
93
93
 
94
- mock.module("../daemon/conversation-registry.js", () => ({
94
+ mock.module("../daemon/conversation-store.js", () => ({
95
95
  findConversation: () => {
96
96
  if (!_conversationFactory) return undefined;
97
97
  return _conversationFactory();
98
98
  },
99
- }));
100
-
101
- mock.module("../daemon/conversation-store.js", () => ({
102
99
  getOrCreateConversation: async (..._args: unknown[]) => {
103
100
  if (!_conversationFactory)
104
101
  throw new Error("_conversationFactory not set in test");
@@ -5,8 +5,6 @@
5
5
  * parses it via the real frontmatter parser, and verifies that `skillFlagKey()`
6
6
  * returns the correct key and `resolveSkillStates()` correctly gates the skill.
7
7
  */
8
- import { readFileSync } from "node:fs";
9
- import { fileURLToPath } from "node:url";
10
8
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
9
 
12
10
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
@@ -227,34 +225,3 @@ describe("frontmatter feature-flag integration", () => {
227
225
  expect(resolvedOff.length).toBe(0);
228
226
  });
229
227
  });
230
-
231
- // ---------------------------------------------------------------------------
232
- // Bundled ACP skill: discoverability when ACP is disabled
233
- // ---------------------------------------------------------------------------
234
-
235
- describe("bundled acp skill discoverability", () => {
236
- test("acp skill resolves with the flag off and config.acp disabled (no frontmatter flag gate)", () => {
237
- // The ACP skill carries its own first-time-setup instructions, so it must
238
- // stay visible even when the acp flag and config.acp.enabled are both off.
239
- // Runtime enforcement happens in the ACP tools via isAcpEnabled instead.
240
- const skillMdPath = fileURLToPath(
241
- new URL("../config/bundled-skills/acp/SKILL.md", import.meta.url),
242
- );
243
- const skillMd = readFileSync(skillMdPath, "utf8");
244
-
245
- const skill = buildSkillSummary("acp", skillMd);
246
- expect(skill).not.toBeNull();
247
- expect(skill!.featureFlag).toBeUndefined();
248
- expect(skillFlagKey(skill!)).toBeUndefined();
249
-
250
- // acp flag at its registry default (off) and config.acp disabled.
251
- const config = makeConfig({
252
- acp: { enabled: false, maxConcurrentSessions: 4, agents: {} },
253
- } as Partial<AssistantConfig>);
254
-
255
- const resolved = resolveSkillStates([skill!], config);
256
- expect(resolved.length).toBe(1);
257
- expect(resolved[0].summary.id).toBe("acp");
258
- expect(resolved[0].state).toBe("enabled");
259
- });
260
- });
@@ -174,7 +174,7 @@ import { LLMSchema } from "../config/schemas/llm.js";
174
174
  import {
175
175
  clearConversations,
176
176
  setConversation,
177
- } from "../daemon/conversation-registry.js";
177
+ } from "../daemon/conversation-store.js";
178
178
  import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
179
179
  import { SubagentManager } from "../subagent/manager.js";
180
180
 
@@ -11,7 +11,7 @@ const capturedNotifications: {
11
11
  message: string;
12
12
  }[] = [];
13
13
 
14
- mock.module("../daemon/conversation-registry.js", () => ({
14
+ mock.module("../daemon/conversation-store.js", () => ({
15
15
  findConversation: (id: string) => ({
16
16
  enqueueMessage: (options: { content: string }) => {
17
17
  capturedNotifications.push({
@@ -23,6 +23,8 @@ mock.module("../daemon/conversation-registry.js", () => ({
23
23
  persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
24
24
  runAgentLoop: async () => {},
25
25
  }),
26
+ addConversation: () => {},
27
+ removeConversation: () => {},
26
28
  }));
27
29
 
28
30
  mock.module("../runtime/assistant-event-hub.js", () => ({
@@ -4,7 +4,7 @@ import {
4
4
  clearConversations,
5
5
  findConversation,
6
6
  setConversation,
7
- } from "../daemon/conversation-registry.js";
7
+ } from "../daemon/conversation-store.js";
8
8
  import type { ServerMessage } from "../daemon/message-protocol.js";
9
9
  import type { Message } from "../providers/types.js";
10
10
  import { SubagentManager } from "../subagent/manager.js";
@@ -11,7 +11,7 @@ const capturedNotifications: {
11
11
  message: string;
12
12
  }[] = [];
13
13
 
14
- mock.module("../daemon/conversation-registry.js", () => ({
14
+ mock.module("../daemon/conversation-store.js", () => ({
15
15
  findConversation: (id: string) => ({
16
16
  enqueueMessage: (options: { content: string }) => {
17
17
  capturedNotifications.push({
@@ -23,6 +23,8 @@ mock.module("../daemon/conversation-registry.js", () => ({
23
23
  persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
24
24
  runAgentLoop: async () => {},
25
25
  }),
26
+ addConversation: () => {},
27
+ removeConversation: () => {},
26
28
  }));
27
29
 
28
30
  mock.module("../runtime/assistant-event-hub.js", () => ({
@@ -36,7 +36,7 @@ mock.module("../memory/conversation-crud.js", () => ({
36
36
  */
37
37
  const capturedMessages: string[] = [];
38
38
 
39
- mock.module("../daemon/conversation-registry.js", () => ({
39
+ mock.module("../daemon/conversation-store.js", () => ({
40
40
  findConversation: (_id: string) => ({
41
41
  enqueueMessage: (options: { content: string }) => {
42
42
  capturedMessages.push(options.content);
@@ -45,6 +45,8 @@ mock.module("../daemon/conversation-registry.js", () => ({
45
45
  persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
46
46
  runAgentLoop: async () => {},
47
47
  }),
48
+ addConversation: () => {},
49
+ removeConversation: () => {},
48
50
  }));
49
51
 
50
52
  mock.module("../runtime/assistant-event-hub.js", () => ({
@@ -32,7 +32,7 @@ mock.module("../memory/conversation-crud.js", () => ({
32
32
  import {
33
33
  clearConversations,
34
34
  setConversation,
35
- } from "../daemon/conversation-registry.js";
35
+ } from "../daemon/conversation-store.js";
36
36
  import type { Message } from "../providers/types.js";
37
37
  import { getSubagentManager } from "../subagent/index.js";
38
38
  import { executeSubagentSpawn } from "../tools/subagent/spawn.js";