@vellumai/assistant 0.8.8 → 0.8.9-staging.1

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 (340) hide show
  1. package/bun.lock +2 -2
  2. package/examples/plugins/echo/README.md +61 -60
  3. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  4. package/examples/plugins/echo/hooks/stop.ts +16 -0
  5. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  6. package/examples/plugins/echo/package.json +1 -2
  7. package/examples/plugins/echo/src/emit.ts +19 -0
  8. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  9. package/openapi.yaml +236 -6
  10. package/package.json +2 -2
  11. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +185 -140
  13. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  14. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  15. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  16. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  17. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  18. package/src/__tests__/agent-loop.test.ts +441 -96
  19. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  20. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  21. package/src/__tests__/anthropic-provider.test.ts +1 -1
  22. package/src/__tests__/app-control-flow.test.ts +1 -1
  23. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  24. package/src/__tests__/approval-cascade.test.ts +5 -4
  25. package/src/__tests__/approval-routes-http.test.ts +4 -1
  26. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  27. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  28. package/src/__tests__/channel-approvals.test.ts +1 -1
  29. package/src/__tests__/compaction-circuit.test.ts +258 -0
  30. package/src/__tests__/compaction-direct.test.ts +132 -0
  31. package/src/__tests__/compaction-events.test.ts +5 -5
  32. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -4
  33. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  34. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +59 -103
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +94 -189
  36. package/src/__tests__/conversation-agent-loop.test.ts +249 -490
  37. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  38. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -4
  39. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  40. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -4
  41. package/src/__tests__/conversation-process-callsite.test.ts +14 -14
  42. package/src/__tests__/conversation-provider-retry-repair.test.ts +18 -16
  43. package/src/__tests__/conversation-queue.test.ts +9 -9
  44. package/src/__tests__/conversation-runtime-assembly.test.ts +923 -231
  45. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  46. package/src/__tests__/conversation-slash-queue.test.ts +6 -4
  47. package/src/__tests__/conversation-slash-unknown.test.ts +6 -4
  48. package/src/__tests__/conversation-speed-override.test.ts +10 -9
  49. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  50. package/src/__tests__/conversation-workspace-cache-state.test.ts +23 -20
  51. package/src/__tests__/conversation-workspace-injection.test.ts +68 -6
  52. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +14 -11
  53. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  54. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  55. package/src/__tests__/db-acp-history.test.ts +101 -0
  56. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  57. package/src/__tests__/empty-response-hook.test.ts +1 -1
  58. package/src/__tests__/file-write-tool.test.ts +63 -0
  59. package/src/__tests__/gateway-only-guard.test.ts +12 -2
  60. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  61. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  62. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  63. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  64. package/src/__tests__/heartbeat-service.test.ts +1 -0
  65. package/src/__tests__/history-repair-hook.test.ts +1 -1
  66. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  67. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  68. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  69. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  70. package/src/__tests__/injector-background-turn.test.ts +13 -23
  71. package/src/__tests__/injector-chain.test.ts +268 -44
  72. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  73. package/src/__tests__/injector-document-comments.test.ts +97 -114
  74. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  75. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  76. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  77. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  78. package/src/__tests__/memory-retrieval-hook.test.ts +73 -6
  79. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  80. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  81. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  82. package/src/__tests__/plugin-bootstrap.test.ts +12 -23
  83. package/src/__tests__/plugin-registry.test.ts +3 -49
  84. package/src/__tests__/plugin-types.test.ts +0 -70
  85. package/src/__tests__/reaction-persistence.test.ts +1 -1
  86. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  87. package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
  88. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  89. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  90. package/src/__tests__/subagent-detail.test.ts +25 -7
  91. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  92. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  93. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  94. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  95. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  96. package/src/__tests__/title-generate-hook.test.ts +1 -1
  97. package/src/__tests__/tool-error-hook.test.ts +1 -1
  98. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  99. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  100. package/src/acp/__tests__/agent-process.test.ts +161 -0
  101. package/src/acp/__tests__/client-handler.test.ts +40 -0
  102. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  103. package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
  104. package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
  105. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  106. package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
  107. package/src/acp/agent-process.ts +61 -1
  108. package/src/acp/auto-install.test.ts +196 -0
  109. package/src/acp/auto-install.ts +177 -0
  110. package/src/acp/client-handler.ts +31 -0
  111. package/src/acp/feature-gate.test.ts +48 -0
  112. package/src/acp/feature-gate.ts +34 -0
  113. package/src/acp/prepare-agent-env.ts +83 -29
  114. package/src/acp/resolve-agent.test.ts +320 -7
  115. package/src/acp/resolve-agent.ts +182 -18
  116. package/src/acp/resume-hint.ts +25 -0
  117. package/src/acp/session-manager.ts +495 -73
  118. package/src/acp/types.ts +8 -0
  119. package/src/agent/compaction-circuit.ts +60 -102
  120. package/src/agent/loop.ts +390 -240
  121. package/src/api/responses/conversation-message.ts +14 -1
  122. package/src/approvals/guardian-request-resolvers.ts +1 -1
  123. package/src/background-wake/next-wake.ts +1 -0
  124. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  125. package/src/cli/commands/plugins.ts +43 -37
  126. package/src/cli/lib/__tests__/install-from-github.test.ts +429 -111
  127. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  128. package/src/cli/lib/__tests__/plugin-details.test.ts +372 -0
  129. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +220 -0
  130. package/src/cli/lib/__tests__/search-plugins.test.ts +226 -32
  131. package/src/cli/lib/install-from-github.ts +464 -55
  132. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  133. package/src/cli/lib/plugin-details.ts +409 -0
  134. package/src/cli/lib/plugin-marketplace.ts +197 -0
  135. package/src/cli/lib/search-plugins.ts +195 -29
  136. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  137. package/src/config/acp-defaults.test.ts +10 -0
  138. package/src/config/acp-defaults.ts +6 -0
  139. package/src/config/bundled-skills/acp/SKILL.md +83 -31
  140. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  141. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  142. package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
  143. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  144. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  145. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  146. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  147. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  148. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  149. package/src/config/bundled-tool-registry.ts +2 -0
  150. package/src/config/feature-flag-registry.json +14 -5
  151. package/src/config/schemas/heartbeat.ts +9 -0
  152. package/src/context/strip-injections.ts +8 -2
  153. package/src/context/window-manager.ts +27 -13
  154. package/src/daemon/conversation-agent-loop-handlers.ts +10 -35
  155. package/src/daemon/conversation-agent-loop.ts +167 -1005
  156. package/src/daemon/conversation-lifecycle.ts +11 -255
  157. package/src/daemon/conversation-process.ts +8 -136
  158. package/src/daemon/conversation-registry.ts +159 -0
  159. package/src/daemon/conversation-runtime-assembly.ts +293 -392
  160. package/src/daemon/conversation-store.ts +9 -90
  161. package/src/daemon/conversation-surfaces.ts +24 -8
  162. package/src/daemon/conversation-workspace.ts +17 -0
  163. package/src/daemon/conversation.ts +383 -56
  164. package/src/daemon/external-plugins-bootstrap.ts +14 -19
  165. package/src/daemon/handlers/conversations.ts +3 -1
  166. package/src/daemon/handlers/skills.ts +4 -1
  167. package/src/daemon/host-proxy-preactivation.ts +1 -3
  168. package/src/daemon/lifecycle.ts +21 -0
  169. package/src/daemon/server.ts +2 -0
  170. package/src/daemon/wake-conversation-ops.ts +269 -0
  171. package/src/embedded/plugin-api.ts +2 -2
  172. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  173. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  174. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  175. package/src/heartbeat/heartbeat-service.ts +26 -0
  176. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  177. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  178. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  179. package/src/ipc/skill-routes/memory.ts +4 -2
  180. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  181. package/src/memory/conversation-crud.ts +29 -19
  182. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  183. package/src/memory/db-init.ts +2 -0
  184. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  185. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  186. package/src/memory/jobs-worker.ts +25 -1
  187. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  188. package/src/memory/migrations/index.ts +1 -0
  189. package/src/memory/schema/acp.ts +4 -0
  190. package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
  191. package/src/memory/v2/consolidation-job.ts +13 -4
  192. package/src/plugin-api/constants.ts +4 -0
  193. package/src/plugin-api/index.ts +6 -5
  194. package/src/plugin-api/types.ts +75 -0
  195. package/src/plugins/defaults/compaction/compact.ts +59 -0
  196. package/src/plugins/defaults/compaction/manager-store.ts +44 -0
  197. package/src/plugins/defaults/compaction/package.json +1 -2
  198. package/src/plugins/defaults/empty-response/package.json +0 -1
  199. package/src/plugins/defaults/history-repair/package.json +0 -1
  200. package/src/plugins/defaults/index.ts +135 -26
  201. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +103 -38
  202. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +167 -56
  203. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  204. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  205. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  206. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
  207. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +9 -6
  208. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
  209. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +8 -5
  210. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
  211. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
  212. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +10 -5
  213. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
  214. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +5 -5
  215. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +16 -17
  216. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -2
  217. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +9 -5
  218. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +5 -2
  219. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  220. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  221. package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
  222. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +15 -8
  223. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +2 -2
  224. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  225. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
  226. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/provider-blocks.ts +1 -1
  227. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +7 -3
  228. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
  229. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +5 -5
  230. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
  231. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +7 -7
  232. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +32 -94
  233. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
  234. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +1 -1
  235. package/src/plugins/defaults/title-generate/package.json +0 -1
  236. package/src/plugins/defaults/tool-error/package.json +0 -1
  237. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  238. package/src/plugins/pipeline.ts +6 -293
  239. package/src/plugins/registry.ts +9 -37
  240. package/src/plugins/types.ts +76 -381
  241. package/src/plugins/user-loader.ts +30 -127
  242. package/src/proactive-artifact/aux-message-injector.ts +1 -1
  243. package/src/proactive-artifact/job.test.ts +1 -1
  244. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  245. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +35 -3
  246. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  247. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  248. package/src/runtime/agent-wake.ts +108 -209
  249. package/src/runtime/assistant-event-hub.ts +1 -1
  250. package/src/runtime/channel-approvals.ts +1 -1
  251. package/src/runtime/interactive-ui.ts +1 -1
  252. package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
  253. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  254. package/src/runtime/routes/__tests__/plugins-routes.test.ts +398 -73
  255. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  256. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  257. package/src/runtime/routes/acp-routes.test.ts +89 -25
  258. package/src/runtime/routes/acp-routes.ts +81 -29
  259. package/src/runtime/routes/approval-routes.ts +1 -1
  260. package/src/runtime/routes/browser-routes.ts +1 -1
  261. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  262. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  264. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  265. package/src/runtime/routes/conversation-routes.ts +28 -2
  266. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  267. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  268. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  269. package/src/runtime/routes/host-cu-routes.ts +1 -1
  270. package/src/runtime/routes/identity-routes.ts +18 -3
  271. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  272. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  273. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  274. package/src/runtime/routes/memory-v3-routes.ts +16 -6
  275. package/src/runtime/routes/playground/helpers.ts +1 -1
  276. package/src/runtime/routes/plugins-routes.ts +336 -35
  277. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  278. package/src/runtime/routes/work-items-routes.ts +2 -4
  279. package/src/runtime/services/conversation-serializer.ts +1 -1
  280. package/src/signals/cancel.ts +2 -4
  281. package/src/subagent/manager.ts +21 -5
  282. package/src/tools/acp/context.ts +20 -0
  283. package/src/tools/acp/list-agents.test.ts +7 -1
  284. package/src/tools/acp/spawn.test.ts +158 -55
  285. package/src/tools/acp/spawn.ts +47 -72
  286. package/src/tools/acp/steer.test.ts +105 -8
  287. package/src/tools/acp/steer.ts +48 -17
  288. package/src/tools/apps/executors.ts +13 -8
  289. package/src/tools/filesystem/write.ts +34 -0
  290. package/src/tools/subagent/spawn.ts +2 -4
  291. package/src/tools/ui-surface/definitions.ts +25 -5
  292. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  293. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  294. package/docs/plugins.md +0 -832
  295. package/examples/plugins/echo/register.ts +0 -143
  296. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  297. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  298. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  299. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  300. package/src/__tests__/pipeline-runner.test.ts +0 -554
  301. package/src/__tests__/plugin-external-api.test.ts +0 -68
  302. package/src/daemon/wake-target-adapter.ts +0 -253
  303. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  304. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  305. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  306. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  307. package/src/plugins/defaults/compaction/register.ts +0 -35
  308. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  309. package/src/plugins/defaults/empty-response/register.ts +0 -23
  310. package/src/plugins/defaults/history-repair/register.ts +0 -24
  311. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  312. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  313. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  314. package/src/plugins/defaults/title-generate/register.ts +0 -35
  315. package/src/plugins/defaults/tool-error/register.ts +0 -23
  316. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  317. package/src/plugins/external-api.ts +0 -104
  318. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
  319. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
  320. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  321. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  322. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +0 -0
  323. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
  324. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/provider-blocks.test.ts +0 -0
  325. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
  326. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
  327. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  328. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  329. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
  330. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  331. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  332. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  333. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  334. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  335. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  336. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
  337. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
  338. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
  339. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
  340. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
@@ -100,7 +100,7 @@ mock.module("../config/loader.js", () => ({
100
100
  // Can be a number (constant), a no-arg function, or a function that
101
101
  // receives the messages array for dynamic behavior based on content.
102
102
  // Both the calibrated entry point (`estimatePromptTokens`, which backs the
103
- // preflight overflow gate and the convergence path) and the raw entry point
103
+ // loop's budget gate and the convergence path) and the raw entry point
104
104
  // (`estimatePromptTokensRaw`, used by the pre-send calibration capture) are
105
105
  // stubbed so either call site can drive the test.
106
106
  let mockEstimateTokens: number | ((msgs?: Message[]) => number) = 1000;
@@ -113,7 +113,7 @@ mock.module("../context/token-estimator.js", () => ({
113
113
  typeof mockEstimateTokens === "function"
114
114
  ? mockEstimateTokens(msgs)
115
115
  : mockEstimateTokens,
116
- // The preflight overflow gate calls this calibrated wrapper directly, so it
116
+ // The loop's budget gate calls this calibrated wrapper directly, so it
117
117
  // must honor `mockEstimateTokens` too — otherwise the real implementation
118
118
  // (which sums tool tokens onto the real calibrated estimate) ignores the
119
119
  // per-test value and the overflow scenarios below never trigger.
@@ -202,7 +202,7 @@ mock.module("../memory/conversation-crud.js", () => ({
202
202
  updateMessageMetadata: () => {},
203
203
  setLastNotifiedInferenceProfile: () => {},
204
204
  getLastUserTimestampBefore: () => 0,
205
- getConversationOverrideProfileFromRow: () => undefined,
205
+ resolveOverrideProfile: () => undefined,
206
206
  reserveMessage: mock(async () => ({ id: "msg-reserve" })),
207
207
  }));
208
208
 
@@ -422,10 +422,8 @@ mock.module("../memory/archive-store.js", () => ({
422
422
  // ── Imports (after mocks) ────────────────────────────────────────────
423
423
 
424
424
  import { AgentLoop } from "../agent/loop.js";
425
- import {
426
- type AgentLoopConversationContext,
427
- runAgentLoopImpl,
428
- } from "../daemon/conversation-agent-loop.js";
425
+ import type { Conversation } from "../daemon/conversation.js";
426
+ import { runAgentLoopImpl } from "../daemon/conversation-agent-loop.js";
429
427
  import {
430
428
  createMockProvider,
431
429
  type ScriptedResponse,
@@ -436,13 +434,13 @@ import {
436
434
  // ── Test helpers ─────────────────────────────────────────────────────
437
435
 
438
436
  function makeCtx(
439
- overrides?: Partial<AgentLoopConversationContext> & {
437
+ overrides?: Partial<Conversation> & {
440
438
  providerResponses?: ScriptedResponse[];
441
439
  loopProvider?: Provider;
442
440
  loopTools?: ToolDefinition[];
443
441
  toolExecutor?: LoopToolExecutor;
444
442
  },
445
- ): AgentLoopConversationContext {
443
+ ): Conversation {
446
444
  const {
447
445
  providerResponses,
448
446
  loopProvider,
@@ -465,7 +463,9 @@ function makeCtx(
465
463
  providerResponses ?? [textResponse("response")],
466
464
  loopProviderName,
467
465
  ).provider;
468
- const agentLoop = new AgentLoop(provider, "system prompt", {
466
+ const agentLoop = new AgentLoop({
467
+ provider: provider,
468
+ systemPrompt: "system prompt",
469
469
  conversationId,
470
470
  tools: loopTools ?? [],
471
471
  toolExecutor,
@@ -495,13 +495,14 @@ function makeCtx(
495
495
  usage: { inputTokens: 0, outputTokens: 0 },
496
496
  stopReason: "end_turn",
497
497
  }),
498
- } as unknown as AgentLoopConversationContext["provider"],
498
+ } as unknown as Conversation["provider"],
499
499
  systemPrompt: "system prompt",
500
500
 
501
501
  contextWindowManager: {
502
+ updateConfig: () => {},
502
503
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
503
504
  maybeCompact: async () => ({ compacted: false }),
504
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
505
+ } as unknown as Conversation["contextWindowManager"],
505
506
  contextCompactedMessageCount: 0,
506
507
  contextCompactedAt: null,
507
508
 
@@ -515,8 +516,6 @@ function makeCtx(
515
516
  currentTurnSurfaces: [],
516
517
 
517
518
  workingDir: "/tmp",
518
- workspaceTopLevelContext: null,
519
- workspaceTopLevelDirty: false,
520
519
  channelCapabilities: undefined,
521
520
  commandIntent: undefined,
522
521
  trustContext: undefined,
@@ -526,15 +525,15 @@ function makeCtx(
526
525
  preactivatedSkillIds: undefined,
527
526
  skillProjectionState: new Map(),
528
527
  skillProjectionCache:
529
- new Map() as unknown as AgentLoopConversationContext["skillProjectionCache"],
528
+ new Map() as unknown as Conversation["skillProjectionCache"],
530
529
 
531
530
  traceEmitter: {
532
531
  emit: () => {},
533
- } as unknown as AgentLoopConversationContext["traceEmitter"],
532
+ } as unknown as Conversation["traceEmitter"],
534
533
  profiler: {
535
534
  startRequest: () => {},
536
535
  emitSummary: () => {},
537
- } as unknown as AgentLoopConversationContext["profiler"],
536
+ } as unknown as Conversation["profiler"],
538
537
  usageStats: {
539
538
  totalInputTokens: 0,
540
539
  totalOutputTokens: 0,
@@ -547,13 +546,12 @@ function makeCtx(
547
546
  lastAttachmentWarnings: [],
548
547
 
549
548
  hasNoClient: false,
550
- prompter: {} as unknown as AgentLoopConversationContext["prompter"],
551
- queue: {} as unknown as AgentLoopConversationContext["queue"],
549
+ prompter: {} as unknown as Conversation["prompter"],
550
+ queue: {} as unknown as Conversation["queue"],
552
551
 
553
552
  getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
554
553
  commitTurnChanges: async () => {},
555
554
 
556
- refreshWorkspaceTopLevelContextIfNeeded: () => {},
557
555
  markWorkspaceTopLevelDirty: () => {},
558
556
  emitActivityState: () => {},
559
557
  getQueueDepth: () => 0,
@@ -580,10 +578,10 @@ function makeCtx(
580
578
  }),
581
579
  retrackCachedNodes: () => {},
582
580
  recordPkbQueryVectors: () => {},
583
- } as unknown as AgentLoopConversationContext["graphMemory"],
581
+ } as unknown as Conversation["graphMemory"],
584
582
 
585
583
  ...ctxOverrides,
586
- } as AgentLoopConversationContext;
584
+ } as unknown as Conversation;
587
585
  }
588
586
 
589
587
  /**
@@ -651,10 +649,9 @@ beforeEach(() => {
651
649
  recordUsageMock.mockClear();
652
650
  setAgentLoopExitReasonOnLatestLogMock.mockClear();
653
651
  addMessageMock.mockClear();
654
- // Reset the plugin registry and re-register every default so the
655
- // orchestrator's pipelines (`overflowReduce`, `persistence`, …) dispatch to
656
- // the default middleware, which in turn hits the mocked collaborators
657
- // (`reduceContextOverflow`, `syncMessageToDisk`, …) these tests install.
652
+ // Reset the plugin registry and re-register every default so the compaction
653
+ // pipeline dispatches to the default middleware, which in turn hits the
654
+ // mocked collaborators (`syncMessageToDisk`, …) these tests install.
658
655
  resetPluginRegistryAndRegisterDefaults();
659
656
  });
660
657
 
@@ -768,9 +765,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
768
765
  isError: false,
769
766
  }),
770
767
  contextWindowManager: {
768
+ updateConfig: () => {},
771
769
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
772
770
  maybeCompact: async () => ({ compacted: false }),
773
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
771
+ } as unknown as Conversation["contextWindowManager"],
774
772
  });
775
773
 
776
774
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -797,9 +795,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
797
795
  const events: ServerMessage[] = [];
798
796
  let reducerCalled = false;
799
797
 
800
- // GIVEN the estimator reports 185k under the 190k preflight budget
801
- // (200k * 0.95), so the turn proceeds to the provider rather than
802
- // compacting up front.
798
+ // GIVEN the estimator reports 185k and the context manager's compaction
799
+ // is a no-op, so the first call proceeds to the provider without any
800
+ // up-front reduction.
803
801
  mockEstimateTokens = 185_000;
804
802
 
805
803
  // AND the post-run convergence reducer successfully compacts
@@ -842,9 +840,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
842
840
  const ctx = makeCtx({
843
841
  loopProvider: provider,
844
842
  contextWindowManager: {
843
+ updateConfig: () => {},
845
844
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
846
845
  maybeCompact: async () => ({ compacted: false }),
847
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
846
+ } as unknown as Conversation["contextWindowManager"],
848
847
  });
849
848
 
850
849
  // WHEN the turn runs
@@ -918,9 +917,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
918
917
  const ctx = makeCtx({
919
918
  loopProvider: provider,
920
919
  contextWindowManager: {
920
+ updateConfig: () => {},
921
921
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
922
922
  maybeCompact: async () => ({ compacted: false }),
923
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
923
+ } as unknown as Conversation["contextWindowManager"],
924
924
  });
925
925
 
926
926
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1005,9 +1005,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1005
1005
  loopProvider: provider,
1006
1006
  messages: longHistory,
1007
1007
  contextWindowManager: {
1008
+ updateConfig: () => {},
1008
1009
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1009
1010
  maybeCompact: async () => ({ compacted: false }),
1010
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1011
+ } as unknown as Conversation["contextWindowManager"],
1011
1012
  });
1012
1013
 
1013
1014
  await runAgentLoopImpl(ctx, "analyze this", "msg-1", (msg) =>
@@ -1087,6 +1088,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1087
1088
  isError: false,
1088
1089
  }),
1089
1090
  contextWindowManager: {
1091
+ updateConfig: () => {},
1090
1092
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1091
1093
  maybeCompact: async (
1092
1094
  _msgs: Message[],
@@ -1118,7 +1120,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1118
1120
  }
1119
1121
  return { compacted: false };
1120
1122
  },
1121
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1123
+ } as unknown as Conversation["contextWindowManager"],
1122
1124
  });
1123
1125
 
1124
1126
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1187,6 +1189,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1187
1189
  isError: false,
1188
1190
  }),
1189
1191
  contextWindowManager: {
1192
+ updateConfig: () => {},
1190
1193
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1191
1194
  maybeCompact: async () => {
1192
1195
  compactionCalled = true;
@@ -1211,7 +1214,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1211
1214
  summaryModel: "mock-model",
1212
1215
  };
1213
1216
  },
1214
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1217
+ } as unknown as Conversation["contextWindowManager"],
1215
1218
  });
1216
1219
 
1217
1220
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1293,6 +1296,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1293
1296
  isError: false,
1294
1297
  }),
1295
1298
  contextWindowManager: {
1299
+ updateConfig: () => {},
1296
1300
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1297
1301
  maybeCompact: async () => {
1298
1302
  compactionCalled = true;
@@ -1317,7 +1321,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1317
1321
  summaryModel: "mock-model",
1318
1322
  };
1319
1323
  },
1320
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1324
+ } as unknown as Conversation["contextWindowManager"],
1321
1325
  });
1322
1326
 
1323
1327
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => {
@@ -1360,14 +1364,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1360
1364
 
1361
1365
  // Budget = 200_000 * 0.95 = 190_000
1362
1366
  // Mid-loop threshold = 190_000 * 0.85 = 161_500
1363
- let estimateCallCount = 0;
1364
- mockEstimateTokens = () => {
1365
- estimateCallCount++;
1366
- // Preflight: below budget
1367
- if (estimateCallCount === 1) return 100_000;
1368
- // Every checkpoint call: above threshold — always triggers yield
1369
- return 170_000;
1370
- };
1367
+ // Every estimate is above the threshold, so the first-call gate compacts
1368
+ // before the first provider call and every checkpoint trips the yield.
1369
+ mockEstimateTokens = 170_000;
1371
1370
 
1372
1371
  // The convergence reducer reduces tokens enough for the rerun to recover.
1373
1372
  let convergenceReducerCalled = false;
@@ -1410,6 +1409,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1410
1409
  ],
1411
1410
  toolExecutor: async () => ({ content: "output", isError: false }),
1412
1411
  contextWindowManager: {
1412
+ updateConfig: () => {},
1413
1413
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1414
1414
  maybeCompact: async () => {
1415
1415
  compactionCallCount++;
@@ -1441,7 +1441,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1441
1441
  summaryModel: "mock-model",
1442
1442
  };
1443
1443
  },
1444
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1444
+ } as unknown as Conversation["contextWindowManager"],
1445
1445
  });
1446
1446
 
1447
1447
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1480,16 +1480,11 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1480
1480
 
1481
1481
  // Budget = 200_000 * 0.95 = 190_000
1482
1482
  // Mid-loop threshold = 190_000 * 0.85 = 161_500
1483
- let estimateCallCount = 0;
1484
- mockEstimateTokens = () => {
1485
- estimateCallCount++;
1486
- // Preflight: below budget.
1487
- if (estimateCallCount === 1) return 100_000;
1488
- // Every checkpoint estimate: above threshold — always trips the
1489
- // yield. Simulates a long turn where each tool call's result
1490
- // inflates the context past 85% even after a successful compaction.
1491
- return 170_000;
1492
- };
1483
+ // Every estimate is above the threshold: the first-call gate compacts
1484
+ // before the first provider call, and each subsequent checkpoint trips
1485
+ // the yield even after a successful compaction (each tool result inflates
1486
+ // the context back past 85%).
1487
+ mockEstimateTokens = 170_000;
1493
1488
 
1494
1489
  // A single tool round reaches one checkpoint; the in-loop budget gate
1495
1490
  // trips there and compaction runs in place. The loop continues the run
@@ -1518,6 +1513,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1518
1513
  ],
1519
1514
  toolExecutor: async () => ({ content: "output", isError: false }),
1520
1515
  contextWindowManager: {
1516
+ updateConfig: () => {},
1521
1517
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1522
1518
  maybeCompact: async () => {
1523
1519
  compactionCallCount++;
@@ -1542,7 +1538,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1542
1538
  summaryModel: "mock-model",
1543
1539
  };
1544
1540
  },
1545
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1541
+ } as unknown as Conversation["contextWindowManager"],
1546
1542
  });
1547
1543
 
1548
1544
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1633,6 +1629,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1633
1629
  ],
1634
1630
  toolExecutor: async () => ({ content: "output", isError: false }),
1635
1631
  contextWindowManager: {
1632
+ updateConfig: () => {},
1636
1633
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1637
1634
  // Under the new architecture (Compaction Re-homing Arc, Bullet 1)
1638
1635
  // the retry budget lives inside `ContextWindowManager._maybeCompact`,
@@ -1660,7 +1657,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1660
1657
  summaryModel: "mock-model",
1661
1658
  exhausted: true,
1662
1659
  }),
1663
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1660
+ } as unknown as Conversation["contextWindowManager"],
1664
1661
  });
1665
1662
 
1666
1663
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1680,124 +1677,6 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1680
1677
  );
1681
1678
  });
1682
1679
 
1683
- // ── Test 8 ────────────────────────────────────────────────────────
1684
- // BUG: The preflight overflow reducer's budget check uses
1685
- // step.estimatedTokens (computed on bare ctx.messages) without
1686
- // accounting for tokens added by applyRuntimeInjections(). This
1687
- // causes the reducer to stop early when the bare estimate is under
1688
- // budget, even though post-injection tokens exceed it — leading to
1689
- // a wasted provider round-trip that gets rejected.
1690
- //
1691
- // After fix: the budget check re-estimates on runMessages (with
1692
- // injections) so the reducer continues to the next tier.
1693
- test("preflight reducer continues when post-injection tokens exceed budget", async () => {
1694
- const events: ServerMessage[] = [];
1695
-
1696
- // Injections add an extra message, bumping the token count.
1697
- const injectionMessage: Message = {
1698
- role: "user" as const,
1699
- content: [
1700
- {
1701
- type: "text" as const,
1702
- text: "injected context " + "x".repeat(500),
1703
- },
1704
- ],
1705
- };
1706
- mockApplyRuntimeInjections = (msgs) => [...msgs, injectionMessage];
1707
-
1708
- // Budget = 200_000 * 0.95 = 190_000
1709
- // The estimator returns different values based on whether the
1710
- // injection message is present:
1711
- // - bare history (no injection msg) → 195_000 (triggers preflight)
1712
- // - after tier 1 bare → 185_000 (under budget, would stop early without fix)
1713
- // - after tier 1 with injection → 195_000 (still over budget)
1714
- // - after tier 2 bare → 170_000
1715
- // - after tier 2 with injection → 175_000 (under budget, reducer stops)
1716
- let reducerCallCount = 0;
1717
- mockEstimateTokens = (msgs?: Message[]) => {
1718
- const hasInjection = msgs?.some(
1719
- (m) =>
1720
- m.role === "user" &&
1721
- Array.isArray(m.content) &&
1722
- m.content.some(
1723
- (b: { type: string; text?: string }) =>
1724
- b.type === "text" &&
1725
- typeof b.text === "string" &&
1726
- b.text.startsWith("injected context"),
1727
- ),
1728
- );
1729
- if (reducerCallCount === 0) {
1730
- // Before any reduction: preflight check on runMessages (with injection)
1731
- return 195_000;
1732
- }
1733
- if (reducerCallCount === 1) {
1734
- // After tier 1
1735
- return hasInjection ? 195_000 : 185_000;
1736
- }
1737
- // After tier 2
1738
- return hasInjection ? 175_000 : 170_000;
1739
- };
1740
-
1741
- mockReducerStepFn = (msgs: Message[]) => {
1742
- reducerCallCount++;
1743
- const tier =
1744
- reducerCallCount === 1 ? "forced_compaction" : "tool_result_truncation";
1745
- return {
1746
- messages: msgs,
1747
- tier,
1748
- state: {
1749
- appliedTiers:
1750
- reducerCallCount === 1
1751
- ? ["forced_compaction"]
1752
- : ["forced_compaction", "tool_result_truncation"],
1753
- injectionMode: "full" as const,
1754
- exhausted: reducerCallCount >= 2,
1755
- },
1756
- // Bare-history estimate (what the reducer sees on ctx.messages)
1757
- estimatedTokens: reducerCallCount === 1 ? 185_000 : 170_000,
1758
- compactionResult: {
1759
- compacted: true,
1760
- messages: msgs,
1761
- compactedPersistedMessages: 5,
1762
- summaryText: "Summary",
1763
- previousEstimatedInputTokens: 195_000,
1764
- estimatedInputTokens: reducerCallCount === 1 ? 185_000 : 170_000,
1765
- maxInputTokens: 200_000,
1766
- thresholdTokens: 160_000,
1767
- compactedMessages: 10,
1768
- summaryCalls: 1,
1769
- summaryInputTokens: 500,
1770
- summaryOutputTokens: 200,
1771
- summaryModel: "mock-model",
1772
- },
1773
- };
1774
- };
1775
-
1776
- // The preflight overflow reducer runs in the orchestrator before the loop,
1777
- // so a single successful provider turn is enough to drive the path.
1778
- const ctx = makeCtx({
1779
- providerResponses: [textResponse("done")],
1780
- contextWindowManager: {
1781
- shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1782
- maybeCompact: async () => ({ compacted: false }),
1783
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1784
- });
1785
-
1786
- await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
1787
-
1788
- // The reducer must be called twice — the first tier's bare estimate
1789
- // (185k) is under budget (190k), but post-injection tokens (195k)
1790
- // still exceed it. Without the fix, the reducer would stop after
1791
- // tier 1 and the provider call would likely fail.
1792
- expect(reducerCallCount).toBe(2);
1793
-
1794
- // Should succeed without errors
1795
- const conversationError = events.find(
1796
- (e) => e.type === "conversation_error",
1797
- );
1798
- expect(conversationError).toBeUndefined();
1799
- });
1800
-
1801
1680
  // ── Test 9 ────────────────────────────────────────────────────────
1802
1681
  // When the `auto_compress_latest_turn` rerun (the last layer of the
1803
1682
  // overflow-recovery ladder) still yields at the mid-loop checkpoint,
@@ -1854,14 +1733,15 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1854
1733
  toolUseResponse("tu-1", "bash", { command: "ls" }),
1855
1734
  ]);
1856
1735
 
1857
- // `maybeCompact` is invoked through three distinct call sites:
1858
- // 1. Start-of-turn compaction (no `force` option) return a no-op
1859
- // so the start-of-turn pass doesn't perturb state. The mock's
1860
- // `shouldCompact` already returns `needed: false`, but the
1861
- // orchestrator still invokes the compaction pipeline.
1862
- // 2. Mid-loop after the initial agent-loop yield (`force: true`) —
1863
- // must signal `exhausted: true` so the daemon escalates to the
1864
- // convergence reducer instead of looping forever.
1736
+ // Every forced `maybeCompact` is invoked through three distinct call
1737
+ // sites, all owned by the loop's pre-call budget gate / recovery ladder:
1738
+ // 1. First-call (turn-start) gate (`force: true`) the loop now owns
1739
+ // the turn-start compaction. It succeeds, but the mocked estimate
1740
+ // stays above the mid-loop threshold, so the turn proceeds and the
1741
+ // mid-loop gate still trips on the next iteration.
1742
+ // 2. Mid-loop after the first tool turn (`force: true`) must signal
1743
+ // `exhausted: true` so the daemon escalates to the convergence
1744
+ // reducer instead of looping forever.
1865
1745
  // 3. auto_compress_latest_turn emergency compaction (`force: true`,
1866
1746
  // `minKeepRecentUserTurns: 0`) — succeeds and drops tokens below
1867
1747
  // threshold; the subsequent rerun yields again and is classified
@@ -1881,22 +1761,47 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1881
1761
  ],
1882
1762
  toolExecutor: async () => ({ content: "output", isError: false }),
1883
1763
  contextWindowManager: {
1764
+ updateConfig: () => {},
1884
1765
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1885
1766
  maybeCompact: async (
1886
1767
  _msgs: Message[],
1887
1768
  _signal: AbortSignal,
1888
1769
  opts?: { force?: boolean },
1889
1770
  ) => {
1890
- // Start-of-turn calls pass no `force` option; route them to a
1891
- // no-op so only the mid-loop and emergency paths drive the test.
1771
+ // Only forced compactions drive this test; any non-forced probe is
1772
+ // a no-op.
1892
1773
  if (!opts?.force) {
1893
1774
  return { compacted: false };
1894
1775
  }
1895
1776
  forcedMaybeCompactCallCount++;
1896
1777
  if (forcedMaybeCompactCallCount === 1) {
1897
- // Mid-loop call under the new architecture (Compaction
1898
- // Re-homing Arc, Bullet 1) the manager owns its own retry
1899
- // budget; signal exhaustion to escalate to convergence.
1778
+ // First-call (turn-start) gate: succeeds, but the mocked estimate
1779
+ // stays above the threshold so the turn proceeds to the call and
1780
+ // the mid-loop gate still trips next iteration.
1781
+ return {
1782
+ compacted: true,
1783
+ messages: [
1784
+ {
1785
+ role: "user" as const,
1786
+ content: [{ type: "text", text: "turn-start compacted" }],
1787
+ },
1788
+ ] as Message[],
1789
+ compactedPersistedMessages: 5,
1790
+ summaryText: "Turn-start summary",
1791
+ previousEstimatedInputTokens: 170_000,
1792
+ estimatedInputTokens: 165_000,
1793
+ maxInputTokens: 200_000,
1794
+ thresholdTokens: 160_000,
1795
+ compactedMessages: 10,
1796
+ summaryCalls: 1,
1797
+ summaryInputTokens: 500,
1798
+ summaryOutputTokens: 200,
1799
+ summaryModel: "mock-model",
1800
+ };
1801
+ }
1802
+ if (forcedMaybeCompactCallCount === 2) {
1803
+ // Mid-loop call — the manager owns its own retry budget; signal
1804
+ // exhaustion to escalate to convergence.
1900
1805
  return {
1901
1806
  compacted: true,
1902
1807
  messages: [
@@ -1941,7 +1846,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1941
1846
  summaryModel: "mock-model",
1942
1847
  };
1943
1848
  },
1944
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1849
+ } as unknown as Conversation["contextWindowManager"],
1945
1850
  });
1946
1851
 
1947
1852
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));