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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -39,6 +39,20 @@ const conversationRuntimeAssemblyRealSnapshot = {
39
39
 
40
40
  // ── Module mocks (must precede imports of the module under test) ─────
41
41
 
42
+ // The real AgentLoop resolves the per-conversation ContextWindowManager from
43
+ // the compaction store keyed by conversationId. These overflow tests build
44
+ // fake conversations whose manager is a canned stub, so register each stub in a
45
+ // map the mocked store reads from.
46
+ const fakeContextWindowManagers = new Map<string, unknown>();
47
+ mock.module("../plugins/defaults/compaction/manager-store.js", () => ({
48
+ createContextWindowManager: () => undefined,
49
+ getContextWindowManager: (conversationId: string) =>
50
+ fakeContextWindowManagers.get(conversationId),
51
+ disposeContextWindowManager: (conversationId: string) => {
52
+ fakeContextWindowManagers.delete(conversationId);
53
+ },
54
+ }));
55
+
42
56
  mock.module("../util/logger.js", () => ({
43
57
  getLogger: () =>
44
58
  new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
@@ -100,7 +114,7 @@ mock.module("../config/loader.js", () => ({
100
114
  // Can be a number (constant), a no-arg function, or a function that
101
115
  // receives the messages array for dynamic behavior based on content.
102
116
  // Both the calibrated entry point (`estimatePromptTokens`, which backs the
103
- // preflight overflow gate and the convergence path) and the raw entry point
117
+ // loop's budget gate and the convergence path) and the raw entry point
104
118
  // (`estimatePromptTokensRaw`, used by the pre-send calibration capture) are
105
119
  // stubbed so either call site can drive the test.
106
120
  let mockEstimateTokens: number | ((msgs?: Message[]) => number) = 1000;
@@ -113,7 +127,7 @@ mock.module("../context/token-estimator.js", () => ({
113
127
  typeof mockEstimateTokens === "function"
114
128
  ? mockEstimateTokens(msgs)
115
129
  : mockEstimateTokens,
116
- // The preflight overflow gate calls this calibrated wrapper directly, so it
130
+ // The loop's budget gate calls this calibrated wrapper directly, so it
117
131
  // must honor `mockEstimateTokens` too — otherwise the real implementation
118
132
  // (which sums tool tokens onto the real calibrated estimate) ignores the
119
133
  // per-test value and the overflow scenarios below never trigger.
@@ -137,35 +151,38 @@ mock.module("../context/token-estimator.js", () => ({
137
151
  let mockReducerStepFn:
138
152
  | ((msgs: Message[], cfg: unknown, state: unknown) => unknown)
139
153
  | null = null;
140
- mock.module("../daemon/context-overflow-reducer.js", () => ({
141
- createInitialReducerState: () => ({
142
- appliedTiers: [],
143
- injectionMode: "full" as const,
144
- exhausted: false,
154
+ mock.module(
155
+ "../plugins/defaults/compaction/context-overflow-reducer.js",
156
+ () => ({
157
+ createInitialReducerState: () => ({
158
+ appliedTiers: [],
159
+ injectionMode: "full" as const,
160
+ exhausted: false,
161
+ }),
162
+ reduceContextOverflow: async (
163
+ msgs: Message[],
164
+ cfg: unknown,
165
+ state: unknown,
166
+ ) => {
167
+ if (mockReducerStepFn) return mockReducerStepFn(msgs, cfg, state);
168
+ return {
169
+ messages: msgs,
170
+ tier: "forced_compaction",
171
+ state: {
172
+ appliedTiers: [
173
+ "forced_compaction",
174
+ "tool_result_truncation",
175
+ "media_stubbing",
176
+ "injection_downgrade",
177
+ ],
178
+ injectionMode: "full",
179
+ exhausted: true,
180
+ },
181
+ estimatedTokens: 1000,
182
+ };
183
+ },
145
184
  }),
146
- reduceContextOverflow: async (
147
- msgs: Message[],
148
- cfg: unknown,
149
- state: unknown,
150
- ) => {
151
- if (mockReducerStepFn) return mockReducerStepFn(msgs, cfg, state);
152
- return {
153
- messages: msgs,
154
- tier: "forced_compaction",
155
- state: {
156
- appliedTiers: [
157
- "forced_compaction",
158
- "tool_result_truncation",
159
- "media_stubbing",
160
- "injection_downgrade",
161
- ],
162
- injectionMode: "full",
163
- exhausted: true,
164
- },
165
- estimatedTokens: 1000,
166
- };
167
- },
168
- }));
185
+ );
169
186
 
170
187
  // Policy: default to fail_gracefully
171
188
  let mockOverflowAction: string = "fail_gracefully";
@@ -202,7 +219,7 @@ mock.module("../memory/conversation-crud.js", () => ({
202
219
  updateMessageMetadata: () => {},
203
220
  setLastNotifiedInferenceProfile: () => {},
204
221
  getLastUserTimestampBefore: () => 0,
205
- getConversationOverrideProfileFromRow: () => undefined,
222
+ resolveOverrideProfile: () => undefined,
206
223
  reserveMessage: mock(async () => ({ id: "msg-reserve" })),
207
224
  }));
208
225
 
@@ -422,10 +439,8 @@ mock.module("../memory/archive-store.js", () => ({
422
439
  // ── Imports (after mocks) ────────────────────────────────────────────
423
440
 
424
441
  import { AgentLoop } from "../agent/loop.js";
425
- import {
426
- type AgentLoopConversationContext,
427
- runAgentLoopImpl,
428
- } from "../daemon/conversation-agent-loop.js";
442
+ import type { Conversation } from "../daemon/conversation.js";
443
+ import { runAgentLoopImpl } from "../daemon/conversation-agent-loop.js";
429
444
  import {
430
445
  createMockProvider,
431
446
  type ScriptedResponse,
@@ -436,13 +451,13 @@ import {
436
451
  // ── Test helpers ─────────────────────────────────────────────────────
437
452
 
438
453
  function makeCtx(
439
- overrides?: Partial<AgentLoopConversationContext> & {
454
+ overrides?: Partial<Conversation> & {
440
455
  providerResponses?: ScriptedResponse[];
441
456
  loopProvider?: Provider;
442
457
  loopTools?: ToolDefinition[];
443
458
  toolExecutor?: LoopToolExecutor;
444
459
  },
445
- ): AgentLoopConversationContext {
460
+ ): Conversation {
446
461
  const {
447
462
  providerResponses,
448
463
  loopProvider,
@@ -465,13 +480,15 @@ function makeCtx(
465
480
  providerResponses ?? [textResponse("response")],
466
481
  loopProviderName,
467
482
  ).provider;
468
- const agentLoop = new AgentLoop(provider, "system prompt", {
483
+ const agentLoop = new AgentLoop({
484
+ provider: provider,
485
+ systemPrompt: "system prompt",
469
486
  conversationId,
470
487
  tools: loopTools ?? [],
471
488
  toolExecutor,
472
489
  });
473
490
 
474
- return {
491
+ const ctx = {
475
492
  conversationId: "test-conv",
476
493
  messages: [
477
494
  { role: "user", content: [{ type: "text", text: "Hello" }] },
@@ -495,13 +512,14 @@ function makeCtx(
495
512
  usage: { inputTokens: 0, outputTokens: 0 },
496
513
  stopReason: "end_turn",
497
514
  }),
498
- } as unknown as AgentLoopConversationContext["provider"],
515
+ } as unknown as Conversation["provider"],
499
516
  systemPrompt: "system prompt",
500
517
 
501
518
  contextWindowManager: {
519
+ updateConfig: () => {},
502
520
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
503
521
  maybeCompact: async () => ({ compacted: false }),
504
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
522
+ } as unknown as Conversation["contextWindowManager"],
505
523
  contextCompactedMessageCount: 0,
506
524
  contextCompactedAt: null,
507
525
 
@@ -515,8 +533,6 @@ function makeCtx(
515
533
  currentTurnSurfaces: [],
516
534
 
517
535
  workingDir: "/tmp",
518
- workspaceTopLevelContext: null,
519
- workspaceTopLevelDirty: false,
520
536
  channelCapabilities: undefined,
521
537
  commandIntent: undefined,
522
538
  trustContext: undefined,
@@ -526,15 +542,15 @@ function makeCtx(
526
542
  preactivatedSkillIds: undefined,
527
543
  skillProjectionState: new Map(),
528
544
  skillProjectionCache:
529
- new Map() as unknown as AgentLoopConversationContext["skillProjectionCache"],
545
+ new Map() as unknown as Conversation["skillProjectionCache"],
530
546
 
531
547
  traceEmitter: {
532
548
  emit: () => {},
533
- } as unknown as AgentLoopConversationContext["traceEmitter"],
549
+ } as unknown as Conversation["traceEmitter"],
534
550
  profiler: {
535
551
  startRequest: () => {},
536
552
  emitSummary: () => {},
537
- } as unknown as AgentLoopConversationContext["profiler"],
553
+ } as unknown as Conversation["profiler"],
538
554
  usageStats: {
539
555
  totalInputTokens: 0,
540
556
  totalOutputTokens: 0,
@@ -547,13 +563,12 @@ function makeCtx(
547
563
  lastAttachmentWarnings: [],
548
564
 
549
565
  hasNoClient: false,
550
- prompter: {} as unknown as AgentLoopConversationContext["prompter"],
551
- queue: {} as unknown as AgentLoopConversationContext["queue"],
566
+ prompter: {} as unknown as Conversation["prompter"],
567
+ queue: {} as unknown as Conversation["queue"],
552
568
 
553
569
  getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
554
570
  commitTurnChanges: async () => {},
555
571
 
556
- refreshWorkspaceTopLevelContextIfNeeded: () => {},
557
572
  markWorkspaceTopLevelDirty: () => {},
558
573
  emitActivityState: () => {},
559
574
  getQueueDepth: () => 0,
@@ -580,10 +595,12 @@ function makeCtx(
580
595
  }),
581
596
  retrackCachedNodes: () => {},
582
597
  recordPkbQueryVectors: () => {},
583
- } as unknown as AgentLoopConversationContext["graphMemory"],
598
+ } as unknown as Conversation["graphMemory"],
584
599
 
585
600
  ...ctxOverrides,
586
- } as AgentLoopConversationContext;
601
+ } as unknown as Conversation;
602
+ fakeContextWindowManagers.set(conversationId, ctx.contextWindowManager);
603
+ return ctx;
587
604
  }
588
605
 
589
606
  /**
@@ -651,10 +668,9 @@ beforeEach(() => {
651
668
  recordUsageMock.mockClear();
652
669
  setAgentLoopExitReasonOnLatestLogMock.mockClear();
653
670
  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.
671
+ // Reset the plugin registry and re-register every default so the compaction
672
+ // pipeline dispatches to the default middleware, which in turn hits the
673
+ // mocked collaborators (`syncMessageToDisk`, …) these tests install.
658
674
  resetPluginRegistryAndRegisterDefaults();
659
675
  });
660
676
 
@@ -768,9 +784,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
768
784
  isError: false,
769
785
  }),
770
786
  contextWindowManager: {
787
+ updateConfig: () => {},
771
788
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
772
789
  maybeCompact: async () => ({ compacted: false }),
773
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
790
+ } as unknown as Conversation["contextWindowManager"],
774
791
  });
775
792
 
776
793
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -797,9 +814,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
797
814
  const events: ServerMessage[] = [];
798
815
  let reducerCalled = false;
799
816
 
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.
817
+ // GIVEN the estimator reports 185k and the context manager's compaction
818
+ // is a no-op, so the first call proceeds to the provider without any
819
+ // up-front reduction.
803
820
  mockEstimateTokens = 185_000;
804
821
 
805
822
  // AND the post-run convergence reducer successfully compacts
@@ -842,9 +859,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
842
859
  const ctx = makeCtx({
843
860
  loopProvider: provider,
844
861
  contextWindowManager: {
862
+ updateConfig: () => {},
845
863
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
846
864
  maybeCompact: async () => ({ compacted: false }),
847
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
865
+ } as unknown as Conversation["contextWindowManager"],
848
866
  });
849
867
 
850
868
  // WHEN the turn runs
@@ -918,9 +936,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
918
936
  const ctx = makeCtx({
919
937
  loopProvider: provider,
920
938
  contextWindowManager: {
939
+ updateConfig: () => {},
921
940
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
922
941
  maybeCompact: async () => ({ compacted: false }),
923
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
942
+ } as unknown as Conversation["contextWindowManager"],
924
943
  });
925
944
 
926
945
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1005,9 +1024,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1005
1024
  loopProvider: provider,
1006
1025
  messages: longHistory,
1007
1026
  contextWindowManager: {
1027
+ updateConfig: () => {},
1008
1028
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1009
1029
  maybeCompact: async () => ({ compacted: false }),
1010
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1030
+ } as unknown as Conversation["contextWindowManager"],
1011
1031
  });
1012
1032
 
1013
1033
  await runAgentLoopImpl(ctx, "analyze this", "msg-1", (msg) =>
@@ -1087,6 +1107,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1087
1107
  isError: false,
1088
1108
  }),
1089
1109
  contextWindowManager: {
1110
+ updateConfig: () => {},
1090
1111
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1091
1112
  maybeCompact: async (
1092
1113
  _msgs: Message[],
@@ -1118,7 +1139,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1118
1139
  }
1119
1140
  return { compacted: false };
1120
1141
  },
1121
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1142
+ } as unknown as Conversation["contextWindowManager"],
1122
1143
  });
1123
1144
 
1124
1145
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1187,6 +1208,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1187
1208
  isError: false,
1188
1209
  }),
1189
1210
  contextWindowManager: {
1211
+ updateConfig: () => {},
1190
1212
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1191
1213
  maybeCompact: async () => {
1192
1214
  compactionCalled = true;
@@ -1211,7 +1233,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1211
1233
  summaryModel: "mock-model",
1212
1234
  };
1213
1235
  },
1214
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1236
+ } as unknown as Conversation["contextWindowManager"],
1215
1237
  });
1216
1238
 
1217
1239
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1293,6 +1315,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1293
1315
  isError: false,
1294
1316
  }),
1295
1317
  contextWindowManager: {
1318
+ updateConfig: () => {},
1296
1319
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1297
1320
  maybeCompact: async () => {
1298
1321
  compactionCalled = true;
@@ -1317,7 +1340,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1317
1340
  summaryModel: "mock-model",
1318
1341
  };
1319
1342
  },
1320
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1343
+ } as unknown as Conversation["contextWindowManager"],
1321
1344
  });
1322
1345
 
1323
1346
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => {
@@ -1360,14 +1383,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1360
1383
 
1361
1384
  // Budget = 200_000 * 0.95 = 190_000
1362
1385
  // 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
- };
1386
+ // Every estimate is above the threshold, so the first-call gate compacts
1387
+ // before the first provider call and every checkpoint trips the yield.
1388
+ mockEstimateTokens = 170_000;
1371
1389
 
1372
1390
  // The convergence reducer reduces tokens enough for the rerun to recover.
1373
1391
  let convergenceReducerCalled = false;
@@ -1410,6 +1428,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1410
1428
  ],
1411
1429
  toolExecutor: async () => ({ content: "output", isError: false }),
1412
1430
  contextWindowManager: {
1431
+ updateConfig: () => {},
1413
1432
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1414
1433
  maybeCompact: async () => {
1415
1434
  compactionCallCount++;
@@ -1441,7 +1460,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1441
1460
  summaryModel: "mock-model",
1442
1461
  };
1443
1462
  },
1444
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1463
+ } as unknown as Conversation["contextWindowManager"],
1445
1464
  });
1446
1465
 
1447
1466
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1480,16 +1499,11 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1480
1499
 
1481
1500
  // Budget = 200_000 * 0.95 = 190_000
1482
1501
  // 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
- };
1502
+ // Every estimate is above the threshold: the first-call gate compacts
1503
+ // before the first provider call, and each subsequent checkpoint trips
1504
+ // the yield even after a successful compaction (each tool result inflates
1505
+ // the context back past 85%).
1506
+ mockEstimateTokens = 170_000;
1493
1507
 
1494
1508
  // A single tool round reaches one checkpoint; the in-loop budget gate
1495
1509
  // trips there and compaction runs in place. The loop continues the run
@@ -1518,6 +1532,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1518
1532
  ],
1519
1533
  toolExecutor: async () => ({ content: "output", isError: false }),
1520
1534
  contextWindowManager: {
1535
+ updateConfig: () => {},
1521
1536
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1522
1537
  maybeCompact: async () => {
1523
1538
  compactionCallCount++;
@@ -1542,7 +1557,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1542
1557
  summaryModel: "mock-model",
1543
1558
  };
1544
1559
  },
1545
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1560
+ } as unknown as Conversation["contextWindowManager"],
1546
1561
  });
1547
1562
 
1548
1563
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1633,6 +1648,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1633
1648
  ],
1634
1649
  toolExecutor: async () => ({ content: "output", isError: false }),
1635
1650
  contextWindowManager: {
1651
+ updateConfig: () => {},
1636
1652
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1637
1653
  // Under the new architecture (Compaction Re-homing Arc, Bullet 1)
1638
1654
  // the retry budget lives inside `ContextWindowManager._maybeCompact`,
@@ -1660,7 +1676,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1660
1676
  summaryModel: "mock-model",
1661
1677
  exhausted: true,
1662
1678
  }),
1663
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1679
+ } as unknown as Conversation["contextWindowManager"],
1664
1680
  });
1665
1681
 
1666
1682
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
@@ -1680,124 +1696,6 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1680
1696
  );
1681
1697
  });
1682
1698
 
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
1699
  // ── Test 9 ────────────────────────────────────────────────────────
1802
1700
  // When the `auto_compress_latest_turn` rerun (the last layer of the
1803
1701
  // overflow-recovery ladder) still yields at the mid-loop checkpoint,
@@ -1823,28 +1721,30 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1823
1721
  return 170_000;
1824
1722
  };
1825
1723
 
1826
- // Convergence reducer becomes exhausted on the second tier so the
1827
- // loop escalates from convergence to the action-resolution block.
1724
+ // The reduction ladder applies a middle tier first, then escalates to its
1725
+ // terminal auto-compress-latest-turn rung and reports exhaustion. The
1726
+ // terminal rung is what produces a `budget_yield_unrecovered` outcome when
1727
+ // its rerun still yields at the mid-loop checkpoint.
1828
1728
  let reducerCallCount = 0;
1829
1729
  mockReducerStepFn = (msgs: Message[]) => {
1830
1730
  reducerCallCount++;
1831
- const exhausted = reducerCallCount >= 2;
1731
+ const terminal = reducerCallCount >= 2;
1832
1732
  return {
1833
1733
  messages: msgs,
1834
- tier: exhausted ? "tool_result_truncation" : "forced_compaction",
1734
+ tier: terminal ? "auto_compress_latest_turn" : "forced_compaction",
1835
1735
  state: {
1836
- appliedTiers: exhausted
1837
- ? ["forced_compaction", "tool_result_truncation"]
1736
+ appliedTiers: terminal
1737
+ ? ["forced_compaction", "auto_compress_latest_turn"]
1838
1738
  : ["forced_compaction"],
1839
1739
  injectionMode: "full" as const,
1840
- exhausted,
1740
+ exhausted: terminal,
1841
1741
  },
1842
- estimatedTokens: exhausted ? 60_000 : 80_000,
1742
+ estimatedTokens: terminal ? 60_000 : 80_000,
1843
1743
  };
1844
1744
  };
1845
1745
 
1846
- // The overflow policy directs us into auto_compress_latest_turn so the
1847
- // emergency compaction + final agentLoop.run path executes.
1746
+ // The overflow policy permits the terminal auto-compress-latest-turn rung,
1747
+ // so the ladder runs it as its final step.
1848
1748
  mockOverflowAction = "auto_compress_latest_turn";
1849
1749
 
1850
1750
  // Every provider call returns a tool_use, so each loop run does a tool
@@ -1854,18 +1754,16 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1854
1754
  toolUseResponse("tu-1", "bash", { command: "ls" }),
1855
1755
  ]);
1856
1756
 
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.
1865
- // 3. auto_compress_latest_turn emergency compaction (`force: true`,
1866
- // `minKeepRecentUserTurns: 0`) — succeeds and drops tokens below
1867
- // threshold; the subsequent rerun yields again and is classified
1868
- // as BUDGET_YIELD_UNRECOVERED.
1757
+ // Forced `maybeCompact` is invoked through the loop's own pre-call budget
1758
+ // gate at two call sites (the reduction-ladder rungs are mocked out, so
1759
+ // their summary calls don't reach this manager):
1760
+ // 1. First-call (turn-start) gate (`force: true`) — the loop owns the
1761
+ // turn-start compaction. It succeeds, but the mocked estimate stays
1762
+ // above the mid-loop threshold, so the turn proceeds and the mid-loop
1763
+ // gate still trips on the next iteration.
1764
+ // 2. Mid-loop after the first tool turn (`force: true`) — must signal
1765
+ // `exhausted: true` so the daemon escalates to the convergence
1766
+ // reducer instead of looping forever.
1869
1767
  let forcedMaybeCompactCallCount = 0;
1870
1768
  const ctx = makeCtx({
1871
1769
  loopProvider: provider,
@@ -1881,22 +1779,47 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1881
1779
  ],
1882
1780
  toolExecutor: async () => ({ content: "output", isError: false }),
1883
1781
  contextWindowManager: {
1782
+ updateConfig: () => {},
1884
1783
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1885
1784
  maybeCompact: async (
1886
1785
  _msgs: Message[],
1887
1786
  _signal: AbortSignal,
1888
1787
  opts?: { force?: boolean },
1889
1788
  ) => {
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.
1789
+ // Only forced compactions drive this test; any non-forced probe is
1790
+ // a no-op.
1892
1791
  if (!opts?.force) {
1893
1792
  return { compacted: false };
1894
1793
  }
1895
1794
  forcedMaybeCompactCallCount++;
1896
1795
  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.
1796
+ // First-call (turn-start) gate: succeeds, but the mocked estimate
1797
+ // stays above the threshold so the turn proceeds to the call and
1798
+ // the mid-loop gate still trips next iteration.
1799
+ return {
1800
+ compacted: true,
1801
+ messages: [
1802
+ {
1803
+ role: "user" as const,
1804
+ content: [{ type: "text", text: "turn-start compacted" }],
1805
+ },
1806
+ ] as Message[],
1807
+ compactedPersistedMessages: 5,
1808
+ summaryText: "Turn-start summary",
1809
+ previousEstimatedInputTokens: 170_000,
1810
+ estimatedInputTokens: 165_000,
1811
+ maxInputTokens: 200_000,
1812
+ thresholdTokens: 160_000,
1813
+ compactedMessages: 10,
1814
+ summaryCalls: 1,
1815
+ summaryInputTokens: 500,
1816
+ summaryOutputTokens: 200,
1817
+ summaryModel: "mock-model",
1818
+ };
1819
+ }
1820
+ if (forcedMaybeCompactCallCount === 2) {
1821
+ // Mid-loop call — the manager owns its own retry budget; signal
1822
+ // exhaustion to escalate to convergence.
1900
1823
  return {
1901
1824
  compacted: true,
1902
1825
  messages: [
@@ -1919,7 +1842,8 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1919
1842
  exhausted: true,
1920
1843
  };
1921
1844
  }
1922
- // Emergency compaction call from auto_compress_latest_turn.
1845
+ // Defensive fallback for any additional forced probe; the two gate
1846
+ // call sites above are the only ones this test exercises.
1923
1847
  return {
1924
1848
  compacted: true,
1925
1849
  messages: [
@@ -1929,7 +1853,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1929
1853
  },
1930
1854
  ] as Message[],
1931
1855
  compactedPersistedMessages: 5,
1932
- summaryText: "Emergency summary",
1856
+ summaryText: "Fallback summary",
1933
1857
  previousEstimatedInputTokens: 170_000,
1934
1858
  estimatedInputTokens: 90_000,
1935
1859
  maxInputTokens: 200_000,
@@ -1941,7 +1865,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1941
1865
  summaryModel: "mock-model",
1942
1866
  };
1943
1867
  },
1944
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
1868
+ } as unknown as Conversation["contextWindowManager"],
1945
1869
  });
1946
1870
 
1947
1871
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));