@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
@@ -25,14 +25,14 @@
25
25
  * `assignPages`, and `invalidateLanes` without process-global module mocks.
26
26
  */
27
27
 
28
- import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
29
- import type { AssistantConfig } from "../../../config/types.js";
30
- import { getMemoryCheckpoint, setMemoryCheckpoint } from "../../../memory/checkpoints.js";
31
- import type { MemoryJob } from "../../../memory/jobs-store.js";
32
- import { getPageIndex } from "../../../memory/v2/page-index.js";
33
- import { listPages, readPage, writePage } from "../../../memory/v2/page-store.js";
34
- import { getLogger } from "../../../util/logger.js";
35
- import { getWorkspaceDir } from "../../../util/platform.js";
28
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
29
+ import type { AssistantConfig } from "../../config/types.js";
30
+ import { getLogger } from "../../util/logger.js";
31
+ import { getWorkspaceDir } from "../../util/platform.js";
32
+ import { getMemoryCheckpoint, setMemoryCheckpoint } from "../checkpoints.js";
33
+ import type { MemoryJob } from "../jobs-store.js";
34
+ import { getPageIndex } from "../v2/page-index.js";
35
+ import { listPages, readPage, writePage } from "../v2/page-store.js";
36
36
  import { assignPages as realAssignPages } from "./assign.js";
37
37
  import { invalidateLanes as realInvalidateLanes } from "./shadow-plugin.js";
38
38
  import { loadLeafTree as realLoadLeafTree, resolveDataDir } from "./tree.js";
@@ -1,5 +1,5 @@
1
- import { readPage, renderPageContent } from "../../../memory/v2/page-store.js";
2
- import { getWorkspaceDir } from "../../../util/platform.js";
1
+ import { getWorkspaceDir } from "../../util/platform.js";
2
+ import { readPage, renderPageContent } from "../v2/page-store.js";
3
3
  import { renderCapabilityContent } from "./capabilities.js";
4
4
  import type { Slug } from "./types.js";
5
5
 
@@ -1,4 +1,4 @@
1
- import type { ContentBlock } from "../../../providers/types.js";
1
+ import type { ContentBlock } from "../../providers/types.js";
2
2
 
3
3
  /**
4
4
  * Text content block carrying a `cache_control` breakpoint with a 1-hour TTL.
@@ -38,9 +38,9 @@ import { join, relative, sep } from "node:path";
38
38
 
39
39
  import { parse as parseYaml } from "yaml";
40
40
 
41
- import { listPages, readPage, writePage } from "../../../memory/v2/page-store.js";
42
- import type { Provider } from "../../../providers/types.js";
43
- import { getLogger } from "../../../util/logger.js";
41
+ import type { Provider } from "../../providers/types.js";
42
+ import { getLogger } from "../../util/logger.js";
43
+ import { listPages, readPage, writePage } from "../v2/page-store.js";
44
44
  import { assignPages } from "./assign.js";
45
45
  import { loadCore } from "./core.js";
46
46
  import { invalidateLanes } from "./shadow-plugin.js";
@@ -1,4 +1,4 @@
1
- import { wrapMemoryBlock } from "../../../memory/memory-marker.js";
1
+ import { wrapMemoryBlock } from "../memory-marker.js";
2
2
  import { Slug } from "./types.js";
3
3
 
4
4
  /**
@@ -33,9 +33,9 @@ import { z } from "zod";
33
33
  import {
34
34
  extractToolUse,
35
35
  getConfiguredProvider,
36
- } from "../../../providers/provider-send-message.js";
37
- import type { Message, ToolDefinition } from "../../../providers/types.js";
38
- import { getLogger } from "../../../util/logger.js";
36
+ } from "../../providers/provider-send-message.js";
37
+ import type { Message, ToolDefinition } from "../../providers/types.js";
38
+ import { getLogger } from "../../util/logger.js";
39
39
  import { retryForResult } from "./llm-retry.js";
40
40
  import { cachedTextBlock } from "./provider-blocks.js";
41
41
  import type { LeafPath, LeafTree, TurnContext } from "./types.js";
@@ -7,10 +7,10 @@
7
7
  * across turns) and can't be reproduced after the fact.
8
8
  */
9
9
 
10
- import type { MemoryV3SelectionLog } from "../../../api/responses/memory-v3-selection-log.js";
11
- import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
12
- import { getConfig } from "../../../config/loader.js";
13
- import { getDb, getSqliteFrom } from "../../../memory/db-connection.js";
10
+ import type { MemoryV3SelectionLog } from "../../api/responses/memory-v3-selection-log.js";
11
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
12
+ import { getConfig } from "../../config/loader.js";
13
+ import { getDb, getSqliteFrom } from "../db-connection.js";
14
14
  import { renderV3PageContent } from "./page-content.js";
15
15
  import { renderMemoryBlock } from "./render-injection.js";
16
16
  import type { Slug } from "./types.js";
@@ -33,10 +33,10 @@ import { z } from "zod";
33
33
  import {
34
34
  extractToolUse,
35
35
  getConfiguredProvider,
36
- } from "../../../providers/provider-send-message.js";
37
- import type { Message, ToolDefinition } from "../../../providers/types.js";
38
- import { getLogger } from "../../../util/logger.js";
39
- import { mapLimit } from "../../../util/map-limit.js";
36
+ } from "../../providers/provider-send-message.js";
37
+ import type { Message, ToolDefinition } from "../../providers/types.js";
38
+ import { getLogger } from "../../util/logger.js";
39
+ import { mapLimit } from "../../util/map-limit.js";
40
40
  import { retryForResult } from "./llm-retry.js";
41
41
  import { cachedTextBlock } from "./provider-blocks.js";
42
42
  import { membersOf } from "./tree.js";
@@ -1,18 +1,18 @@
1
1
  /**
2
- * Memory v3 — flag-gated shadow/live orchestration engine.
2
+ * Memory v3 — flag-gated shadow/live injector.
3
3
  *
4
- * Runs the v3 orchestrator each turn and records its selection set to
5
- * `memory_v3_selections`. Two flags gate behavior:
4
+ * An {@link Injector} that runs the v3 orchestrator each turn and
5
+ * records its selection set to `memory_v3_selections`. Two flags gate its
6
+ * injection behavior:
6
7
  *
7
- * - `memory-v3-shadow` (live OFF): observation-only. {@link observeTurn}
8
- * orchestrates and logs the selection set; no injection is produced, so v2
9
- * injection is bit-for-bit identical — the only difference is the
10
- * side-effect telemetry write.
11
- * - `memory-v3-live`: live injection. The injector (`memoryV3Injector` in
12
- * `./injector.ts`) additionally renders the working-set selection into a
13
- * `<memory>` block and returns it at v2's dynamic-memory placement
8
+ * - `memory-v3-shadow` (and live OFF): observation-only. `produce()` returns
9
+ * `null`, so v2 injection is bit-for-bit identical whether the flag is on
10
+ * or off — the only difference is the side-effect telemetry write.
11
+ * - `memory-v3-live`: live injection. `produce()` additionally renders the
12
+ * working-set selection into a `<memory>` block via {@link renderMemoryBlock}
13
+ * and returns it as an injection block at v2's dynamic-memory placement
14
14
  * (`after-memory-prefix`). Selections are still logged.
15
- * - both OFF: orchestration is skipped entirely.
15
+ * - both OFF: `produce()` returns `null` and skips orchestration entirely.
16
16
  *
17
17
  * On each turn (either flag on):
18
18
  * 1. Lazy-init the v3 lanes ONCE across the whole process (leaf tree, core
@@ -22,45 +22,54 @@
22
22
  * 3. Run {@link orchestrate} and record its selection set to
23
23
  * `memory_v3_selections` with a best-effort lane attribution.
24
24
  *
25
- * {@link observeTurn} wraps everything after the flag read in try/catch — any
26
- * failure is logged and swallowed so it can never affect the live turn. The
27
- * injector treats a `null`/empty result as "no v3 injection", so v2 memory
28
- * remains the fallback rather than dropping all memory.
25
+ * Everything after the flag read is wrapped in try/catch — any failure is
26
+ * logged and swallowed so it can never affect the live turn. In live mode a
27
+ * failure returns `null` (no v3 injection); v2 suppression keys off BOTH the
28
+ * flag AND whether `produce()` actually returned a block, so a v3 failure (or
29
+ * empty selection) falls back to v2 memory rather than dropping all memory.
29
30
  */
30
31
 
31
32
  import { existsSync, readFileSync } from "node:fs";
32
33
 
33
- import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
34
- import { getConfig } from "../../../config/loader.js";
35
- import type { AssistantConfig } from "../../../config/schema.js";
36
- import { getMessages } from "../../../memory/conversation-crud.js";
37
- import { getDb, getSqliteFrom } from "../../../memory/db-connection.js";
38
- import { stringifyMessageContent } from "../../../memory/message-content.js";
39
- import { getPageIndex } from "../../../memory/v2/page-index.js";
40
- import { getLogger } from "../../../util/logger.js";
34
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
35
+ import { getConfig } from "../../config/loader.js";
36
+ import type { AssistantConfig } from "../../config/schema.js";
37
+ import { getMessages } from "../../memory/conversation-crud.js";
38
+ import { getDb, getSqliteFrom } from "../../memory/db-connection.js";
39
+ import { stringifyMessageContent } from "../../memory/message-content.js";
40
+ import {
41
+ type InjectionBlock,
42
+ type Injector,
43
+ type TurnContext as PluginTurnContext,
44
+ } from "../../plugins/types.js";
45
+ import { getLogger } from "../../util/logger.js";
41
46
  import {
42
47
  getWorkspaceDir,
43
48
  getWorkspacePromptPath,
44
- } from "../../../util/platform.js";
45
- import { stripCommentLines } from "../../../util/strip-comment-lines.js";
49
+ } from "../../util/platform.js";
50
+ import { stripCommentLines } from "../../util/strip-comment-lines.js";
51
+ import { getPageIndex } from "../v2/page-index.js";
46
52
  import { injectCapabilitiesLeaf, isCapabilitySlug } from "./capabilities.js";
47
53
  import { loadCore } from "./core.js";
48
54
  import type { NeedleIndex } from "./needle.js";
49
55
  import { buildNeedleIndex } from "./needle.js";
50
56
  import type { OrchestrateResult } from "./orchestrate.js";
51
57
  import { orchestrate } from "./orchestrate.js";
58
+ import { renderV3PageContent } from "./page-content.js";
59
+ import { renderMemoryBlock } from "./render-injection.js";
52
60
  import { coreSlugs, loadLeafTree, resolveDataDir } from "./tree.js";
53
61
  import {
54
62
  type LeafPath,
55
63
  type LeafTree,
64
+ MEMORY_V3_BLOCK_ID,
56
65
  type SelectionSource,
57
66
  type Slug,
58
67
  type TurnContext,
59
68
  } from "./types.js";
60
69
  import { WorkingSet } from "./working-set.js";
61
70
 
62
- export const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
63
- export const MEMORY_V3_LIVE = "memory-v3-live" as const;
71
+ const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
72
+ const MEMORY_V3_LIVE = "memory-v3-live" as const;
64
73
 
65
74
  const log = getLogger("memory-v3-shadow");
66
75
 
@@ -301,7 +310,7 @@ function writeSelections(
301
310
  * failures are logged and swallowed (returning `null`) so the live turn is
302
311
  * unaffected. Returns `null` when there is no user message to route on.
303
312
  */
304
- export async function observeTurn(
313
+ async function observeTurn(
305
314
  conversationId: string,
306
315
  turnIndex: number,
307
316
  ): Promise<OrchestrateResult | null> {
@@ -347,3 +356,56 @@ export async function runShadowObservation(
347
356
  if (!isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, getConfig())) return;
348
357
  await observeTurn(conversationId, turnIndex);
349
358
  }
359
+
360
+ /**
361
+ * The v3 injector. Reads both flags:
362
+ * - `memory-v3-live` on → orchestrate, log, render the working-set selection
363
+ * into a `<memory>` block, and return it at v2's dynamic-memory placement.
364
+ * - `memory-v3-shadow` on (live off) → orchestrate + log only, return `null`.
365
+ * - both off → return `null` (no orchestration).
366
+ *
367
+ * Empty selection and any failure return `null` (no v3 injection). v2
368
+ * suppression keys off BOTH the flag AND this return value, so a `null` here
369
+ * (failure or empty selection) falls back to v2 memory rather than dropping all
370
+ * memory.
371
+ */
372
+ export const memoryV3Injector: Injector = {
373
+ name: "memory-v3-shadow",
374
+ // High order so it sorts last; the live `<memory>` block uses the
375
+ // after-memory-prefix placement so it lands at the memory boundary regardless
376
+ // of this sort key, which only orders content-producing injectors.
377
+ order: 1000,
378
+ async produce(ctx: PluginTurnContext): Promise<InjectionBlock | null> {
379
+ const config = getConfig();
380
+ const live = isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config);
381
+ const shadow = isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config);
382
+ if (!live && !shadow) return null;
383
+
384
+ const result = await observeTurn(ctx.conversationId, ctx.turnIndex);
385
+ if (!live || !result) return null;
386
+
387
+ try {
388
+ // `renderMemoryBlock` returns "" for an empty selection; inject nothing.
389
+ const text = await renderMemoryBlock(
390
+ result.finalInjection,
391
+ renderV3PageContent,
392
+ );
393
+ if (text.length === 0) return null;
394
+ return {
395
+ id: MEMORY_V3_BLOCK_ID,
396
+ text,
397
+ // Mirror v2's dynamic `<memory>` block placement.
398
+ placement: "after-memory-prefix",
399
+ };
400
+ } catch (err) {
401
+ log.warn(
402
+ {
403
+ err: err instanceof Error ? err.message : String(err),
404
+ conversationId: ctx.conversationId,
405
+ },
406
+ "memory-v3 live render failed (non-fatal) — falling back to v2",
407
+ );
408
+ return null;
409
+ }
410
+ },
411
+ };
@@ -5,7 +5,7 @@ import { fileURLToPath } from "node:url";
5
5
 
6
6
  import { parse as parseYaml } from "yaml";
7
7
 
8
- import { getWorkspaceDir } from "../../../util/platform.js";
8
+ import { getWorkspaceDir } from "../../util/platform.js";
9
9
  import type {
10
10
  LeafFrontmatter,
11
11
  LeafNode,
@@ -34,6 +34,11 @@
34
34
  * for both plugin tool files and workspace tool files)
35
35
  * - {@link ToolContext} — passed to a plugin tool's `execute` method
36
36
  * - {@link ToolExecutionResult} — return shape of a plugin tool's `execute`
37
+ *
38
+ * Pipeline-argument types (`MemoryArgs`, `CompactionArgs`, etc.) currently
39
+ * live in `assistant/src/plugins/types.ts` and have not yet migrated into
40
+ * this package. A follow-up PR will move them into this surface as the
41
+ * per-pipeline schemas stabilize.
37
42
  */
38
43
 
39
44
  export type { HookName } from "./constants.js";
@@ -0,0 +1,93 @@
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,7 +1,7 @@
1
1
  {
2
- "name": "default-memory-v3-shadow",
2
+ "name": "default-circuit-breaker",
3
3
  "version": "1.0.0",
4
- "description": "First-party default plugin housing the memory-v3 shadow/live orchestration engine and its injector.",
4
+ "description": "First-party default plugin wrapping the assistant's built-in circuit-breaker pipeline with a passthrough implementation.",
5
5
  "private": true,
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -0,0 +1,39 @@
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
+ };
@@ -0,0 +1,25 @@
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,7 +1,7 @@
1
1
  {
2
2
  "name": "default-compaction",
3
3
  "version": "1.0.0",
4
- "description": "First-party default plugin providing the assistant's built-in conversation-history compaction.",
4
+ "description": "First-party default plugin wrapping the assistant's built-in compaction pipeline with a passthrough implementation.",
5
5
  "private": true,
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -1,24 +1,35 @@
1
1
  /**
2
2
  * Default `compaction` plugin.
3
3
  *
4
- * Compaction is implemented in `./compact.ts` as {@link defaultCompact}, which
5
- * the agent loop calls directly with a {@link CompactionContext}. The plugin
6
- * stays registered as a placeholder so it keeps a presence in the defaults
7
- * list while we decide how plugins should surface compaction; it contributes
8
- * no contract slot today.
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).
9
16
  */
10
17
 
11
18
  import { type Plugin } from "../../types.js";
19
+ import defaultCompactionMiddleware from "./middlewares/compaction.js";
12
20
  import pkg from "./package.json" with { type: "json" };
13
21
 
14
22
  /**
15
- * Manifest for the default compaction plugin. The registration happens in
16
- * `daemon/external-plugins-bootstrap.ts` before {@link bootstrapPlugins} fires
17
- * plugin `init()` hooks.
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.
18
26
  */
19
27
  export const defaultCompactionPlugin: Plugin = {
20
28
  manifest: {
21
29
  name: pkg.name,
22
30
  version: pkg.version,
23
31
  },
32
+ middleware: {
33
+ compaction: defaultCompactionMiddleware,
34
+ },
24
35
  };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Default `compaction` behavior: summarizes conversation history when the
3
+ * context window fills up.
4
+ *
5
+ * This module is side-effect free: importing it does not register any plugin.
6
+ *
7
+ * Delegates to the orchestrator's existing {@link ContextWindowManager}
8
+ * instance, read from `ctx.contextWindowManager` on the {@link TurnContext} as
9
+ * a typed optional field. The orchestrator is responsible for attaching that
10
+ * handle to the per-turn context. If the handle is missing, this throws a
11
+ * {@link PluginExecutionError} so the bug surfaces with clear attribution
12
+ * instead of a late `undefined.maybeCompact is not a function`.
13
+ */
14
+
15
+ import type {
16
+ ContextWindowCompactOptions,
17
+ ContextWindowManager,
18
+ ContextWindowResult,
19
+ } from "../../../context/window-manager.js";
20
+ import type { Message } from "../../../providers/types.js";
21
+ import {
22
+ type CompactionArgs,
23
+ type CompactionResult,
24
+ PluginExecutionError,
25
+ type TurnContext,
26
+ } from "../../types.js";
27
+
28
+ /**
29
+ * Name under which the default plugin registers. Exposed so tests and later
30
+ * plugins can assert registration order or override the default via
31
+ * composition.
32
+ */
33
+ export const DEFAULT_COMPACTION_PLUGIN_NAME = "default-compaction";
34
+
35
+ /**
36
+ * Read `contextWindowManager` off the turn context. Throws
37
+ * {@link PluginExecutionError} when absent so the failure attributes cleanly
38
+ * to the default plugin instead of manifesting as a later NPE.
39
+ */
40
+ function extractManager(ctx: TurnContext): ContextWindowManager {
41
+ const manager = ctx.contextWindowManager;
42
+ if (
43
+ manager == null ||
44
+ typeof manager !== "object" ||
45
+ typeof (manager as { maybeCompact?: unknown }).maybeCompact !== "function"
46
+ ) {
47
+ throw new PluginExecutionError(
48
+ "default-compaction: ctx.contextWindowManager is missing — orchestrator must attach it before invoking compaction",
49
+ DEFAULT_COMPACTION_PLUGIN_NAME,
50
+ );
51
+ }
52
+ return manager;
53
+ }
54
+
55
+ /**
56
+ * Run compaction for the turn: reads the context window manager off the turn
57
+ * context and returns the (possibly summarized) message history from
58
+ * `maybeCompact`.
59
+ */
60
+ export async function defaultCompactionTerminal(
61
+ args: CompactionArgs,
62
+ ctx: TurnContext,
63
+ ): Promise<CompactionResult> {
64
+ const manager = extractManager(ctx);
65
+ const messages = args.messages as Message[];
66
+ const options = args.options as ContextWindowCompactOptions | undefined;
67
+ const result: ContextWindowResult = await manager.maybeCompact(
68
+ messages,
69
+ args.signal,
70
+ options,
71
+ );
72
+ return result;
73
+ }
@@ -25,10 +25,11 @@
25
25
 
26
26
  import { registerPlugin, resetPluginRegistryForTests } from "../registry.js";
27
27
  import { type Plugin, PluginExecutionError } from "../types.js";
28
+ import { defaultCircuitBreakerPlugin } from "./circuit-breaker/register.js";
28
29
  import { defaultCompactionPlugin } from "./compaction/register.js";
29
30
  import { defaultEmptyResponsePlugin } from "./empty-response/register.js";
30
31
  import { defaultHistoryRepairPlugin } from "./history-repair/register.js";
31
- import { memoryV3ShadowPlugin } from "./memory-v3-shadow/register.js";
32
+ import { defaultOverflowReducePlugin } from "./overflow-reduce/register.js";
32
33
  import { defaultTitleGeneratePlugin } from "./title-generate/register.js";
33
34
  import { defaultToolErrorPlugin } from "./tool-error/register.js";
34
35
  import { defaultToolResultTruncatePlugin } from "./tool-result-truncate/register.js";
@@ -48,10 +49,11 @@ function getAllDefaultPlugins(): readonly Plugin[] {
48
49
  defaultToolResultTruncatePlugin,
49
50
  defaultEmptyResponsePlugin,
50
51
  defaultToolErrorPlugin,
52
+ defaultOverflowReducePlugin,
51
53
  defaultHistoryRepairPlugin,
52
54
  defaultCompactionPlugin,
55
+ defaultCircuitBreakerPlugin,
53
56
  defaultTitleGeneratePlugin,
54
- memoryV3ShadowPlugin,
55
57
  ];
56
58
  }
57
59
 
@@ -83,7 +85,7 @@ export function registerDefaultPlugins(): void {
83
85
  * so integration tests that exercise the full agent loop have a
84
86
  * production-parity plugin stack. Use this in `beforeEach` of tests that
85
87
  * dispatch through pipelines with a terminal that assumes the default
86
- * plugin handles every op (e.g. compaction).
88
+ * plugin handles every op (e.g. overflowReduce).
87
89
  *
88
90
  * Tests that specifically need an empty registry (pipeline-unit tests, the
89
91
  * plugin-registry tests themselves) should continue to call