@vellumai/assistant 0.8.5 → 0.8.7-dev.202606052118.34cd356

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 (1323) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +1 -1
  3. package/Dockerfile +21 -4
  4. package/bun.lock +13 -4
  5. package/bunfig.toml +6 -1
  6. package/docker-entrypoint.sh +12 -8
  7. package/docker-init-apt-root.sh +3 -1
  8. package/docker-kata-apt-env.sh +3 -1
  9. package/docker-kata-runtime-family.sh +12 -0
  10. package/docs/architecture/memory.md +1 -1
  11. package/docs/credential-execution-service.md +6 -6
  12. package/docs/plugins.md +114 -86
  13. package/examples/plugins/echo/README.md +13 -12
  14. package/examples/plugins/echo/register.ts +0 -54
  15. package/knip.json +1 -0
  16. package/node_modules/@vellumai/environments/bun.lock +24 -0
  17. package/node_modules/@vellumai/environments/package.json +18 -0
  18. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +95 -0
  19. package/node_modules/@vellumai/environments/src/index.ts +11 -0
  20. package/node_modules/@vellumai/environments/src/seeds.ts +73 -0
  21. package/node_modules/@vellumai/environments/src/types.ts +70 -0
  22. package/node_modules/@vellumai/environments/tsconfig.json +20 -0
  23. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +11 -0
  24. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +15 -17
  25. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
  26. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +15 -7
  27. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  28. package/openapi.yaml +8748 -589
  29. package/package.json +8 -4
  30. package/scripts/generate-openapi.ts +88 -54
  31. package/src/__tests__/actor-token-service.test.ts +3 -2
  32. package/src/__tests__/agent-loop-callsite-precedence.test.ts +42 -80
  33. package/src/__tests__/agent-loop-exit-reason.test.ts +284 -48
  34. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +141 -0
  35. package/src/__tests__/agent-loop-override-profile.test.ts +21 -33
  36. package/src/__tests__/agent-loop-provider-error-recording.test.ts +7 -5
  37. package/src/__tests__/agent-loop-thinking.test.ts +17 -12
  38. package/src/__tests__/agent-loop.test.ts +238 -422
  39. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +7 -2
  40. package/src/__tests__/agent-wake-override-profile.test.ts +23 -40
  41. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  42. package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
  43. package/src/__tests__/annotate-risk-options.test.ts +3 -3
  44. package/src/__tests__/anthropic-provider.test.ts +296 -57
  45. package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
  46. package/src/__tests__/app-control-flow.test.ts +6 -1
  47. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  48. package/src/__tests__/approval-cascade.test.ts +5 -11
  49. package/src/__tests__/approval-routes-http.test.ts +17 -16
  50. package/src/__tests__/assert-not-live-db.ts +79 -0
  51. package/src/__tests__/assistant-event-hub.test.ts +25 -0
  52. package/src/__tests__/assistant-event.test.ts +15 -0
  53. package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
  54. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -27
  55. package/src/__tests__/assistant-stream-state.test.ts +645 -0
  56. package/src/__tests__/audit-log-rotation.test.ts +2 -2
  57. package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
  58. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  59. package/src/__tests__/avatar-e2e.test.ts +7 -37
  60. package/src/__tests__/avatar-generator.test.ts +12 -42
  61. package/src/__tests__/avatar-identity-sync.test.ts +28 -3
  62. package/src/__tests__/background-shell-bash.test.ts +3 -7
  63. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -8
  64. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  65. package/src/__tests__/btw-routes.test.ts +72 -17
  66. package/src/__tests__/build-persisted-content.test.ts +184 -0
  67. package/src/__tests__/call-controller.test.ts +3 -2
  68. package/src/__tests__/call-pointer-messages.test.ts +5 -3
  69. package/src/__tests__/call-site-routing-provider.test.ts +22 -40
  70. package/src/__tests__/catalog-files.test.ts +1 -0
  71. package/src/__tests__/channel-approval-routes.test.ts +52 -23
  72. package/src/__tests__/channel-approvals.test.ts +4 -2
  73. package/src/__tests__/channel-guardian.test.ts +3 -2
  74. package/src/__tests__/channel-invite-transport.test.ts +1 -5
  75. package/src/__tests__/channel-readiness-routes.test.ts +0 -4
  76. package/src/__tests__/channel-readiness-slack-remote.test.ts +170 -0
  77. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  78. package/src/__tests__/channel-retry-sweep.test.ts +388 -79
  79. package/src/__tests__/checker.test.ts +12 -12
  80. package/src/__tests__/clawhub-files.test.ts +1 -0
  81. package/src/__tests__/compaction-circuit.test.ts +258 -0
  82. package/src/__tests__/compaction-direct.test.ts +132 -0
  83. package/src/__tests__/compaction-events.test.ts +6 -17
  84. package/src/__tests__/compaction-trail-store.test.ts +186 -0
  85. package/src/__tests__/compaction.benchmark.test.ts +0 -30
  86. package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
  87. package/src/__tests__/compactor-image-manifest-trust.test.ts +112 -0
  88. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  89. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
  90. package/src/__tests__/computer-use-tools.test.ts +14 -16
  91. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  92. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  93. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  94. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  95. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  96. package/src/__tests__/config-schema.test.ts +10 -10
  97. package/src/__tests__/config-watcher.test.ts +28 -0
  98. package/src/__tests__/connection-model-compat.test.ts +83 -0
  99. package/src/__tests__/contacts-tools.test.ts +3 -2
  100. package/src/__tests__/context-search-agent-runner.test.ts +6 -3
  101. package/src/__tests__/context-token-estimator.test.ts +56 -0
  102. package/src/__tests__/context-window-manager-compact-retry.test.ts +291 -0
  103. package/src/__tests__/conversation-abort-tool-results.test.ts +73 -23
  104. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +10 -7
  105. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  106. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +23 -34
  107. package/src/__tests__/conversation-agent-loop-overflow.test.ts +477 -930
  108. package/src/__tests__/conversation-agent-loop.test.ts +1056 -1068
  109. package/src/__tests__/conversation-analysis-routes.test.ts +8 -3
  110. package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
  111. package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -1
  112. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  113. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  114. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  115. package/src/__tests__/conversation-clear-safety.test.ts +20 -10
  116. package/src/__tests__/conversation-confirmation-signals.test.ts +16 -45
  117. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  118. package/src/__tests__/conversation-disk-view.test.ts +10 -17
  119. package/src/__tests__/conversation-error.test.ts +30 -0
  120. package/src/__tests__/conversation-fork-crud.test.ts +132 -157
  121. package/src/__tests__/conversation-fork-route.test.ts +19 -16
  122. package/src/__tests__/conversation-history-web-search.test.ts +12 -1
  123. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  124. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  125. package/src/__tests__/conversation-init.benchmark.test.ts +6 -6
  126. package/src/__tests__/conversation-lifecycle.test.ts +4 -2
  127. package/src/__tests__/conversation-list-source.test.ts +3 -2
  128. package/src/__tests__/conversation-load-history-repair.test.ts +5 -3
  129. package/src/__tests__/conversation-load-history-stripped.test.ts +2 -1
  130. package/src/__tests__/conversation-message-sync-tags.test.ts +3 -4
  131. package/src/__tests__/conversation-pairing.test.ts +60 -4
  132. package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
  133. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +36 -7
  134. package/src/__tests__/conversation-process-callsite.test.ts +28 -30
  135. package/src/__tests__/conversation-provider-retry-repair.test.ts +85 -51
  136. package/src/__tests__/conversation-queue.test.ts +605 -455
  137. package/src/__tests__/conversation-routes-disk-view.test.ts +9 -20
  138. package/src/__tests__/conversation-routes-guardian-reply.test.ts +35 -10
  139. package/src/__tests__/conversation-routes-slash-commands.test.ts +40 -8
  140. package/src/__tests__/conversation-runtime-assembly.test.ts +395 -313
  141. package/src/__tests__/conversation-runtime-workspace.test.ts +114 -36
  142. package/src/__tests__/conversation-skill-tools.test.ts +38 -142
  143. package/src/__tests__/conversation-slash-commands.test.ts +8 -42
  144. package/src/__tests__/conversation-slash-queue.test.ts +125 -62
  145. package/src/__tests__/conversation-slash-unknown.test.ts +18 -15
  146. package/src/__tests__/conversation-speed-override.test.ts +9 -22
  147. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  148. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +136 -15
  149. package/src/__tests__/conversation-surfaces-app-control.test.ts +32 -4
  150. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  151. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  152. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  153. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  154. package/src/__tests__/conversation-surfaces-table-action.test.ts +13 -32
  155. package/src/__tests__/conversation-sync-tags.test.ts +140 -12
  156. package/src/__tests__/conversation-title-service.test.ts +136 -2
  157. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +53 -11
  158. package/src/__tests__/conversation-unread-route.test.ts +14 -2
  159. package/src/__tests__/conversation-usage.test.ts +1 -2
  160. package/src/__tests__/conversation-wipe.test.ts +1 -1
  161. package/src/__tests__/conversation-workspace-cache-state.test.ts +21 -17
  162. package/src/__tests__/conversation-workspace-injection.test.ts +119 -23
  163. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +39 -13
  164. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  165. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  166. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  167. package/src/__tests__/credential-execution-client.test.ts +72 -1
  168. package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
  169. package/src/__tests__/credential-execution-tools.test.ts +1 -2
  170. package/src/__tests__/credential-health-service.test.ts +252 -3
  171. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  172. package/src/__tests__/credential-vault-unit.test.ts +19 -19
  173. package/src/__tests__/credential-vault.test.ts +5 -5
  174. package/src/__tests__/cross-provider-web-search.test.ts +275 -4
  175. package/src/__tests__/cu-unified-flow.test.ts +26 -1
  176. package/src/__tests__/db-acp-history.test.ts +101 -0
  177. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  178. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  179. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  180. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  181. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -0
  182. package/src/__tests__/db-test-helpers.ts +58 -0
  183. package/src/__tests__/disk-pressure-guard.test.ts +119 -36
  184. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  185. package/src/__tests__/disk-pressure-routes.test.ts +9 -35
  186. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  187. package/src/__tests__/dm-persistence.test.ts +38 -43
  188. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  189. package/src/__tests__/document-find-replace.test.ts +3 -2
  190. package/src/__tests__/document-tool-security.test.ts +81 -2
  191. package/src/__tests__/dynamic-page-surface.test.ts +99 -0
  192. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  193. package/src/__tests__/edit-propagation.test.ts +1 -2
  194. package/src/__tests__/empty-response-hook.test.ts +304 -0
  195. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  196. package/src/__tests__/encrypted-store.test.ts +11 -9
  197. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  198. package/src/__tests__/file-write-tool.test.ts +63 -0
  199. package/src/__tests__/filing-service.test.ts +3 -2
  200. package/src/__tests__/first-greeting.test.ts +103 -12
  201. package/src/__tests__/gateway-flag-listener.test.ts +0 -1
  202. package/src/__tests__/gemini-image-service.test.ts +13 -0
  203. package/src/__tests__/gemini-inline-media.test.ts +78 -0
  204. package/src/__tests__/gemini-provider.test.ts +375 -26
  205. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  206. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  207. package/src/__tests__/guardian-outbound-http.test.ts +3 -2
  208. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  209. package/src/__tests__/guardian-routing-state.test.ts +60 -71
  210. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  211. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +11 -8
  212. package/src/__tests__/heartbeat-disk-pressure.test.ts +3 -0
  213. package/src/__tests__/heartbeat-service.test.ts +4 -1
  214. package/src/__tests__/helpers/mock-logger.ts +26 -0
  215. package/src/__tests__/helpers/mock-provider.ts +110 -0
  216. package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
  217. package/src/__tests__/history-repair-hook.test.ts +162 -0
  218. package/src/__tests__/history-repair-observability.test.ts +1 -1
  219. package/src/__tests__/history-repair.test.ts +2 -1
  220. package/src/__tests__/host-app-control-proxy.test.ts +2 -0
  221. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  222. package/src/__tests__/host-bash-routes.test.ts +1 -0
  223. package/src/__tests__/host-cu-proxy.test.ts +2 -0
  224. package/src/__tests__/host-cu-routes-targeted.test.ts +4 -3
  225. package/src/__tests__/host-file-edit-tool.test.ts +4 -2
  226. package/src/__tests__/host-file-proxy.test.ts +31 -0
  227. package/src/__tests__/host-file-read-tool.test.ts +4 -2
  228. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  229. package/src/__tests__/host-file-write-tool.test.ts +9 -3
  230. package/src/__tests__/host-proxy-preactivation.test.ts +53 -14
  231. package/src/__tests__/host-shell-tool.test.ts +11 -5
  232. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  233. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  234. package/src/__tests__/http-user-message-parity.test.ts +31 -9
  235. package/src/__tests__/identity-intro-cache.test.ts +140 -96
  236. package/src/__tests__/identity-routes.test.ts +248 -7
  237. package/src/__tests__/inbound-slack-persistence.test.ts +56 -75
  238. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  239. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  240. package/src/__tests__/injector-background-turn.test.ts +3 -9
  241. package/src/__tests__/injector-chain.test.ts +139 -275
  242. package/src/__tests__/injector-disk-pressure.test.ts +78 -58
  243. package/src/__tests__/injector-document-comments.test.ts +3 -3
  244. package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
  245. package/src/__tests__/injector-v3-suppression.test.ts +214 -0
  246. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  247. package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
  248. package/src/__tests__/list-messages-attachments.test.ts +7 -8
  249. package/src/__tests__/list-messages-hidden-metadata.test.ts +131 -11
  250. package/src/__tests__/list-messages-page-latest.test.ts +60 -1
  251. package/src/__tests__/list-messages-tool-merge.test.ts +56 -6
  252. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  253. package/src/__tests__/llm-request-log-turn-query.test.ts +42 -86
  254. package/src/__tests__/llm-resolver.test.ts +346 -39
  255. package/src/__tests__/llm-schema.test.ts +1 -1
  256. package/src/__tests__/llm-usage-store.test.ts +268 -1
  257. package/src/__tests__/log-export-routes.test.ts +59 -0
  258. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -8
  259. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  260. package/src/__tests__/mcp-abort-signal.test.ts +14 -0
  261. package/src/__tests__/mcp-auth-routes.test.ts +15 -10
  262. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  263. package/src/__tests__/mcp-health-check.test.ts +18 -13
  264. package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
  265. package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
  266. package/src/__tests__/messaging-send-tool.test.ts +9 -4
  267. package/src/__tests__/migration-export-http.test.ts +12 -12
  268. package/src/__tests__/migration-import-commit-http.test.ts +8 -8
  269. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  270. package/src/__tests__/migration-import-preflight-http.test.ts +7 -7
  271. package/src/__tests__/migration-validate-http.test.ts +3 -3
  272. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  273. package/src/__tests__/model-intents.test.ts +3 -3
  274. package/src/__tests__/native-web-search.test.ts +235 -22
  275. package/src/__tests__/notification-decision-identity.test.ts +9 -18
  276. package/src/__tests__/notification-decision-recipient-context.test.ts +3 -6
  277. package/src/__tests__/notification-deep-link.test.ts +62 -0
  278. package/src/__tests__/oauth-commands-routes.test.ts +38 -1
  279. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  280. package/src/__tests__/oauth-store.test.ts +3 -2
  281. package/src/__tests__/onboarding-template-contract.test.ts +15 -2
  282. package/src/__tests__/openai-image-service.test.ts +17 -0
  283. package/src/__tests__/openai-provider.test.ts +105 -80
  284. package/src/__tests__/openai-responses-provider.test.ts +90 -86
  285. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  286. package/src/__tests__/outbound-slack-persistence.test.ts +48 -2
  287. package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -286
  288. package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
  289. package/src/__tests__/persist-unsendable-image.test.ts +215 -0
  290. package/src/__tests__/persistence-secret-redaction.test.ts +86 -13
  291. package/src/__tests__/pipeline-runner.test.ts +31 -43
  292. package/src/__tests__/pkb-autoinject.test.ts +2 -5
  293. package/src/__tests__/plugin-bootstrap.test.ts +72 -63
  294. package/src/__tests__/plugin-registry.test.ts +0 -27
  295. package/src/__tests__/plugin-route-contribution.test.ts +6 -16
  296. package/src/__tests__/plugin-skill-contribution.test.ts +7 -17
  297. package/src/__tests__/plugin-tool-contribution.test.ts +51 -64
  298. package/src/__tests__/plugin-types.test.ts +8 -173
  299. package/src/__tests__/prechat-onboarding-contract.test.ts +23 -0
  300. package/src/__tests__/process-message-background-slack.test.ts +38 -32
  301. package/src/__tests__/process-message-display-content.test.ts +55 -66
  302. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  303. package/src/__tests__/provider-commit-message-generator.test.ts +19 -14
  304. package/src/__tests__/provider-error-scenarios.test.ts +7 -6
  305. package/src/__tests__/provider-platform-proxy-integration.test.ts +215 -8
  306. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  307. package/src/__tests__/provider-send-message-override-profile.test.ts +9 -25
  308. package/src/__tests__/provider-streaming.benchmark.test.ts +12 -22
  309. package/src/__tests__/provider-usage-tracking.test.ts +0 -6
  310. package/src/__tests__/ratelimit.test.ts +9 -4
  311. package/src/__tests__/reaction-persistence.test.ts +1 -1
  312. package/src/__tests__/recording-handler.test.ts +1 -0
  313. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +6 -1
  314. package/src/__tests__/registry.test.ts +82 -76
  315. package/src/__tests__/relay-server.test.ts +30 -23
  316. package/src/__tests__/resolve-trust-class.test.ts +4 -4
  317. package/src/__tests__/retry-openrouter-only-normalization.test.ts +5 -8
  318. package/src/__tests__/retry-thinking-tool-choice.test.ts +10 -13
  319. package/src/__tests__/retry-verbosity-normalization.test.ts +5 -8
  320. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  321. package/src/__tests__/runtime-events-sse-reconnect.test.ts +390 -0
  322. package/src/__tests__/schedule-routes.test.ts +683 -12
  323. package/src/__tests__/schedule-store.test.ts +124 -1
  324. package/src/__tests__/schedule-tools.test.ts +160 -0
  325. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  326. package/src/__tests__/secret-ingress-http.test.ts +7 -3
  327. package/src/__tests__/secret-prompt-log-hygiene.test.ts +11 -7
  328. package/src/__tests__/secret-prompter-channel-fallback.test.ts +11 -9
  329. package/src/__tests__/secret-response-routing.test.ts +13 -11
  330. package/src/__tests__/secure-keys.test.ts +3 -3
  331. package/src/__tests__/send-endpoint-busy.test.ts +87 -44
  332. package/src/__tests__/server-history-render.test.ts +318 -2
  333. package/src/__tests__/shell-observability.test.ts +249 -0
  334. package/src/__tests__/skill-feature-flags-integration.test.ts +52 -21
  335. package/src/__tests__/skill-feature-flags.test.ts +20 -22
  336. package/src/__tests__/skill-load-feature-flag.test.ts +15 -15
  337. package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
  338. package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
  339. package/src/__tests__/skill-tool-factory.test.ts +96 -95
  340. package/src/__tests__/skills-files-catalog-fallback.test.ts +10 -0
  341. package/src/__tests__/skillssh-files.test.ts +1 -0
  342. package/src/__tests__/slack-channel-config.test.ts +3 -3
  343. package/src/__tests__/starter-task-flow.test.ts +6 -6
  344. package/src/__tests__/strip-memory-injections.test.ts +102 -14
  345. package/src/__tests__/subagent-call-site-routing.test.ts +14 -6
  346. package/src/__tests__/subagent-disposal.test.ts +27 -8
  347. package/src/__tests__/subagent-fork-notifications.test.ts +25 -12
  348. package/src/__tests__/subagent-fork-spawn.test.ts +14 -5
  349. package/src/__tests__/subagent-manager-notify.test.ts +21 -11
  350. package/src/__tests__/subagent-notify-parent.test.ts +6 -7
  351. package/src/__tests__/subagent-spawn-tool-fork.test.ts +59 -1
  352. package/src/__tests__/subagent-tools.test.ts +2 -1
  353. package/src/__tests__/suggestion-routes.test.ts +4 -3
  354. package/src/__tests__/sync-message-contract.test.ts +19 -16
  355. package/src/__tests__/system-prompt.test.ts +112 -0
  356. package/src/__tests__/task-scheduler.test.ts +162 -1
  357. package/src/__tests__/terminal-tools.test.ts +9 -25
  358. package/src/__tests__/test-preload-verifier.ts +68 -0
  359. package/src/__tests__/test-preload.ts +32 -39
  360. package/src/__tests__/thread-backfill.test.ts +4 -9
  361. package/src/__tests__/title-generate-hook.test.ts +319 -0
  362. package/src/__tests__/tool-error-hook.test.ts +278 -0
  363. package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
  364. package/src/__tests__/tool-executor.test.ts +55 -10
  365. package/src/__tests__/tool-preview-lifecycle.test.ts +481 -15
  366. package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
  367. package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
  368. package/src/__tests__/tool-result-truncation.test.ts +1 -1
  369. package/src/__tests__/tools-audio-read.test.ts +113 -0
  370. package/src/__tests__/turn-boundary-resolution.test.ts +44 -84
  371. package/src/__tests__/turn-events-store.test.ts +11 -7
  372. package/src/__tests__/twilio-routes.test.ts +3 -2
  373. package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
  374. package/src/__tests__/ui-work-result-surface.test.ts +159 -0
  375. package/src/__tests__/usage-routes.test.ts +285 -1
  376. package/src/__tests__/user-plugin-loader.test.ts +2 -2
  377. package/src/__tests__/validate-input.test.ts +381 -0
  378. package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
  379. package/src/__tests__/voice-scoped-grant-consumer.test.ts +10 -7
  380. package/src/__tests__/voice-session-bridge.test.ts +56 -38
  381. package/src/__tests__/web-search-backend-failure.test.ts +166 -0
  382. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  383. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  384. package/src/acp/__tests__/agent-process.test.ts +161 -0
  385. package/src/acp/__tests__/client-handler.test.ts +40 -0
  386. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  387. package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
  388. package/src/acp/__tests__/prepare-agent-env.test.ts +143 -31
  389. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  390. package/src/acp/__tests__/session-manager-resume.test.ts +695 -0
  391. package/src/acp/agent-process.ts +61 -1
  392. package/src/acp/auto-install.test.ts +125 -0
  393. package/src/acp/auto-install.ts +174 -0
  394. package/src/acp/client-handler.ts +31 -0
  395. package/src/acp/feature-gate.test.ts +48 -0
  396. package/src/acp/feature-gate.ts +34 -0
  397. package/src/acp/prepare-agent-env.ts +52 -11
  398. package/src/acp/resolve-agent.test.ts +147 -6
  399. package/src/acp/resolve-agent.ts +81 -7
  400. package/src/acp/resume-hint.ts +22 -0
  401. package/src/acp/session-manager.ts +492 -77
  402. package/src/agent/compaction-circuit.ts +98 -0
  403. package/src/agent/loop.ts +730 -449
  404. package/src/api/README.md +126 -2
  405. package/src/api/constants/call-sites.ts +27 -0
  406. package/src/api/constants/tool-execution.ts +21 -0
  407. package/src/api/events/assistant-activity-state.ts +75 -0
  408. package/src/api/events/assistant-outbound-attachment.ts +49 -0
  409. package/src/api/events/assistant-text-delta.ts +30 -0
  410. package/src/api/events/assistant-thinking-delta.ts +33 -0
  411. package/src/api/events/assistant-turn-start.ts +31 -0
  412. package/src/api/events/avatar-updated.ts +24 -0
  413. package/src/api/events/compaction-circuit-closed.ts +26 -0
  414. package/src/api/events/compaction-circuit-open.ts +28 -0
  415. package/src/api/events/confirmation-request.ts +114 -0
  416. package/src/api/events/contact-request.ts +33 -0
  417. package/src/api/events/conversation-error.ts +77 -0
  418. package/src/api/events/conversation-list-invalidated.ts +38 -0
  419. package/src/api/events/conversation-title-updated.ts +24 -0
  420. package/src/api/events/disk-pressure-status-changed.ts +61 -0
  421. package/src/api/events/document-comment-created.ts +44 -0
  422. package/src/api/events/document-comment-deleted.ts +22 -0
  423. package/src/api/events/document-comment-reopened.ts +23 -0
  424. package/src/api/events/document-comment-resolved.ts +25 -0
  425. package/src/api/events/document-editor-update.ts +27 -0
  426. package/src/api/events/error.ts +32 -0
  427. package/src/api/events/generation-cancelled.ts +22 -0
  428. package/src/api/events/generation-handoff.ts +39 -0
  429. package/src/api/events/home-feed-updated.ts +26 -0
  430. package/src/api/events/identity-changed.ts +32 -0
  431. package/src/api/events/interaction-resolved.ts +50 -0
  432. package/src/api/events/message-complete.ts +40 -0
  433. package/src/api/events/message-dequeued.ts +21 -0
  434. package/src/api/events/message-queued-deleted.ts +23 -0
  435. package/src/api/events/message-queued.ts +22 -0
  436. package/src/api/events/message-request-complete.ts +29 -0
  437. package/src/api/events/navigate-settings.ts +20 -0
  438. package/src/api/events/notification-intent.ts +33 -0
  439. package/src/api/events/open-url.ts +28 -0
  440. package/src/api/events/question-request.ts +67 -0
  441. package/src/{events → api/events}/relationship-state-updated.ts +6 -8
  442. package/src/api/events/secret-request.ts +42 -0
  443. package/src/api/events/subagent-event.ts +79 -0
  444. package/src/api/events/subagent-spawned.ts +40 -0
  445. package/src/api/events/subagent-status-changed.ts +65 -0
  446. package/src/api/events/sync-changed.ts +29 -0
  447. package/src/api/events/tool-output-chunk.ts +45 -0
  448. package/src/api/events/tool-result.ts +129 -0
  449. package/src/api/events/tool-use-preview-start.ts +32 -0
  450. package/src/api/events/tool-use-start.ts +30 -0
  451. package/src/api/events/trace-event.ts +69 -0
  452. package/src/api/events/turn-profile-auto-routed.ts +28 -0
  453. package/src/api/events/ui-surface-complete.ts +30 -0
  454. package/src/api/events/ui-surface-dismiss.ts +22 -0
  455. package/src/api/events/ui-surface-show.ts +67 -0
  456. package/src/api/events/ui-surface-update.ts +26 -0
  457. package/src/api/events/usage-update.ts +34 -0
  458. package/src/api/events/user-message-echo.ts +35 -0
  459. package/src/api/index.ts +517 -3
  460. package/src/api/requests/dictation.ts +45 -0
  461. package/src/api/responses/conversation-message.ts +374 -0
  462. package/src/api/responses/disk-pressure-status.ts +26 -0
  463. package/src/api/responses/home.ts +217 -0
  464. package/src/api/responses/llm-context-response.ts +41 -0
  465. package/src/api/responses/llm-request-log-entry.ts +93 -0
  466. package/src/api/responses/memory-recall-log.ts +65 -0
  467. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  468. package/src/api/responses/memory-v3-selection-log.ts +50 -0
  469. package/src/api/responses/subagent-detail.ts +48 -0
  470. package/src/approvals/guardian-decision-primitive.ts +7 -15
  471. package/src/approvals/guardian-request-resolvers.ts +7 -10
  472. package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
  473. package/src/avatar/__tests__/avatar-store.test.ts +198 -0
  474. package/src/avatar/avatar-manifest.ts +195 -0
  475. package/src/avatar/avatar-store.ts +113 -0
  476. package/src/avatar/traits-png-sync.ts +8 -2
  477. package/src/background-wake/background-wake-routes.test.ts +687 -52
  478. package/src/background-wake/next-wake.test.ts +31 -1
  479. package/src/background-wake/next-wake.ts +5 -1
  480. package/src/background-wake/platform-client.test.ts +308 -0
  481. package/src/background-wake/platform-client.ts +167 -0
  482. package/src/background-wake/publisher.ts +91 -0
  483. package/src/background-wake/runtime-registry.ts +2 -2
  484. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  485. package/src/calls/call-conversation-messages.ts +6 -4
  486. package/src/calls/guardian-action-sweep.ts +6 -4
  487. package/src/calls/guardian-dispatch.ts +1 -0
  488. package/src/calls/relay-server.ts +12 -8
  489. package/src/calls/voice-session-bridge.ts +17 -31
  490. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  491. package/src/cli/commands/__tests__/memory-v3.test.ts +245 -0
  492. package/src/cli/commands/__tests__/notifications.test.ts +242 -54
  493. package/src/cli/commands/avatar.ts +17 -11
  494. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  495. package/src/cli/commands/channels/index.ts +229 -0
  496. package/src/cli/commands/conversations.ts +15 -1
  497. package/src/cli/commands/db/__tests__/repair.test.ts +540 -0
  498. package/src/cli/commands/db/__tests__/status.test.ts +253 -0
  499. package/src/cli/commands/db/format.ts +48 -0
  500. package/src/cli/commands/db/index.ts +29 -0
  501. package/src/cli/commands/db/repair-step-conversation-backfill.ts +345 -0
  502. package/src/cli/commands/db/repair-step-integrity.ts +146 -0
  503. package/src/cli/commands/db/repair-steps.ts +164 -0
  504. package/src/cli/commands/db/repair.ts +141 -0
  505. package/src/cli/commands/db/status.ts +366 -0
  506. package/src/cli/commands/memory-v3.ts +168 -203
  507. package/src/cli/commands/notifications.ts +427 -65
  508. package/src/cli/lib/cli-colors.ts +24 -6
  509. package/src/cli/lib/open-browser.ts +7 -2
  510. package/src/cli/program.ts +6 -5
  511. package/src/config/__tests__/feature-flag-registry-guard.test.ts +4 -4
  512. package/src/config/acp-defaults.test.ts +10 -0
  513. package/src/config/acp-defaults.ts +6 -0
  514. package/src/config/assistant-feature-flags.ts +47 -55
  515. package/src/config/bundled-skills/acp/SKILL.md +64 -30
  516. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  517. package/src/config/bundled-skills/app-builder/SKILL.md +224 -387
  518. package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
  519. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  520. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  521. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  522. package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
  523. package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
  524. package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
  525. package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
  526. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  527. package/src/config/bundled-skills/document-editor/SKILL.md +33 -24
  528. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  529. package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
  530. package/src/config/bundled-skills/messaging/SKILL.md +0 -7
  531. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +7 -2
  532. package/src/config/bundled-skills/schedule/SKILL.md +2 -2
  533. package/src/config/bundled-skills/schedule/TOOLS.json +10 -2
  534. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  535. package/src/config/bundled-tool-registry.ts +2 -0
  536. package/src/config/call-site-defaults.ts +3 -8
  537. package/src/config/feature-flag-cache.ts +86 -0
  538. package/src/config/feature-flag-registry.json +81 -25
  539. package/src/config/llm-context-resolution.ts +10 -1
  540. package/src/config/llm-resolver.ts +121 -15
  541. package/src/config/loader.ts +4 -5
  542. package/src/config/schemas/__tests__/memory-v2.test.ts +2 -211
  543. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
  544. package/src/config/schemas/call-site-catalog.ts +8 -15
  545. package/src/config/schemas/heartbeat.ts +10 -1
  546. package/src/config/schemas/llm.ts +93 -4
  547. package/src/config/schemas/memory-lifecycle.ts +24 -0
  548. package/src/config/schemas/memory-v2.ts +8 -227
  549. package/src/config/schemas/memory-v3.ts +47 -0
  550. package/src/config/schemas/memory.ts +6 -1
  551. package/src/config/schemas/platform.ts +8 -0
  552. package/src/config/schemas/services.ts +6 -2
  553. package/src/config/schemas/timeouts.ts +3 -1
  554. package/src/config/seed-inference-profiles.ts +38 -18
  555. package/src/config/skills.ts +13 -0
  556. package/src/context/compactor.ts +55 -32
  557. package/src/context/strip-injections.ts +128 -0
  558. package/src/context/token-estimator.ts +52 -5
  559. package/src/context/tool-result-truncation.ts +1 -66
  560. package/src/context/window-manager.ts +141 -26
  561. package/src/credential-execution/executable-discovery.ts +56 -0
  562. package/src/credential-execution/process-manager.ts +6 -2
  563. package/src/credential-health/credential-health-service.ts +125 -40
  564. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +9 -6
  565. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +15 -17
  566. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
  567. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  568. package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
  569. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  570. package/src/daemon/__tests__/native-web-search-metadata.test.ts +11 -8
  571. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  572. package/src/daemon/__tests__/web-search-status-text.test.ts +11 -6
  573. package/src/daemon/approval-generators.ts +4 -4
  574. package/src/daemon/assistant-attachments.ts +1 -1
  575. package/src/daemon/config-watcher.ts +7 -1
  576. package/src/daemon/context-overflow-reducer.ts +0 -1
  577. package/src/daemon/conversation-agent-loop-handlers.ts +1146 -247
  578. package/src/daemon/conversation-agent-loop.ts +570 -1457
  579. package/src/daemon/conversation-error.ts +40 -12
  580. package/src/daemon/conversation-history.ts +27 -10
  581. package/src/daemon/conversation-launch.ts +4 -8
  582. package/src/daemon/conversation-lifecycle.ts +13 -42
  583. package/src/daemon/conversation-messaging.ts +89 -49
  584. package/src/daemon/conversation-notifiers.ts +7 -5
  585. package/src/daemon/conversation-process.ts +183 -130
  586. package/src/daemon/conversation-registry.ts +159 -0
  587. package/src/daemon/conversation-runtime-assembly.ts +209 -362
  588. package/src/daemon/conversation-skill-tools.ts +14 -30
  589. package/src/daemon/conversation-slash.ts +6 -25
  590. package/src/daemon/conversation-store.ts +15 -95
  591. package/src/daemon/conversation-surfaces.ts +346 -107
  592. package/src/daemon/conversation-tool-setup.ts +38 -77
  593. package/src/daemon/conversation-workspace.ts +17 -0
  594. package/src/daemon/conversation.ts +143 -186
  595. package/src/daemon/daemon-control.ts +1 -1
  596. package/src/daemon/daemon-skill-host.ts +7 -4
  597. package/src/daemon/disk-pressure-guard.ts +54 -50
  598. package/src/daemon/external-plugins-bootstrap.ts +53 -32
  599. package/src/daemon/first-greeting.ts +53 -13
  600. package/src/daemon/guardian-action-generators.ts +2 -2
  601. package/src/daemon/handlers/config-a2a.ts +51 -36
  602. package/src/daemon/handlers/config-slack-channel.ts +20 -14
  603. package/src/daemon/handlers/config-telegram.ts +16 -2
  604. package/src/daemon/handlers/conversations.ts +9 -23
  605. package/src/daemon/handlers/shared.ts +158 -77
  606. package/src/daemon/handlers/skills.ts +53 -20
  607. package/src/daemon/host-app-control-proxy.ts +54 -1
  608. package/src/daemon/host-cu-proxy.ts +46 -22
  609. package/src/daemon/host-file-proxy.ts +25 -1
  610. package/src/daemon/host-proxy-preactivation.ts +25 -6
  611. package/src/daemon/lifecycle.ts +65 -67
  612. package/src/daemon/mcp-reload-service.ts +1 -1
  613. package/src/daemon/meet-manifest-loader.ts +10 -17
  614. package/src/daemon/message-protocol.ts +2 -3
  615. package/src/daemon/message-provenance.ts +49 -0
  616. package/src/daemon/message-types/apps.ts +1 -29
  617. package/src/daemon/message-types/contacts.ts +3 -20
  618. package/src/daemon/message-types/conversations.ts +25 -125
  619. package/src/daemon/message-types/document-comments.ts +8 -44
  620. package/src/daemon/message-types/documents.ts +3 -9
  621. package/src/daemon/message-types/home.ts +5 -18
  622. package/src/daemon/message-types/integrations.ts +4 -13
  623. package/src/daemon/message-types/messages.ts +50 -428
  624. package/src/daemon/message-types/notifications.ts +2 -32
  625. package/src/daemon/message-types/settings.ts +3 -8
  626. package/src/daemon/message-types/skills.ts +4 -0
  627. package/src/daemon/message-types/subagents.ts +6 -0
  628. package/src/daemon/message-types/surfaces.ts +138 -3
  629. package/src/daemon/message-types/sync.ts +12 -25
  630. package/src/daemon/message-types/workspace.ts +3 -11
  631. package/src/daemon/now-scratchpad.ts +21 -0
  632. package/src/daemon/orphan-reaper.test.ts +210 -0
  633. package/src/daemon/orphan-reaper.ts +240 -0
  634. package/src/daemon/overflow-reduction-loop.ts +230 -0
  635. package/src/daemon/persist-unsendable-image.ts +117 -0
  636. package/src/daemon/process-message.ts +59 -58
  637. package/src/daemon/providers-setup.ts +1 -1
  638. package/src/daemon/server.ts +30 -0
  639. package/src/daemon/switch-inference-profile-tool.ts +13 -3
  640. package/src/daemon/tool-setup-types.ts +0 -6
  641. package/src/daemon/tool-side-effects.ts +10 -7
  642. package/src/daemon/trace-emitter.ts +6 -4
  643. package/src/daemon/trust-context.ts +32 -0
  644. package/src/daemon/wake-target-adapter.ts +24 -2
  645. package/src/documents/document-store.ts +38 -0
  646. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  647. package/src/heartbeat/__tests__/heartbeat-service.test.ts +34 -0
  648. package/src/heartbeat/heartbeat-run-store.ts +54 -1
  649. package/src/heartbeat/heartbeat-service.ts +105 -0
  650. package/src/home/__tests__/feed-writer.test.ts +161 -0
  651. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  652. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  653. package/src/home/feed-types.ts +36 -221
  654. package/src/home/feed-writer.ts +146 -7
  655. package/src/home/home-greeting-cache.ts +24 -1
  656. package/src/home/suggested-prompts.ts +27 -145
  657. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  658. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  659. package/src/ipc/__tests__/email-ipc.test.ts +0 -9
  660. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  661. package/src/ipc/gateway-client.test.ts +6 -3
  662. package/src/ipc/gateway-client.ts +3 -3
  663. package/src/ipc/routes/__tests__/route-adapter.test.ts +244 -0
  664. package/src/ipc/routes/route-adapter.ts +45 -6
  665. package/src/ipc/skill-routes/__tests__/memory.test.ts +34 -9
  666. package/src/ipc/skill-routes/__tests__/providers.test.ts +10 -10
  667. package/src/ipc/skill-routes/__tests__/registries.test.ts +59 -20
  668. package/src/ipc/skill-routes/memory.ts +29 -13
  669. package/src/ipc/skill-routes/providers.ts +5 -6
  670. package/src/ipc/skill-routes/registries.ts +39 -88
  671. package/src/live-voice/__tests__/live-voice-archive.test.ts +24 -11
  672. package/src/media/gemini-image-service.ts +15 -0
  673. package/src/media/openai-image-service.ts +14 -0
  674. package/src/media/types.ts +34 -0
  675. package/src/memory/__tests__/conversation-queries.test.ts +192 -8
  676. package/src/memory/__tests__/db-maintenance.test.ts +128 -0
  677. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
  678. package/src/memory/__tests__/jobs-store-job-classes.test.ts +5 -4
  679. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +82 -5
  680. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  681. package/src/memory/__tests__/memory-retrospective-job.test.ts +11 -6
  682. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  683. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  684. package/src/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
  685. package/src/memory/auth-fallback-events-store.ts +94 -0
  686. package/src/memory/context-search/agent-runner.ts +2 -4
  687. package/src/memory/conversation-attention-store.ts +17 -3
  688. package/src/memory/conversation-crud.ts +386 -115
  689. package/src/memory/conversation-queries.ts +78 -22
  690. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  691. package/src/memory/conversation-title-service.ts +65 -41
  692. package/src/memory/db-connection.ts +29 -19
  693. package/src/memory/db-init.ts +18 -0
  694. package/src/memory/db-maintenance.ts +18 -2
  695. package/src/memory/db-singleton.ts +77 -0
  696. package/src/memory/delivery-channels.ts +82 -0
  697. package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
  698. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  699. package/src/memory/graph/consolidation.ts +8 -11
  700. package/src/memory/graph/conversation-graph-memory.ts +106 -8
  701. package/src/memory/graph/extraction.ts +6 -9
  702. package/src/memory/graph/narrative.ts +2 -2
  703. package/src/memory/graph/pattern-scan.ts +2 -2
  704. package/src/memory/graph/retriever.test.ts +3 -3
  705. package/src/memory/graph/retriever.ts +20 -26
  706. package/src/memory/graph/tools.ts +4 -4
  707. package/src/memory/job-handlers/conversation-starters.ts +45 -34
  708. package/src/memory/job-handlers/embedding.test.ts +3 -2
  709. package/src/memory/job-handlers/summarization.ts +1 -2
  710. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  711. package/src/memory/jobs-store.ts +36 -1
  712. package/src/memory/jobs-worker.ts +93 -43
  713. package/src/memory/llm-request-log-source-clickhouse.ts +55 -1
  714. package/src/memory/llm-request-log-source-local.ts +13 -0
  715. package/src/memory/llm-request-log-source.ts +21 -6
  716. package/src/memory/llm-request-log-store.ts +147 -3
  717. package/src/memory/llm-usage-store.ts +234 -50
  718. package/src/memory/memory-marker.ts +17 -0
  719. package/src/memory/memory-retrospective-job.ts +6 -2
  720. package/src/memory/memory-v2-activation-log-store.ts +13 -1
  721. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
  722. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  723. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  724. package/src/memory/migrations/267-llm-usage-events-add-assistant-version.ts +46 -0
  725. package/src/memory/migrations/268-add-memory-v3-selections.ts +28 -0
  726. package/src/memory/migrations/269-schedule-script-timeout.ts +11 -0
  727. package/src/memory/migrations/270-messages-role-created-at-index.ts +18 -0
  728. package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
  729. package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
  730. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  731. package/src/memory/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
  732. package/src/memory/migrations/index.ts +9 -0
  733. package/src/memory/pkb/autoinject.ts +61 -0
  734. package/src/memory/pkb/context.ts +50 -0
  735. package/src/memory/pkb/types.ts +14 -0
  736. package/src/memory/schedule-attribution-sql.ts +104 -0
  737. package/src/memory/schema/acp.ts +4 -0
  738. package/src/memory/schema/conversations.ts +9 -1
  739. package/src/memory/schema/inference.ts +0 -1
  740. package/src/memory/schema/infrastructure.ts +27 -0
  741. package/src/memory/usage-grouped-buckets.ts +6 -1
  742. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  743. package/src/memory/v2/__tests__/consolidation-job.test.ts +125 -1
  744. package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
  745. package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
  746. package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
  747. package/src/memory/v2/__tests__/migration.test.ts +11 -3
  748. package/src/memory/v2/__tests__/page-index.test.ts +37 -1
  749. package/src/memory/v2/__tests__/router.test.ts +14 -4
  750. package/src/memory/v2/__tests__/sweep-job.test.ts +9 -5
  751. package/src/memory/v2/backfill-jobs.ts +6 -0
  752. package/src/memory/v2/consolidation-job.ts +99 -10
  753. package/src/memory/v2/harness/metrics.ts +5 -1
  754. package/src/memory/v2/harness/replay-input.ts +19 -3
  755. package/src/memory/v2/harness/runner.ts +6 -0
  756. package/src/memory/v2/harness/trace.ts +6 -0
  757. package/src/memory/v2/migration.ts +5 -3
  758. package/src/memory/v2/page-index.ts +11 -0
  759. package/src/memory/v2/router.ts +8 -11
  760. package/src/memory/v2/sweep-job.ts +8 -11
  761. package/src/memory/v2/types.ts +1 -0
  762. package/src/messaging/providers/slack/render-transcript.test.ts +1 -1
  763. package/src/messaging/providers/slack/render-transcript.ts +2 -2
  764. package/src/messaging/style-analyzer.ts +8 -11
  765. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  766. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  767. package/src/notifications/adapters/slack.ts +45 -11
  768. package/src/notifications/broadcaster.ts +114 -63
  769. package/src/notifications/conversation-pairing.ts +23 -8
  770. package/src/notifications/decision-engine.ts +16 -16
  771. package/src/notifications/decisions-store.ts +32 -1
  772. package/src/notifications/deliveries-store.ts +45 -0
  773. package/src/notifications/edit-notification.ts +201 -0
  774. package/src/notifications/emit-signal.ts +11 -1
  775. package/src/notifications/home-feed-side-effect.ts +12 -1
  776. package/src/notifications/preference-extractor.ts +11 -14
  777. package/src/notifications/signal.ts +10 -0
  778. package/src/notifications/types.ts +37 -0
  779. package/src/oauth/byo-connection.test.ts +67 -3
  780. package/src/oauth/byo-connection.ts +32 -5
  781. package/src/oauth/connect-orchestrator.ts +9 -0
  782. package/src/oauth/connection-resolver.test.ts +76 -0
  783. package/src/oauth/connection-resolver.ts +49 -10
  784. package/src/oauth/manual-token-connection.ts +51 -3
  785. package/src/oauth/seed-providers.ts +3 -0
  786. package/src/permissions/approval-policy.test.ts +19 -5
  787. package/src/permissions/approval-policy.ts +14 -3
  788. package/src/permissions/checker.ts +21 -8
  789. package/src/permissions/prompter.ts +46 -36
  790. package/src/permissions/question-prompter.test.ts +35 -26
  791. package/src/permissions/question-prompter.ts +6 -10
  792. package/src/platform/client.test.ts +24 -1
  793. package/src/platform/client.ts +8 -0
  794. package/src/platform/feature-gate.ts +15 -0
  795. package/src/plugin-api/constants.ts +4 -0
  796. package/src/plugin-api/index.ts +10 -1
  797. package/src/plugin-api/types.ts +176 -4
  798. package/src/plugins/defaults/compaction/compact.ts +59 -0
  799. package/src/plugins/defaults/compaction/package.json +15 -0
  800. package/src/plugins/defaults/compaction/register.ts +24 -0
  801. package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
  802. package/src/plugins/defaults/empty-response/package.json +15 -0
  803. package/src/plugins/defaults/empty-response/register.ts +23 -0
  804. package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +35 -0
  805. package/src/plugins/defaults/history-repair/package.json +15 -0
  806. package/src/plugins/defaults/history-repair/register.ts +24 -0
  807. package/src/{daemon/history-repair.ts → plugins/defaults/history-repair/terminal.ts} +48 -35
  808. package/src/plugins/defaults/index.ts +22 -49
  809. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
  810. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
  811. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
  812. package/src/plugins/defaults/{injectors.ts → memory-retrieval/injectors.ts} +297 -120
  813. package/src/plugins/defaults/memory-v3-shadow/__tests__/assign.test.ts +242 -0
  814. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +118 -0
  815. package/src/plugins/defaults/memory-v3-shadow/__tests__/core.test.ts +39 -0
  816. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +36 -0
  817. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +37 -0
  818. package/src/plugins/defaults/memory-v3-shadow/__tests__/health.test.ts +219 -0
  819. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +330 -0
  820. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +288 -0
  821. package/src/plugins/defaults/memory-v3-shadow/__tests__/needle.test.ts +107 -0
  822. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +436 -0
  823. package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
  824. package/src/plugins/defaults/memory-v3-shadow/__tests__/reconcile.test.ts +274 -0
  825. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +61 -0
  826. package/src/plugins/defaults/memory-v3-shadow/__tests__/router.test.ts +332 -0
  827. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +179 -0
  828. package/src/plugins/defaults/memory-v3-shadow/__tests__/selector.test.ts +470 -0
  829. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +432 -0
  830. package/src/plugins/defaults/memory-v3-shadow/__tests__/snapshot.test.ts +168 -0
  831. package/src/plugins/defaults/memory-v3-shadow/__tests__/tree.test.ts +192 -0
  832. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +54 -0
  833. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +106 -0
  834. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +44 -0
  835. package/src/plugins/defaults/memory-v3-shadow/assign.ts +268 -0
  836. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +124 -0
  837. package/src/plugins/defaults/memory-v3-shadow/core.ts +26 -0
  838. package/src/plugins/defaults/memory-v3-shadow/data/README.md +84 -0
  839. package/src/plugins/defaults/memory-v3-shadow/data/assignments.json +5 -0
  840. package/src/plugins/defaults/memory-v3-shadow/data/core.json +1 -0
  841. package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-x.md +9 -0
  842. package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-y.md +9 -0
  843. package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-b/topic-z.md +9 -0
  844. package/src/plugins/defaults/memory-v3-shadow/health.ts +0 -0
  845. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  846. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  847. package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
  848. package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
  849. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +314 -0
  850. package/src/plugins/defaults/memory-v3-shadow/needle.ts +115 -0
  851. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +126 -0
  852. package/src/plugins/defaults/memory-v3-shadow/package.json +15 -0
  853. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +34 -0
  854. package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
  855. package/src/plugins/defaults/memory-v3-shadow/reconcile.ts +523 -0
  856. package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
  857. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +32 -0
  858. package/src/plugins/defaults/memory-v3-shadow/router.ts +190 -0
  859. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +84 -0
  860. package/src/plugins/defaults/memory-v3-shadow/selector.ts +226 -0
  861. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +349 -0
  862. package/src/plugins/defaults/memory-v3-shadow/snapshot.ts +209 -0
  863. package/src/plugins/defaults/memory-v3-shadow/tree.ts +174 -0
  864. package/src/plugins/defaults/memory-v3-shadow/types.ts +59 -0
  865. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +88 -0
  866. package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
  867. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
  868. package/src/plugins/defaults/title-generate/package.json +15 -0
  869. package/src/plugins/defaults/title-generate/register.ts +35 -0
  870. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
  871. package/src/plugins/defaults/tool-error/package.json +15 -0
  872. package/src/plugins/defaults/tool-error/register.ts +23 -0
  873. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
  874. package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
  875. package/src/plugins/defaults/tool-result-truncate/register.ts +24 -0
  876. package/src/plugins/defaults/tool-result-truncate/terminal.ts +132 -0
  877. package/src/plugins/external-plugin-loader.ts +2 -2
  878. package/src/plugins/pipeline.ts +8 -35
  879. package/src/plugins/registry.ts +8 -25
  880. package/src/plugins/types.ts +62 -677
  881. package/src/plugins/user-loader.ts +4 -3
  882. package/src/proactive-artifact/aux-message-injector.ts +4 -5
  883. package/src/proactive-artifact/job.test.ts +29 -21
  884. package/src/proactive-artifact/job.ts +3 -1
  885. package/src/prompts/__tests__/system-prompt.test.ts +46 -4
  886. package/src/prompts/sections.ts +20 -7
  887. package/src/prompts/system-prompt.ts +38 -40
  888. package/src/prompts/template-detection.ts +10 -4
  889. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
  890. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +2 -2
  891. package/src/prompts/templates/BOOTSTRAP.md +12 -12
  892. package/src/prompts/templates/IDENTITY.md +0 -2
  893. package/src/prompts/templates/system-sections.ts +21 -0
  894. package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
  895. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  896. package/src/providers/__tests__/retry-callsite.test.ts +25 -25
  897. package/src/providers/__tests__/satellite-connection-routing.test.ts +7 -21
  898. package/src/providers/anthropic/client.ts +61 -34
  899. package/src/providers/call-site-routing.ts +34 -18
  900. package/src/providers/connection-model-compat.ts +23 -0
  901. package/src/providers/connection-resolution.ts +39 -20
  902. package/src/providers/fireworks/client.ts +1 -0
  903. package/src/providers/gemini/client.ts +176 -37
  904. package/src/providers/gemini/inline-media.ts +74 -0
  905. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  906. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  907. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  908. package/src/providers/inference/auth.ts +0 -8
  909. package/src/providers/inference/connections.ts +3 -66
  910. package/src/providers/inference/resolve-auth.ts +2 -3
  911. package/src/providers/model-catalog.ts +35 -1
  912. package/src/providers/model-intents.ts +3 -3
  913. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  914. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +269 -7
  915. package/src/providers/openai/chat-completions-provider.ts +155 -16
  916. package/src/providers/openai/codex-models.ts +2 -0
  917. package/src/providers/openai/responses-provider.ts +54 -57
  918. package/src/providers/openrouter/client.ts +15 -14
  919. package/src/providers/placeholder-sentinels.ts +35 -0
  920. package/src/providers/provider-send-message.ts +23 -14
  921. package/src/providers/ratelimit.ts +1 -9
  922. package/src/providers/registry.ts +48 -8
  923. package/src/providers/retry.ts +16 -9
  924. package/src/providers/search-provider-catalog.ts +17 -9
  925. package/src/providers/types.ts +20 -2
  926. package/src/providers/usage-tracking.ts +1 -9
  927. package/src/runtime/__tests__/agent-wake.test.ts +142 -32
  928. package/src/runtime/__tests__/background-job-runner.test.ts +2 -3
  929. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  930. package/src/runtime/access-request-helper.ts +1 -0
  931. package/src/runtime/agent-wake.ts +95 -23
  932. package/src/runtime/assistant-event-hub.ts +38 -8
  933. package/src/runtime/assistant-stream-state.ts +368 -0
  934. package/src/runtime/auth/__tests__/guard-tests.test.ts +75 -109
  935. package/src/runtime/auth/__tests__/route-policy.test.ts +153 -170
  936. package/src/runtime/auth/route-policy.ts +42 -1069
  937. package/src/runtime/background-job-runner.ts +1 -4
  938. package/src/runtime/btw-sidechain.ts +3 -1
  939. package/src/runtime/channel-approvals.ts +4 -15
  940. package/src/runtime/channel-invite-transport.ts +5 -6
  941. package/src/runtime/channel-readiness-service.ts +70 -5
  942. package/src/runtime/channel-reply-delivery.ts +23 -0
  943. package/src/runtime/channel-retry-sweep.ts +59 -30
  944. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  945. package/src/runtime/http-router.ts +35 -43
  946. package/src/runtime/http-types.ts +23 -71
  947. package/src/runtime/interactive-ui.ts +1 -1
  948. package/src/runtime/invite-instruction-generator.ts +3 -3
  949. package/src/runtime/migrations/vbundle-builder.ts +3 -2
  950. package/src/runtime/pending-interactions.ts +3 -2
  951. package/src/runtime/routes/__tests__/acp-routes.test.ts +253 -55
  952. package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +565 -0
  953. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  954. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
  955. package/src/runtime/routes/__tests__/content-source-routes.test.ts +4 -4
  956. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +436 -0
  957. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +237 -0
  958. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +129 -1
  959. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  960. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  961. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +26 -72
  962. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
  963. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +58 -5
  964. package/src/runtime/routes/__tests__/sanity-routes.test.ts +6 -6
  965. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  966. package/src/runtime/routes/__tests__/stt-routes.test.ts +3 -3
  967. package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +5 -2
  968. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  969. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +297 -0
  970. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  971. package/src/runtime/routes/__tests__/tts-routes.test.ts +9 -5
  972. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  973. package/src/runtime/routes/acp-routes.test.ts +186 -100
  974. package/src/runtime/routes/acp-routes.ts +110 -35
  975. package/src/runtime/routes/app-management-routes.ts +175 -106
  976. package/src/runtime/routes/app-routes.ts +38 -20
  977. package/src/runtime/routes/approval-routes.ts +17 -5
  978. package/src/runtime/routes/attachment-routes.ts +51 -16
  979. package/src/runtime/routes/audio-routes.ts +1 -0
  980. package/src/runtime/routes/audit-routes.ts +5 -0
  981. package/src/runtime/routes/auth-routes.ts +5 -0
  982. package/src/runtime/routes/avatar-routes.ts +264 -59
  983. package/src/runtime/routes/background-tool-routes.ts +9 -0
  984. package/src/runtime/routes/background-wake-routes.ts +201 -23
  985. package/src/runtime/routes/backup-routes.ts +45 -0
  986. package/src/runtime/routes/bookmark-routes.ts +13 -0
  987. package/src/runtime/routes/brain-graph-routes.ts +9 -0
  988. package/src/runtime/routes/browser-routes.ts +6 -1
  989. package/src/runtime/routes/browser-tabs-routes.ts +11 -10
  990. package/src/runtime/routes/btw-routes.ts +37 -27
  991. package/src/runtime/routes/cache-routes.ts +13 -0
  992. package/src/runtime/routes/call-routes.ts +21 -10
  993. package/src/runtime/routes/channel-availability-routes.ts +5 -1
  994. package/src/runtime/routes/channel-readiness-routes.ts +37 -4
  995. package/src/runtime/routes/channel-route-definitions.ts +21 -0
  996. package/src/runtime/routes/channel-verification-routes.ts +21 -0
  997. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +9 -2
  998. package/src/runtime/routes/client-routes.ts +9 -0
  999. package/src/runtime/routes/consolidation-routes.ts +133 -25
  1000. package/src/runtime/routes/contact-prompt-routes.ts +9 -0
  1001. package/src/runtime/routes/contact-routes.ts +90 -23
  1002. package/src/runtime/routes/content-source-routes.ts +5 -1
  1003. package/src/runtime/routes/conversation-analysis-routes.ts +11 -1
  1004. package/src/runtime/routes/conversation-attention-routes.ts +5 -0
  1005. package/src/runtime/routes/conversation-cli-routes.ts +54 -7
  1006. package/src/runtime/routes/conversation-compaction-routes.ts +292 -0
  1007. package/src/runtime/routes/conversation-list-routes.ts +225 -9
  1008. package/src/runtime/routes/conversation-management-routes.ts +96 -28
  1009. package/src/runtime/routes/conversation-query-routes.ts +150 -51
  1010. package/src/runtime/routes/conversation-routes.ts +615 -327
  1011. package/src/runtime/routes/conversation-starter-routes.ts +35 -20
  1012. package/src/runtime/routes/conversations-import-routes.ts +48 -13
  1013. package/src/runtime/routes/credential-prompt-routes.ts +5 -0
  1014. package/src/runtime/routes/credential-routes.ts +25 -6
  1015. package/src/runtime/routes/debug-bash-routes.ts +5 -0
  1016. package/src/runtime/routes/debug-routes.ts +11 -2
  1017. package/src/runtime/routes/defer-routes.ts +13 -0
  1018. package/src/runtime/routes/diagnostics-routes.ts +37 -46
  1019. package/src/runtime/routes/disk-pressure-routes.ts +17 -31
  1020. package/src/runtime/routes/document-comments-routes.ts +46 -27
  1021. package/src/runtime/routes/documents-routes.ts +35 -11
  1022. package/src/runtime/routes/domain-routes.ts +98 -51
  1023. package/src/runtime/routes/email-routes.ts +33 -0
  1024. package/src/runtime/routes/epoch-millis-range.ts +34 -0
  1025. package/src/runtime/routes/events-routes.ts +107 -8
  1026. package/src/runtime/routes/filing-routes.ts +9 -4
  1027. package/src/runtime/routes/gateway-log-routes.ts +31 -4
  1028. package/src/runtime/routes/global-search-routes.ts +53 -50
  1029. package/src/runtime/routes/group-routes.ts +32 -5
  1030. package/src/runtime/routes/guardian-action-routes.ts +9 -0
  1031. package/src/runtime/routes/guardian-approval-interception.ts +0 -31
  1032. package/src/runtime/routes/heartbeat-routes.ts +57 -21
  1033. package/src/runtime/routes/home-feed-routes.ts +149 -16
  1034. package/src/runtime/routes/home-state-routes.ts +8 -40
  1035. package/src/runtime/routes/host-app-control-routes.ts +6 -1
  1036. package/src/runtime/routes/host-bash-routes.ts +5 -0
  1037. package/src/runtime/routes/host-browser-routes.ts +13 -0
  1038. package/src/runtime/routes/host-cu-routes.ts +6 -1
  1039. package/src/runtime/routes/host-file-routes.ts +26 -6
  1040. package/src/runtime/routes/host-transfer-routes.ts +13 -2
  1041. package/src/runtime/routes/http-adapter.ts +1 -2
  1042. package/src/runtime/routes/identity-intro-cache.ts +72 -39
  1043. package/src/runtime/routes/identity-routes.ts +257 -20
  1044. package/src/runtime/routes/image-generation-routes.ts +45 -2
  1045. package/src/runtime/routes/inbound-message-handler.ts +16 -12
  1046. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +524 -12
  1047. package/src/runtime/routes/inbound-stages/background-dispatch.ts +72 -27
  1048. package/src/runtime/routes/index.ts +4 -0
  1049. package/src/runtime/routes/inference-profile-session-routes.ts +13 -3
  1050. package/src/runtime/routes/inference-provider-connection-routes.ts +26 -31
  1051. package/src/runtime/routes/inference-send-routes.ts +11 -11
  1052. package/src/runtime/routes/integrations/a2a.ts +32 -7
  1053. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
  1054. package/src/runtime/routes/integrations/slack/channel.ts +23 -3
  1055. package/src/runtime/routes/integrations/slack/share.ts +36 -8
  1056. package/src/runtime/routes/integrations/telegram.ts +34 -9
  1057. package/src/runtime/routes/integrations/twilio.ts +77 -7
  1058. package/src/runtime/routes/integrations/vercel.ts +18 -3
  1059. package/src/runtime/routes/internal-oauth-routes.ts +5 -0
  1060. package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
  1061. package/src/runtime/routes/internal-twilio-routes.ts +13 -0
  1062. package/src/runtime/routes/llm-call-sites-routes.ts +39 -4
  1063. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  1064. package/src/runtime/routes/log-export-routes.ts +36 -10
  1065. package/src/runtime/routes/mcp-auth-routes.ts +25 -0
  1066. package/src/runtime/routes/memory-item-routes.ts +21 -10
  1067. package/src/runtime/routes/memory-v2-routes.ts +105 -44
  1068. package/src/runtime/routes/memory-v3-routes.ts +313 -257
  1069. package/src/runtime/routes/migration-rollback-routes.ts +5 -1
  1070. package/src/runtime/routes/migration-routes.ts +49 -13
  1071. package/src/runtime/routes/notification-routes.ts +80 -2
  1072. package/src/runtime/routes/oauth-apps.ts +99 -23
  1073. package/src/runtime/routes/oauth-commands-routes.ts +43 -15
  1074. package/src/runtime/routes/oauth-connect-routes.ts +9 -0
  1075. package/src/runtime/routes/oauth-lifecycle-routes.ts +5 -1
  1076. package/src/runtime/routes/oauth-providers.ts +79 -15
  1077. package/src/runtime/routes/platform-routes.ts +102 -5
  1078. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +9 -6
  1079. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +37 -16
  1080. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +7 -3
  1081. package/src/runtime/routes/playground/__tests__/state.test.ts +10 -3
  1082. package/src/runtime/routes/playground/force-compact.ts +2 -2
  1083. package/src/runtime/routes/playground/helpers.ts +1 -2
  1084. package/src/runtime/routes/playground/inject-failures.ts +13 -8
  1085. package/src/runtime/routes/playground/reset-circuit.ts +14 -9
  1086. package/src/runtime/routes/playground/seed-conversation.ts +1 -1
  1087. package/src/runtime/routes/playground/seeded-conversations.ts +3 -3
  1088. package/src/runtime/routes/playground/state.ts +4 -3
  1089. package/src/runtime/routes/plugins-routes.ts +22 -19
  1090. package/src/runtime/routes/profiler-routes.ts +17 -4
  1091. package/src/runtime/routes/ps-routes.ts +5 -0
  1092. package/src/runtime/routes/publish-routes.ts +13 -3
  1093. package/src/runtime/routes/question-routes.ts +5 -0
  1094. package/src/runtime/routes/recording-routes.ts +25 -12
  1095. package/src/runtime/routes/rename-conversation-routes.ts +10 -0
  1096. package/src/runtime/routes/sanity-routes.ts +9 -2
  1097. package/src/runtime/routes/schedule-routes.ts +288 -88
  1098. package/src/runtime/routes/secret-routes.ts +31 -6
  1099. package/src/runtime/routes/sequence-routes.ts +33 -0
  1100. package/src/runtime/routes/settings-routes.ts +65 -19
  1101. package/src/runtime/routes/skills-routes.ts +166 -73
  1102. package/src/runtime/routes/slack-channel-routes.ts +5 -0
  1103. package/src/runtime/routes/stt-routes.ts +13 -6
  1104. package/src/runtime/routes/subagents-routes.ts +24 -18
  1105. package/src/runtime/routes/suggest-trust-rule-routes.ts +7 -2
  1106. package/src/runtime/routes/surface-action-routes.ts +10 -38
  1107. package/src/runtime/routes/surface-content-routes.ts +21 -6
  1108. package/src/runtime/routes/surface-conversation-resolver.ts +66 -0
  1109. package/src/runtime/routes/task-routes.ts +37 -0
  1110. package/src/runtime/routes/telemetry-routes.ts +9 -0
  1111. package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
  1112. package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
  1113. package/src/runtime/routes/trace-event-routes.ts +42 -1
  1114. package/src/runtime/routes/trust-rules-routes.ts +31 -2
  1115. package/src/runtime/routes/tts-routes.ts +48 -6
  1116. package/src/runtime/routes/types.ts +83 -16
  1117. package/src/runtime/routes/ui-request-routes.ts +5 -0
  1118. package/src/runtime/routes/upgrade-broadcast-routes.ts +5 -0
  1119. package/src/runtime/routes/usage-routes.ts +118 -42
  1120. package/src/runtime/routes/user-routes-cli.ts +9 -0
  1121. package/src/runtime/routes/user-routes.ts +5 -1
  1122. package/src/runtime/routes/wake-conversation-routes.ts +5 -0
  1123. package/src/runtime/routes/watcher-routes.ts +21 -0
  1124. package/src/runtime/routes/webhook-routes.ts +50 -2
  1125. package/src/runtime/routes/wipe-conversation-routes.ts +8 -0
  1126. package/src/runtime/routes/work-items-routes.ts +49 -23
  1127. package/src/runtime/routes/workspace-commit-routes.ts +5 -0
  1128. package/src/runtime/routes/workspace-routes.test.ts +42 -0
  1129. package/src/runtime/routes/workspace-routes.ts +124 -9
  1130. package/src/runtime/services/__tests__/analyze-conversation.test.ts +10 -4
  1131. package/src/runtime/services/analyze-conversation.ts +5 -8
  1132. package/src/runtime/services/conversation-serializer.ts +24 -2
  1133. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  1134. package/src/runtime/sync/resource-sync-events.ts +17 -3
  1135. package/src/runtime/sync/sync-publisher.ts +2 -2
  1136. package/src/runtime/tool-grant-request-helper.ts +1 -0
  1137. package/src/schedule/run-script.ts +28 -3
  1138. package/src/schedule/schedule-store.ts +36 -2
  1139. package/src/schedule/schedule-usage-store.ts +83 -0
  1140. package/src/schedule/scheduler.ts +126 -21
  1141. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  1142. package/src/security/encrypted-store.ts +7 -16
  1143. package/src/security/store-path-override.ts +61 -0
  1144. package/src/signals/cancel.ts +2 -4
  1145. package/src/signals/user-message.ts +10 -16
  1146. package/src/skills/catalog-files.ts +4 -1
  1147. package/src/skills/catalog-install.ts +3 -0
  1148. package/src/skills/categories-cache.ts +118 -0
  1149. package/src/skills/clawhub-files.ts +1 -0
  1150. package/src/skills/skillssh-files.ts +1 -0
  1151. package/src/skills/validate-input.ts +177 -0
  1152. package/src/subagent/manager.ts +33 -24
  1153. package/src/subagent/types.ts +6 -0
  1154. package/src/tasks/tool-sanitizer.ts +2 -2
  1155. package/src/telemetry/types.ts +55 -1
  1156. package/src/telemetry/usage-telemetry-reporter.test.ts +250 -4
  1157. package/src/telemetry/usage-telemetry-reporter.ts +88 -2
  1158. package/src/tools/acp/context.ts +20 -0
  1159. package/src/tools/acp/list-agents.test.ts +7 -1
  1160. package/src/tools/acp/spawn.test.ts +198 -93
  1161. package/src/tools/acp/spawn.ts +32 -70
  1162. package/src/tools/acp/steer.test.ts +105 -8
  1163. package/src/tools/acp/steer.ts +48 -17
  1164. package/src/tools/apps/definitions.ts +42 -24
  1165. package/src/tools/apps/executors.ts +13 -8
  1166. package/src/tools/ask-question/ask-question-tool.test.ts +120 -105
  1167. package/src/tools/ask-question/ask-question-tool.ts +85 -90
  1168. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  1169. package/src/tools/computer-use/definitions.ts +295 -289
  1170. package/src/tools/credential-execution/make-authenticated-request.ts +56 -51
  1171. package/src/tools/credential-execution/manage-secure-command-tool.ts +2 -2
  1172. package/src/tools/credential-execution/run-authenticated-command.ts +82 -77
  1173. package/src/tools/credentials/vault.ts +112 -111
  1174. package/src/tools/document/document-tool.ts +131 -8
  1175. package/src/tools/execution-target.ts +3 -6
  1176. package/src/tools/execution-timeout.ts +3 -4
  1177. package/src/tools/executor.ts +18 -107
  1178. package/src/tools/filesystem/edit.ts +45 -42
  1179. package/src/tools/filesystem/list.ts +33 -30
  1180. package/src/tools/filesystem/read.ts +54 -35
  1181. package/src/tools/filesystem/write.ts +69 -32
  1182. package/src/tools/host-filesystem/edit.test.ts +1 -0
  1183. package/src/tools/host-filesystem/edit.ts +44 -42
  1184. package/src/tools/host-filesystem/read.test.ts +1 -0
  1185. package/src/tools/host-filesystem/read.ts +49 -35
  1186. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  1187. package/src/tools/host-filesystem/transfer.ts +121 -108
  1188. package/src/tools/host-filesystem/write.test.ts +1 -0
  1189. package/src/tools/host-filesystem/write.ts +33 -31
  1190. package/src/tools/host-terminal/host-shell.ts +50 -48
  1191. package/src/tools/mcp/mcp-tool-factory.ts +0 -2
  1192. package/src/tools/memory/register.ts +23 -24
  1193. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  1194. package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
  1195. package/src/tools/network/__tests__/web-search.test.ts +222 -6
  1196. package/src/tools/network/managed-search-proxy.ts +183 -0
  1197. package/src/tools/network/web-fetch.ts +49 -46
  1198. package/src/tools/network/web-search-error.test.ts +248 -0
  1199. package/src/tools/network/web-search-error.ts +267 -0
  1200. package/src/tools/network/web-search.ts +414 -97
  1201. package/src/tools/policy-context.ts +3 -1
  1202. package/src/tools/registry.ts +184 -118
  1203. package/src/tools/schedule/create.ts +14 -1
  1204. package/src/tools/schedule/update.ts +16 -0
  1205. package/src/tools/shared/filesystem/audio-read.ts +122 -0
  1206. package/src/tools/shared/filesystem/image-read.ts +1 -1
  1207. package/src/tools/skills/execute.ts +34 -31
  1208. package/src/tools/skills/load.ts +29 -23
  1209. package/src/tools/skills/skill-tool-factory.ts +17 -36
  1210. package/src/tools/subagent/notify-parent.ts +35 -32
  1211. package/src/tools/subagent/spawn.ts +2 -1
  1212. package/src/tools/system/avatar-generator.ts +13 -22
  1213. package/src/tools/system/request-permission.ts +30 -27
  1214. package/src/tools/terminal/safe-env.ts +10 -1
  1215. package/src/tools/terminal/shell.ts +190 -61
  1216. package/src/tools/tool-approval-handler.ts +10 -4
  1217. package/src/tools/tool-defaults.ts +20 -9
  1218. package/src/tools/tool-manifest.ts +4 -4
  1219. package/src/tools/tool-name-aliases.ts +72 -14
  1220. package/src/tools/types.ts +86 -33
  1221. package/src/tools/ui-surface/definitions.ts +196 -95
  1222. package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
  1223. package/src/tts/provider-catalog.ts +76 -1
  1224. package/src/types/onboarding-context.ts +6 -0
  1225. package/src/usage/attribution.ts +32 -1
  1226. package/src/usage/types.ts +10 -0
  1227. package/src/util/browser.ts +7 -2
  1228. package/src/util/errors.ts +2 -2
  1229. package/src/util/map-limit.ts +27 -0
  1230. package/src/util/mutex.ts +47 -0
  1231. package/src/util/platform.ts +15 -12
  1232. package/src/work-items/work-item-runner.ts +7 -2
  1233. package/src/workspace/git-service.ts +1 -42
  1234. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +7 -20
  1235. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  1236. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  1237. package/src/workspace/migrations/092-backfill-v3-leaves.ts +169 -0
  1238. package/src/workspace/migrations/093-backfill-leaf-ids.ts +144 -0
  1239. package/src/workspace/migrations/094-seed-avatar-manifest.ts +155 -0
  1240. package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
  1241. package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
  1242. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
  1243. package/src/workspace/migrations/__tests__/094-seed-avatar-manifest.test.ts +136 -0
  1244. package/src/workspace/migrations/__tests__/backfill-leaf-ids.test.ts +175 -0
  1245. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +124 -0
  1246. package/src/workspace/migrations/registry.ts +16 -0
  1247. package/src/workspace/provider-commit-message-generator.ts +15 -17
  1248. package/tsconfig.json +4 -1
  1249. package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
  1250. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  1251. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  1252. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -262
  1253. package/src/__tests__/empty-response-pipeline.test.ts +0 -301
  1254. package/src/__tests__/history-repair-pipeline.test.ts +0 -396
  1255. package/src/__tests__/llm-call-pipeline.test.ts +0 -281
  1256. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
  1257. package/src/__tests__/persistence-pipeline.test.ts +0 -376
  1258. package/src/__tests__/title-generate-pipeline.test.ts +0 -211
  1259. package/src/__tests__/token-estimate-pipeline.test.ts +0 -481
  1260. package/src/__tests__/tool-error-pipeline.test.ts +0 -241
  1261. package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
  1262. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -344
  1263. package/src/cli/commands/__tests__/memory-v3-render.test.ts +0 -340
  1264. package/src/cli/commands/memory-v3-render.ts +0 -344
  1265. package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
  1266. package/src/daemon/message-types/disk-pressure.ts +0 -9
  1267. package/src/email/feature-gate.ts +0 -23
  1268. package/src/gallery/default-gallery.ts +0 -1359
  1269. package/src/gallery/gallery-manifest.ts +0 -28
  1270. package/src/memory/v3/__tests__/coactivation-store.test.ts +0 -422
  1271. package/src/memory/v3/__tests__/consolidation-job.test.ts +0 -468
  1272. package/src/memory/v3/__tests__/edge-learning-job.test.ts +0 -324
  1273. package/src/memory/v3/__tests__/edges.test.ts +0 -563
  1274. package/src/memory/v3/__tests__/filter.test.ts +0 -512
  1275. package/src/memory/v3/__tests__/gate.test.ts +0 -574
  1276. package/src/memory/v3/__tests__/index-composition.test.ts +0 -233
  1277. package/src/memory/v3/__tests__/loop.test.ts +0 -530
  1278. package/src/memory/v3/__tests__/retriever.test.ts +0 -226
  1279. package/src/memory/v3/__tests__/scouts.test.ts +0 -440
  1280. package/src/memory/v3/__tests__/shadow-middleware.test.ts +0 -312
  1281. package/src/memory/v3/__tests__/system-prompts.test.ts +0 -154
  1282. package/src/memory/v3/__tests__/traversal.test.ts +0 -469
  1283. package/src/memory/v3/__tests__/tree-index.test.ts +0 -280
  1284. package/src/memory/v3/__tests__/tree-store.test.ts +0 -529
  1285. package/src/memory/v3/__tests__/tree-walk.test.ts +0 -707
  1286. package/src/memory/v3/__tests__/validate.test.ts +0 -245
  1287. package/src/memory/v3/auto-edges.ts +0 -223
  1288. package/src/memory/v3/coactivation-store.ts +0 -124
  1289. package/src/memory/v3/consolidation-job.ts +0 -323
  1290. package/src/memory/v3/edge-learning-job.ts +0 -160
  1291. package/src/memory/v3/edges.ts +0 -249
  1292. package/src/memory/v3/filter.ts +0 -281
  1293. package/src/memory/v3/gate.ts +0 -334
  1294. package/src/memory/v3/index-composition.ts +0 -113
  1295. package/src/memory/v3/llm-capture.ts +0 -46
  1296. package/src/memory/v3/loop.ts +0 -382
  1297. package/src/memory/v3/maintenance.ts +0 -144
  1298. package/src/memory/v3/prompt-context.ts +0 -33
  1299. package/src/memory/v3/prompts/consolidation.ts +0 -458
  1300. package/src/memory/v3/prompts/system-prompts.ts +0 -196
  1301. package/src/memory/v3/retriever.ts +0 -33
  1302. package/src/memory/v3/scouts.ts +0 -420
  1303. package/src/memory/v3/shadow-middleware.ts +0 -305
  1304. package/src/memory/v3/traversal.ts +0 -206
  1305. package/src/memory/v3/tree-index.ts +0 -237
  1306. package/src/memory/v3/tree-store.ts +0 -394
  1307. package/src/memory/v3/tree-walk.ts +0 -351
  1308. package/src/memory/v3/types.ts +0 -65
  1309. package/src/memory/v3/validate.ts +0 -300
  1310. package/src/plugins/defaults/circuit-breaker.ts +0 -141
  1311. package/src/plugins/defaults/compaction.ts +0 -141
  1312. package/src/plugins/defaults/empty-response.ts +0 -124
  1313. package/src/plugins/defaults/history-repair.ts +0 -83
  1314. package/src/plugins/defaults/llm-call.ts +0 -77
  1315. package/src/plugins/defaults/memory-retrieval.ts +0 -219
  1316. package/src/plugins/defaults/overflow-reduce.ts +0 -185
  1317. package/src/plugins/defaults/persistence.ts +0 -127
  1318. package/src/plugins/defaults/title-generate.ts +0 -90
  1319. package/src/plugins/defaults/token-estimate.ts +0 -101
  1320. package/src/plugins/defaults/tool-error.ts +0 -119
  1321. package/src/plugins/defaults/tool-execute.ts +0 -87
  1322. package/src/plugins/defaults/tool-result-truncate.ts +0 -84
  1323. package/src/skills/category-inference.ts +0 -111
@@ -14,15 +14,11 @@
14
14
  import { createRequire } from "node:module";
15
15
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
16
16
 
17
- import type {
18
- AgentEvent,
19
- CheckpointDecision,
20
- CheckpointInfo,
21
- } from "../agent/loop.js";
17
+ import type { LoopToolExecutor } from "../agent/loop.js";
22
18
  import type { LLMConfig } from "../config/schemas/llm.js";
23
19
  import type { ServerMessage } from "../daemon/message-protocol.js";
24
20
  import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
25
- import type { ContentBlock, Message } from "../providers/types.js";
21
+ import type { Message, Provider, ToolDefinition } from "../providers/types.js";
26
22
 
27
23
  const conversationCrudRealSnapshot = {
28
24
  ...(createRequire(import.meta.url)(
@@ -91,6 +87,7 @@ mock.module("../config/loader.js", () => ({
91
87
  memory: { retrieval: { scratchpadInjection: { enabled: true } } },
92
88
  ui: {},
93
89
  compaction: { enabled: true, autoThreshold: 0.7 },
90
+ conversations: { skipAutoRetitling: true },
94
91
  }),
95
92
  loadRawConfig: () => ({}),
96
93
  saveRawConfig: () => {},
@@ -102,10 +99,10 @@ mock.module("../config/loader.js", () => ({
102
99
  // Token estimator — controllable per-test via mockEstimateTokens.
103
100
  // Can be a number (constant), a no-arg function, or a function that
104
101
  // receives the messages array for dynamic behavior based on content.
105
- // Both the calibrated entry point (`estimatePromptTokens`, used in the
106
- // convergence path) and the raw entry point (`estimatePromptTokensRaw`,
107
- // used by the default `tokenEstimate` plugin pipeline for preflight/mid-
108
- // loop) are stubbed so either call site can drive the test.
102
+ // Both the calibrated entry point (`estimatePromptTokens`, which backs the
103
+ // preflight overflow gate and the convergence path) and the raw entry point
104
+ // (`estimatePromptTokensRaw`, used by the pre-send calibration capture) are
105
+ // stubbed so either call site can drive the test.
109
106
  let mockEstimateTokens: number | ((msgs?: Message[]) => number) = 1000;
110
107
  mock.module("../context/token-estimator.js", () => ({
111
108
  estimatePromptTokens: (msgs: Message[]) =>
@@ -116,8 +113,16 @@ mock.module("../context/token-estimator.js", () => ({
116
113
  typeof mockEstimateTokens === "function"
117
114
  ? mockEstimateTokens(msgs)
118
115
  : mockEstimateTokens,
119
- // Default plugin multiplies-in tool tokens via this helper; 0 keeps the
120
- // stubbed raw value unchanged.
116
+ // The preflight overflow gate calls this calibrated wrapper directly, so it
117
+ // must honor `mockEstimateTokens` too — otherwise the real implementation
118
+ // (which sums tool tokens onto the real calibrated estimate) ignores the
119
+ // per-test value and the overflow scenarios below never trigger.
120
+ estimatePromptTokensWithTools: (history: Message[]) =>
121
+ typeof mockEstimateTokens === "function"
122
+ ? mockEstimateTokens(history)
123
+ : mockEstimateTokens,
124
+ // `estimatePromptTokensWithTools` folds tool tokens in via this helper; 0
125
+ // keeps the stubbed value unchanged.
121
126
  estimateToolsTokens: () => 0,
122
127
  // Conversation agent loop now calls this helper to canonicalize the
123
128
  // provider key shared with the calibration system. The tests here
@@ -198,6 +203,7 @@ mock.module("../memory/conversation-crud.js", () => ({
198
203
  setLastNotifiedInferenceProfile: () => {},
199
204
  getLastUserTimestampBefore: () => 0,
200
205
  getConversationOverrideProfileFromRow: () => undefined,
206
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
201
207
  }));
202
208
 
203
209
  afterAll(() => {
@@ -268,15 +274,6 @@ mock.module("../daemon/conversation-runtime-assembly.js", () => ({
268
274
  blocks: {},
269
275
  }),
270
276
  stripInjectionsForCompaction: (msgs: Message[]) => msgs,
271
- findLastInjectedNowContent: () => null,
272
- readNowScratchpad: () => null,
273
- readPkbContext: () => null,
274
- getPkbAutoInjectList: () => [
275
- "INDEX.md",
276
- "essentials.md",
277
- "threads.md",
278
- "buffer.md",
279
- ],
280
277
  isSlackChannelConversation: () => false,
281
278
  getSlackCompactionWatermarkForPrefix: () => null,
282
279
  loadSlackChronologicalContext: () => null,
@@ -290,7 +287,7 @@ mock.module("../daemon/date-context.js", () => ({
290
287
  formatTurnTimestamp: () => "2026-01-01 (Thursday) 00:00:00 +00:00 (UTC)",
291
288
  }));
292
289
 
293
- mock.module("../daemon/history-repair.js", () => ({
290
+ mock.module("../plugins/defaults/history-repair/terminal.js", () => ({
294
291
  repairHistory: (msgs: Message[]) => ({
295
292
  messages: msgs,
296
293
  stats: {
@@ -424,37 +421,55 @@ mock.module("../memory/archive-store.js", () => ({
424
421
 
425
422
  // ── Imports (after mocks) ────────────────────────────────────────────
426
423
 
424
+ import { AgentLoop } from "../agent/loop.js";
427
425
  import {
428
426
  type AgentLoopConversationContext,
429
427
  runAgentLoopImpl,
430
428
  } from "../daemon/conversation-agent-loop.js";
429
+ import {
430
+ createMockProvider,
431
+ type ScriptedResponse,
432
+ textResponse,
433
+ toolUseResponse,
434
+ } from "./helpers/mock-provider.js";
431
435
 
432
436
  // ── Test helpers ─────────────────────────────────────────────────────
433
437
 
434
- type AgentLoopRun = (
435
- messages: Message[],
436
- onEvent: (event: AgentEvent) => void,
437
- signal?: AbortSignal,
438
- requestId?: string,
439
- onCheckpoint?: (
440
- checkpoint: CheckpointInfo,
441
- ) => CheckpointDecision | Promise<CheckpointDecision>,
442
- ) => Promise<Message[]>;
443
-
444
438
  function makeCtx(
445
439
  overrides?: Partial<AgentLoopConversationContext> & {
446
- agentLoopRun?: AgentLoopRun;
440
+ providerResponses?: ScriptedResponse[];
441
+ loopProvider?: Provider;
442
+ loopTools?: ToolDefinition[];
443
+ toolExecutor?: LoopToolExecutor;
447
444
  },
448
445
  ): AgentLoopConversationContext {
449
- const agentLoopRun =
450
- overrides?.agentLoopRun ??
451
- (async (messages: Message[]) => [
452
- ...messages,
453
- {
454
- role: "assistant" as const,
455
- content: [{ type: "text" as const, text: "response" }],
456
- },
457
- ]);
446
+ const {
447
+ providerResponses,
448
+ loopProvider,
449
+ loopTools,
450
+ toolExecutor,
451
+ ...ctxOverrides
452
+ } = overrides ?? {};
453
+ const conversationId = ctxOverrides.conversationId ?? "test-conv";
454
+
455
+ // Drive the real `AgentLoop` against a scripted provider, mocking only the
456
+ // provider HTTP boundary. The loop owns its mid-loop budget gate, inline
457
+ // compaction, and event emission, so these overflow tests exercise the real
458
+ // escalation/persistence path.
459
+ const loopProviderName =
460
+ (ctxOverrides.provider as { name?: string } | undefined)?.name ??
461
+ "mock-provider";
462
+ const provider =
463
+ loopProvider ??
464
+ createMockProvider(
465
+ providerResponses ?? [textResponse("response")],
466
+ loopProviderName,
467
+ ).provider;
468
+ const agentLoop = new AgentLoop(provider, "system prompt", {
469
+ conversationId,
470
+ tools: loopTools ?? [],
471
+ toolExecutor,
472
+ });
458
473
 
459
474
  return {
460
475
  conversationId: "test-conv",
@@ -462,18 +477,16 @@ function makeCtx(
462
477
  { role: "user", content: [{ type: "text", text: "Hello" }] },
463
478
  ] as Message[],
464
479
  processing: true,
480
+ isProcessing(this: { processing: boolean }) {
481
+ return this.processing;
482
+ },
483
+ setProcessing(this: { processing: boolean }, value: boolean) {
484
+ this.processing = value;
485
+ },
465
486
  abortController: new AbortController(),
466
487
  currentRequestId: "test-req",
467
488
 
468
- agentLoop: {
469
- run: agentLoopRun,
470
- getToolTokenBudget: () => 0,
471
- getResolvedTools: () => [],
472
- // Tests in this file don't exercise calibration, so returning
473
- // undefined is fine — the estimator falls back to the per-provider
474
- // aggregate key.
475
- getActiveModel: () => undefined,
476
- } as unknown as AgentLoopConversationContext["agentLoop"],
489
+ agentLoop,
477
490
  provider: {
478
491
  name: "mock-provider",
479
492
  sendMessage: async () => ({
@@ -502,8 +515,6 @@ function makeCtx(
502
515
  currentTurnSurfaces: [],
503
516
 
504
517
  workingDir: "/tmp",
505
- workspaceTopLevelContext: null,
506
- workspaceTopLevelDirty: false,
507
518
  channelCapabilities: undefined,
508
519
  commandIntent: undefined,
509
520
  trustContext: undefined,
@@ -540,7 +551,6 @@ function makeCtx(
540
551
  getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
541
552
  commitTurnChanges: async () => {},
542
553
 
543
- refreshWorkspaceTopLevelContextIfNeeded: () => {},
544
554
  markWorkspaceTopLevelDirty: () => {},
545
555
  emitActivityState: () => {},
546
556
  getQueueDepth: () => 0,
@@ -566,9 +576,10 @@ function makeCtx(
566
576
  injectedTokens: 0,
567
577
  }),
568
578
  retrackCachedNodes: () => {},
579
+ recordPkbQueryVectors: () => {},
569
580
  } as unknown as AgentLoopConversationContext["graphMemory"],
570
581
 
571
- ...overrides,
582
+ ...ctxOverrides,
572
583
  } as AgentLoopConversationContext;
573
584
  }
574
585
 
@@ -637,15 +648,15 @@ beforeEach(() => {
637
648
  recordUsageMock.mockClear();
638
649
  setAgentLoopExitReasonOnLatestLogMock.mockClear();
639
650
  addMessageMock.mockClear();
640
- // Reset the plugin registry and re-register every default so the
641
- // orchestrator's pipelines (`overflowReduce`, `persistence`, …) dispatch to
642
- // the default middleware, which in turn hits the mocked collaborators
643
- // (`reduceContextOverflow`, `syncMessageToDisk`, …) these tests install.
651
+ // Reset the plugin registry and re-register every default so the compaction
652
+ // pipeline dispatches to the default middleware, which in turn hits the
653
+ // mocked collaborators (`syncMessageToDisk`, …) these tests install.
644
654
  resetPluginRegistryAndRegisterDefaults();
645
655
  });
646
656
 
647
657
  describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
648
658
  test("usage update context max follows active main-agent profile budget", async () => {
659
+ // GIVEN an active main-agent profile that narrows the context budget
649
660
  mockLlmConfig = {
650
661
  ...structuredClone(defaultLlmConfig),
651
662
  activeProfile: "short-context",
@@ -657,27 +668,22 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
657
668
  },
658
669
  };
659
670
 
671
+ // AND a provider turn that reports 12k input tokens of usage
660
672
  const ctx = makeCtx({
661
- agentLoopRun: async (messages, onEvent) => {
662
- onEvent({
663
- type: "usage",
664
- inputTokens: 12_000,
665
- outputTokens: 300,
673
+ providerResponses: [
674
+ {
675
+ content: [{ type: "text", text: "response" }],
666
676
  model: "mock-model",
667
- providerDurationMs: 25,
668
- });
669
- return [
670
- ...messages,
671
- {
672
- role: "assistant" as const,
673
- content: [{ type: "text" as const, text: "response" }],
674
- },
675
- ];
676
- },
677
+ usage: { inputTokens: 12_000, outputTokens: 300 },
678
+ stopReason: "end_turn",
679
+ },
680
+ ],
677
681
  });
678
682
 
683
+ // WHEN the turn runs to completion
679
684
  await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
680
685
 
686
+ // THEN the recorded main-agent usage carries the profile's max budget
681
687
  const mainAgentUsageCall = recordUsageMock.mock.calls.find(
682
688
  (call) => call[5] === "main_agent",
683
689
  );
@@ -690,10 +696,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
690
696
 
691
697
  // ── Test 1 ────────────────────────────────────────────────────────
692
698
  // BUG: When the agent loop makes progress (adds messages to history)
693
- // before hitting context_too_large, the convergence loop at line 864
694
- // checks `updatedHistory.length === preRunHistoryLength` which is
695
- // false when progress was made. This means the reducer is never
696
- // invoked — the error is surfaced immediately at line 1163-1175
699
+ // before hitting context_too_large, the convergence loop's progress
700
+ // check must recognize that the loop appended messages. If it fails to,
701
+ // the reducer is never invoked — the error is surfaced immediately
697
702
  // without any compaction attempt.
698
703
  //
699
704
  // Expected behavior (PR 2 fix): After progress + context_too_large,
@@ -733,122 +738,31 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
733
738
  };
734
739
  };
735
740
 
736
- let agentLoopCallCount = 0;
737
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
738
- agentLoopCallCount++;
739
- if (agentLoopCallCount === 1) {
740
- // Simulate: agent makes progress (tool calls + results added)
741
- // then hits context_too_large on next LLM call
742
- const progressMessages: Message[] = [
743
- ...messages,
744
- {
745
- role: "assistant" as const,
746
- content: [
747
- { type: "text", text: "Let me check that." },
748
- {
749
- type: "tool_use",
750
- id: "tu-progress",
751
- name: "bash",
752
- input: { command: "ls" },
753
- },
754
- ] as ContentBlock[],
755
- },
756
- {
757
- role: "user" as const,
758
- content: [
759
- {
760
- type: "tool_result",
761
- tool_use_id: "tu-progress",
762
- content: "file1.ts\nfile2.ts",
763
- is_error: false,
764
- },
765
- ] as ContentBlock[],
766
- },
767
- ];
741
+ // Run 1 makes progress (a tool turn) then the following provider call
742
+ // rejects with a context_too_large error; after the convergence reducer
743
+ // compacts, the rerun recovers with plain text.
744
+ const { provider } = createMockProvider([
745
+ toolUseResponse("tu-progress", "bash", { command: "ls" }),
746
+ new Error("prompt is too long: 242201 tokens > 200000 maximum"),
747
+ textResponse("recovered after compaction"),
748
+ ]);
768
749
 
769
- // Emit events for the progress that was made
770
- onEvent({
771
- type: "tool_use",
772
- id: "tu-progress",
750
+ const ctx = makeCtx({
751
+ loopProvider: provider,
752
+ loopTools: [
753
+ {
773
754
  name: "bash",
774
- input: { command: "ls" },
775
- });
776
- onEvent({
777
- type: "tool_result",
778
- toolUseId: "tu-progress",
779
- content: "file1.ts\nfile2.ts",
780
- isError: false,
781
- });
782
- onEvent({
783
- type: "message_complete",
784
- message: {
785
- role: "assistant",
786
- content: [
787
- { type: "text", text: "Let me check that." },
788
- {
789
- type: "tool_use",
790
- id: "tu-progress",
791
- name: "bash",
792
- input: { command: "ls" },
793
- },
794
- ],
755
+ description: "Run a shell command",
756
+ input_schema: {
757
+ type: "object",
758
+ properties: { command: { type: "string" } },
795
759
  },
796
- });
797
- onEvent({
798
- type: "usage",
799
- inputTokens: 100,
800
- outputTokens: 50,
801
- model: "test-model",
802
- providerDurationMs: 100,
803
- });
804
-
805
- // Then context_too_large error occurs on the *next* LLM call
806
- onEvent({
807
- type: "error",
808
- error: new Error(
809
- "prompt is too long: 242201 tokens > 200000 maximum",
810
- ),
811
- });
812
- onEvent({
813
- type: "usage",
814
- inputTokens: 0,
815
- outputTokens: 0,
816
- model: "test-model",
817
- providerDurationMs: 10,
818
- });
819
-
820
- // Return the history WITH progress (more messages than input)
821
- return progressMessages;
822
- }
823
-
824
- // Second call (after compaction): succeed
825
- onEvent({
826
- type: "message_complete",
827
- message: {
828
- role: "assistant",
829
- content: [{ type: "text", text: "recovered after compaction" }],
830
760
  },
831
- });
832
- onEvent({
833
- type: "usage",
834
- inputTokens: 50,
835
- outputTokens: 25,
836
- model: "test-model",
837
- providerDurationMs: 100,
838
- });
839
- return [
840
- ...messages,
841
- {
842
- role: "assistant" as const,
843
- content: [
844
- { type: "text", text: "recovered after compaction" },
845
- ] as ContentBlock[],
846
- },
847
- ];
848
- };
849
-
850
- const ctx = makeCtx({
851
- agentLoopRun,
761
+ ],
762
+ toolExecutor: async () => ({
763
+ content: "file1.ts\nfile2.ts",
764
+ isError: false,
765
+ }),
852
766
  contextWindowManager: {
853
767
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
854
768
  maybeCompact: async () => ({ compacted: false }),
@@ -877,13 +791,14 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
877
791
  // This test should PASS against current code (when no progress is made).
878
792
  test("overflow recovery compacts below limit even when estimation underestimates", async () => {
879
793
  const events: ServerMessage[] = [];
880
- let callCount = 0;
881
794
  let reducerCalled = false;
882
795
 
883
- // Estimator says 185k (below 190k budget = 200k * 0.95)
796
+ // GIVEN the estimator reports 185k — under the 190k preflight budget
797
+ // (200k * 0.95), so the turn proceeds to the provider rather than
798
+ // compacting up front.
884
799
  mockEstimateTokens = 185_000;
885
800
 
886
- // Reducer successfully compacts
801
+ // AND the post-run convergence reducer successfully compacts
887
802
  mockReducerStepFn = (msgs: Message[]) => {
888
803
  reducerCalled = true;
889
804
  return {
@@ -913,93 +828,46 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
913
828
  };
914
829
  };
915
830
 
916
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
917
- callCount++;
918
- if (callCount === 1) {
919
- // Provider rejects with "prompt is too long: 242201 tokens > 200000"
920
- // even though estimator said 185k
921
- onEvent({
922
- type: "error",
923
- error: new Error(
924
- "prompt is too long: 242201 tokens > 200000 maximum",
925
- ),
926
- });
927
- onEvent({
928
- type: "usage",
929
- inputTokens: 0,
930
- outputTokens: 0,
931
- model: "test-model",
932
- providerDurationMs: 10,
933
- });
934
- // No progress — return same messages
935
- return messages;
936
- }
937
- // Second call succeeds
938
- onEvent({
939
- type: "message_complete",
940
- message: {
941
- role: "assistant",
942
- content: [{ type: "text", text: "recovered" }],
943
- },
944
- });
945
- onEvent({
946
- type: "usage",
947
- inputTokens: 80_000,
948
- outputTokens: 200,
949
- model: "test-model",
950
- providerDurationMs: 500,
951
- });
952
- return [
953
- ...messages,
954
- {
955
- role: "assistant" as const,
956
- content: [{ type: "text", text: "recovered" }] as ContentBlock[],
957
- },
958
- ];
959
- };
831
+ // AND a provider that rejects the first call as too long (revealing the
832
+ // real 242k count the estimator missed), then succeeds on the rerun.
833
+ const { provider, calls } = createMockProvider([
834
+ new Error("prompt is too long: 242201 tokens > 200000 maximum"),
835
+ textResponse("recovered"),
836
+ ]);
960
837
 
961
838
  const ctx = makeCtx({
962
- agentLoopRun,
839
+ loopProvider: provider,
963
840
  contextWindowManager: {
964
841
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
965
842
  maybeCompact: async () => ({ compacted: false }),
966
843
  } as unknown as AgentLoopConversationContext["contextWindowManager"],
967
844
  });
968
845
 
846
+ // WHEN the turn runs
969
847
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
970
848
 
971
- // The reducer should be called in the convergence loop
849
+ // THEN the convergence reducer ran and the rerun recovered without a
850
+ // user-facing conversation_error.
972
851
  expect(reducerCalled).toBe(true);
973
- // Should recover without conversation_error
974
852
  const conversationError = events.find(
975
853
  (e) => e.type === "conversation_error",
976
854
  );
977
855
  expect(conversationError).toBeUndefined();
978
- expect(callCount).toBe(2);
856
+ expect(calls.length).toBe(2);
979
857
  });
980
858
 
981
859
  // ── Test 3 ────────────────────────────────────────────────────────
982
- // BUG: When the provider rejection reveals actual token count (e.g.,
983
- // "242201 tokens > 200000"), the reducer should target a budget below
984
- // the actual limit (not below the estimator's inaccurate budget).
985
- // Currently the reducer always uses `preflightBudget` (190k) as the
986
- // target, but the actual tokens were 242k — so 190k is already too
987
- // high relative to the real count. The target should be adjusted
988
- // downward based on the observed mismatch.
989
- //
990
- // Expected behavior (PR 4 fix): `targetInputTokensOverride` should
991
- // be adjusted based on the ratio between estimated and actual tokens.
992
- // BUG: The targetTokens passed to the reducer is preflightBudget = 190k.
993
- // But when the actual token count is 242k (1.31x the estimate of 185k),
994
- // the target should be adjusted downward to account for the estimation
995
- // inaccuracy. For example: 190k / 1.31 ≈ 145k.
996
- // Planned fix: targetInputTokensOverride should be adjusted based on
997
- // the ratio between estimated and actual tokens.
860
+ // When the provider rejection reveals the actual token count (e.g.,
861
+ // "242201 tokens > 200000"), the overflow reducer's `targetTokens`
862
+ // should be a budget below the actual limit, not below the estimator's
863
+ // inaccurate budget. With a preflightBudget of 190k but an actual count
864
+ // of 242k (1.31x the estimate of 185k), the target is adjusted downward
865
+ // based on the observed mismatch (190k / 1.31 ≈ 145k) so the reducer
866
+ // converges toward the real ceiling rather than the optimistic estimate.
998
867
  test.todo(
999
868
  "forced compaction targets a lower budget when estimation has been inaccurate",
1000
869
  async () => {
1001
870
  const events: ServerMessage[] = [];
1002
- let callCount = 0;
1003
871
  let capturedTargetTokens: number | undefined;
1004
872
 
1005
873
  // Estimator says 185k (below 190k budget = 200k * 0.95)
@@ -1035,52 +903,16 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1035
903
  };
1036
904
  };
1037
905
 
1038
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
1039
- callCount++;
1040
- if (callCount === 1) {
1041
- // Provider rejects: actual tokens 242201, way above estimate of 185k
1042
- onEvent({
1043
- type: "error",
1044
- error: new Error(
1045
- "prompt is too long: 242201 tokens > 200000 maximum",
1046
- ),
1047
- });
1048
- onEvent({
1049
- type: "usage",
1050
- inputTokens: 0,
1051
- outputTokens: 0,
1052
- model: "test-model",
1053
- providerDurationMs: 10,
1054
- });
1055
- // No progress — return same messages
1056
- return messages;
1057
- }
1058
- // Second call succeeds after compaction
1059
- onEvent({
1060
- type: "message_complete",
1061
- message: {
1062
- role: "assistant",
1063
- content: [{ type: "text", text: "recovered" }],
1064
- },
1065
- });
1066
- onEvent({
1067
- type: "usage",
1068
- inputTokens: 80_000,
1069
- outputTokens: 200,
1070
- model: "test-model",
1071
- providerDurationMs: 500,
1072
- });
1073
- return [
1074
- ...messages,
1075
- {
1076
- role: "assistant" as const,
1077
- content: [{ type: "text", text: "recovered" }] as ContentBlock[],
1078
- },
1079
- ];
1080
- };
906
+ // The provider rejects the first call with a context_too_large error
907
+ // (actual tokens 242201, far above the 185k estimate); after forced
908
+ // compaction re-targets a lower budget, the rerun recovers with text.
909
+ const { provider, calls } = createMockProvider([
910
+ new Error("prompt is too long: 242201 tokens > 200000 maximum"),
911
+ textResponse("recovered"),
912
+ ]);
1081
913
 
1082
914
  const ctx = makeCtx({
1083
- agentLoopRun,
915
+ loopProvider: provider,
1084
916
  contextWindowManager: {
1085
917
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1086
918
  maybeCompact: async () => ({ compacted: false }),
@@ -1110,7 +942,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1110
942
  (e) => e.type === "conversation_error",
1111
943
  );
1112
944
  expect(conversationError).toBeUndefined();
1113
- expect(callCount).toBe(2);
945
+ expect(calls.length).toBe(2);
1114
946
  },
1115
947
  );
1116
948
 
@@ -1124,7 +956,6 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1124
956
  async () => {
1125
957
  const events: ServerMessage[] = [];
1126
958
  const longHistory = buildLongConversation(75);
1127
- let callCount = 0;
1128
959
  let reducerCalled = false;
1129
960
 
1130
961
  // Estimator says ~195k — just above budget so preflight reducer runs
@@ -1160,35 +991,14 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1160
991
  };
1161
992
  };
1162
993
 
1163
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
1164
- callCount++;
1165
- onEvent({
1166
- type: "message_complete",
1167
- message: {
1168
- role: "assistant",
1169
- content: [{ type: "text", text: "Here's the analysis..." }],
1170
- },
1171
- });
1172
- onEvent({
1173
- type: "usage",
1174
- inputTokens: 50_000,
1175
- outputTokens: 300,
1176
- model: "test-model",
1177
- providerDurationMs: 800,
1178
- });
1179
- return [
1180
- ...messages,
1181
- {
1182
- role: "assistant" as const,
1183
- content: [
1184
- { type: "text", text: "Here's the analysis..." },
1185
- ] as ContentBlock[],
1186
- },
1187
- ];
1188
- };
994
+ // After the preflight reducer compacts the long history under budget,
995
+ // a single provider call completes the turn with plain text.
996
+ const { provider, calls } = createMockProvider([
997
+ textResponse("Here's the analysis..."),
998
+ ]);
1189
999
 
1190
1000
  const ctx = makeCtx({
1191
- agentLoopRun,
1001
+ loopProvider: provider,
1192
1002
  messages: longHistory,
1193
1003
  contextWindowManager: {
1194
1004
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
@@ -1203,7 +1013,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1203
1013
  // Preflight should trigger the reducer since 195k > 190k budget
1204
1014
  expect(reducerCalled).toBe(true);
1205
1015
  // Should succeed
1206
- expect(callCount).toBe(1);
1016
+ expect(calls.length).toBe(1);
1207
1017
  const conversationError = events.find(
1208
1018
  (e) => e.type === "conversation_error",
1209
1019
  );
@@ -1247,115 +1057,31 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1247
1057
  };
1248
1058
  };
1249
1059
 
1250
- let agentLoopCallCount = 0;
1251
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
1252
- agentLoopCallCount++;
1253
- if (agentLoopCallCount === 1) {
1254
- // Agent makes progress (tool calls succeed, messages grow)
1255
- const progressMessages: Message[] = [
1256
- ...messages,
1257
- {
1258
- role: "assistant" as const,
1259
- content: [
1260
- { type: "text", text: "Running analysis..." },
1261
- {
1262
- type: "tool_use",
1263
- id: "tu-1",
1264
- name: "bash",
1265
- input: { command: "find . -name '*.ts'" },
1266
- },
1267
- ] as ContentBlock[],
1268
- },
1269
- {
1270
- role: "user" as const,
1271
- content: [
1272
- {
1273
- type: "tool_result",
1274
- tool_use_id: "tu-1",
1275
- content: "file1.ts\nfile2.ts\nfile3.ts",
1276
- is_error: false,
1277
- },
1278
- ] as ContentBlock[],
1279
- },
1280
- ];
1060
+ // Run 1 makes progress (a tool turn) then the following provider call
1061
+ // rejects with context_too_large; after emergency compaction the rerun
1062
+ // recovers with plain text.
1063
+ const { provider } = createMockProvider([
1064
+ toolUseResponse("tu-1", "bash", { command: "find . -name '*.ts'" }),
1065
+ new Error("context_length_exceeded"),
1066
+ textResponse("recovered"),
1067
+ ]);
1281
1068
 
1282
- onEvent({
1283
- type: "tool_use",
1284
- id: "tu-1",
1069
+ const ctx = makeCtx({
1070
+ loopProvider: provider,
1071
+ loopTools: [
1072
+ {
1285
1073
  name: "bash",
1286
- input: { command: "find . -name '*.ts'" },
1287
- });
1288
- onEvent({
1289
- type: "tool_result",
1290
- toolUseId: "tu-1",
1291
- content: "file1.ts\nfile2.ts\nfile3.ts",
1292
- isError: false,
1293
- });
1294
- onEvent({
1295
- type: "message_complete",
1296
- message: {
1297
- role: "assistant",
1298
- content: [
1299
- { type: "text", text: "Running analysis..." },
1300
- {
1301
- type: "tool_use",
1302
- id: "tu-1",
1303
- name: "bash",
1304
- input: { command: "find . -name '*.ts'" },
1305
- },
1306
- ],
1074
+ description: "Run a shell command",
1075
+ input_schema: {
1076
+ type: "object",
1077
+ properties: { command: { type: "string" } },
1307
1078
  },
1308
- });
1309
- onEvent({
1310
- type: "usage",
1311
- inputTokens: 190_000,
1312
- outputTokens: 100,
1313
- model: "test-model",
1314
- providerDurationMs: 200,
1315
- });
1316
-
1317
- // Then context_too_large on the next LLM call within the loop
1318
- onEvent({
1319
- type: "error",
1320
- error: new Error("context_length_exceeded"),
1321
- });
1322
- onEvent({
1323
- type: "usage",
1324
- inputTokens: 0,
1325
- outputTokens: 0,
1326
- model: "test-model",
1327
- providerDurationMs: 10,
1328
- });
1329
-
1330
- return progressMessages;
1331
- }
1332
-
1333
- // After emergency compaction, succeed
1334
- onEvent({
1335
- type: "message_complete",
1336
- message: {
1337
- role: "assistant",
1338
- content: [{ type: "text", text: "recovered" }],
1339
1079
  },
1340
- });
1341
- onEvent({
1342
- type: "usage",
1343
- inputTokens: 50_000,
1344
- outputTokens: 100,
1345
- model: "test-model",
1346
- providerDurationMs: 200,
1347
- });
1348
- return [
1349
- ...messages,
1350
- {
1351
- role: "assistant" as const,
1352
- content: [{ type: "text", text: "recovered" }] as ContentBlock[],
1353
- },
1354
- ];
1355
- };
1356
-
1357
- const ctx = makeCtx({
1358
- agentLoopRun,
1080
+ ],
1081
+ toolExecutor: async () => ({
1082
+ content: "file1.ts\nfile2.ts\nfile3.ts",
1083
+ isError: false,
1084
+ }),
1359
1085
  contextWindowManager: {
1360
1086
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1361
1087
  maybeCompact: async (
@@ -1432,114 +1158,30 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1432
1158
  return 170_000;
1433
1159
  };
1434
1160
 
1435
- let agentLoopCallCount = 0;
1436
- const agentLoopRun: AgentLoopRun = async (
1437
- messages,
1438
- onEvent,
1439
- _signal,
1440
- _requestId,
1441
- onCheckpoint,
1442
- ) => {
1443
- agentLoopCallCount++;
1444
-
1445
- if (agentLoopCallCount === 1) {
1446
- // Simulate a tool round: assistant calls a tool, results come back
1447
- const withProgress: Message[] = [
1448
- ...messages,
1449
- {
1450
- role: "assistant" as const,
1451
- content: [
1452
- { type: "text", text: "Let me check." },
1453
- {
1454
- type: "tool_use",
1455
- id: "tu-1",
1456
- name: "bash",
1457
- input: { command: "ls" },
1458
- },
1459
- ] as ContentBlock[],
1460
- },
1461
- {
1462
- role: "user" as const,
1463
- content: [
1464
- {
1465
- type: "tool_result",
1466
- tool_use_id: "tu-1",
1467
- content: "file1.ts\nfile2.ts",
1468
- is_error: false,
1469
- },
1470
- ] as ContentBlock[],
1471
- },
1472
- ];
1473
-
1474
- onEvent({
1475
- type: "message_complete",
1476
- message: {
1477
- role: "assistant",
1478
- content: [
1479
- { type: "text", text: "Let me check." },
1480
- {
1481
- type: "tool_use",
1482
- id: "tu-1",
1483
- name: "bash",
1484
- input: { command: "ls" },
1485
- },
1486
- ],
1487
- },
1488
- });
1489
- onEvent({
1490
- type: "usage",
1491
- inputTokens: 100,
1492
- outputTokens: 50,
1493
- model: "test-model",
1494
- providerDurationMs: 100,
1495
- });
1496
-
1497
- // Call onCheckpoint — this should trigger the mid-loop budget check
1498
- // which sees 170_000 > 161_500 and returns "yield"
1499
- if (onCheckpoint) {
1500
- const decision = await onCheckpoint({
1501
- turnIndex: 0,
1502
- toolCount: 1,
1503
- hasToolUse: true,
1504
- history: withProgress,
1505
- });
1506
- if (decision === "yield") {
1507
- // Agent loop stops when checkpoint yields
1508
- return withProgress;
1509
- }
1510
- }
1511
-
1512
- return withProgress;
1513
- }
1161
+ // A tool round trips the mid-loop budget gate (170k > 161_500); the
1162
+ // gate compacts in place (productive) and the loop continues, so the
1163
+ // post-compaction provider call completes the turn with plain text.
1164
+ const { provider, calls } = createMockProvider([
1165
+ toolUseResponse("tu-1", "bash", { command: "ls" }),
1166
+ textResponse("done after compaction"),
1167
+ ]);
1514
1168
 
1515
- // Second call (after compaction): complete successfully
1516
- onEvent({
1517
- type: "message_complete",
1518
- message: {
1519
- role: "assistant",
1520
- content: [{ type: "text", text: "done after compaction" }],
1521
- },
1522
- });
1523
- onEvent({
1524
- type: "usage",
1525
- inputTokens: 50,
1526
- outputTokens: 25,
1527
- model: "test-model",
1528
- providerDurationMs: 100,
1529
- });
1530
- return [
1531
- ...messages,
1169
+ const ctx = makeCtx({
1170
+ loopProvider: provider,
1171
+ loopTools: [
1532
1172
  {
1533
- role: "assistant" as const,
1534
- content: [
1535
- { type: "text", text: "done after compaction" },
1536
- ] as ContentBlock[],
1173
+ name: "bash",
1174
+ description: "Run a shell command",
1175
+ input_schema: {
1176
+ type: "object",
1177
+ properties: { command: { type: "string" } },
1178
+ },
1537
1179
  },
1538
- ];
1539
- };
1540
-
1541
- const ctx = makeCtx({
1542
- agentLoopRun,
1180
+ ],
1181
+ toolExecutor: async () => ({
1182
+ content: "file1.ts\nfile2.ts",
1183
+ isError: false,
1184
+ }),
1543
1185
  contextWindowManager: {
1544
1186
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1545
1187
  maybeCompact: async () => {
@@ -1573,8 +1215,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1573
1215
  // The mid-loop budget check should have triggered compaction
1574
1216
  expect(compactionCalled).toBe(true);
1575
1217
 
1576
- // Agent loop should have been called twice: once before yield, once after compaction
1577
- expect(agentLoopCallCount).toBe(2);
1218
+ // Provider called twice: the tool turn that tripped the gate, then the
1219
+ // post-compaction turn that completed the run.
1220
+ expect(calls.length).toBe(2);
1578
1221
 
1579
1222
  // No conversation_error should be emitted
1580
1223
  const conversationError = events.find(
@@ -1615,107 +1258,36 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1615
1258
  return 175_000;
1616
1259
  };
1617
1260
 
1618
- let agentLoopCallCount = 0;
1619
1261
  let contextTooLargeEmitted = false;
1620
1262
 
1621
- const agentLoopRun: AgentLoopRun = async (
1622
- messages,
1623
- onEvent,
1624
- _signal,
1625
- _requestId,
1626
- onCheckpoint,
1627
- ) => {
1628
- agentLoopCallCount++;
1629
-
1630
- if (agentLoopCallCount === 1) {
1631
- const currentHistory = [...messages];
1632
-
1633
- // Simulate 5 tool rounds — but the checkpoint should yield at round 3
1634
- for (let i = 0; i < 5; i++) {
1635
- const toolId = `tu-${i}`;
1636
- const assistantMsg: Message = {
1637
- role: "assistant" as const,
1638
- content: [
1639
- { type: "text", text: `Step ${i}` },
1640
- {
1641
- type: "tool_use",
1642
- id: toolId,
1643
- name: "bash",
1644
- input: { command: `cmd-${i}` },
1645
- },
1646
- ] as ContentBlock[],
1647
- };
1648
- const resultMsg: Message = {
1649
- role: "user" as const,
1650
- content: [
1651
- {
1652
- type: "tool_result",
1653
- tool_use_id: toolId,
1654
- content: "x".repeat(10_000),
1655
- is_error: false,
1656
- },
1657
- ] as ContentBlock[],
1658
- };
1659
- currentHistory.push(assistantMsg, resultMsg);
1660
-
1661
- onEvent({
1662
- type: "message_complete",
1663
- message: assistantMsg,
1664
- });
1665
- onEvent({
1666
- type: "usage",
1667
- inputTokens: 50_000 + i * 20_000,
1668
- outputTokens: 50,
1669
- model: "test-model",
1670
- providerDurationMs: 100,
1671
- });
1672
-
1673
- if (onCheckpoint) {
1674
- const decision = await onCheckpoint({
1675
- turnIndex: i,
1676
- toolCount: 1,
1677
- hasToolUse: true,
1678
- history: currentHistory,
1679
- });
1680
- if (decision === "yield") {
1681
- return currentHistory;
1682
- }
1683
- }
1684
- }
1685
-
1686
- return currentHistory;
1687
- }
1263
+ // Each tool round produces a large result; the estimate grows with each
1264
+ // checkpoint until tool round 3 trips the mid-loop gate (175k > 161_500).
1265
+ // Compaction runs in place (productive) and the loop continues, so the
1266
+ // following plain-text provider call completes the turn. The provider
1267
+ // never rejects with context_too_large.
1268
+ const { provider, calls } = createMockProvider([
1269
+ toolUseResponse("tu-0", "bash", { command: "cmd-0" }),
1270
+ toolUseResponse("tu-1", "bash", { command: "cmd-1" }),
1271
+ toolUseResponse("tu-2", "bash", { command: "cmd-2" }),
1272
+ textResponse("completed after mid-loop compaction"),
1273
+ ]);
1688
1274
 
1689
- // Second call (after compaction): complete
1690
- onEvent({
1691
- type: "message_complete",
1692
- message: {
1693
- role: "assistant",
1694
- content: [
1695
- { type: "text", text: "completed after mid-loop compaction" },
1696
- ],
1697
- },
1698
- });
1699
- onEvent({
1700
- type: "usage",
1701
- inputTokens: 60_000,
1702
- outputTokens: 100,
1703
- model: "test-model",
1704
- providerDurationMs: 200,
1705
- });
1706
- return [
1707
- ...messages,
1275
+ const ctx = makeCtx({
1276
+ loopProvider: provider,
1277
+ loopTools: [
1708
1278
  {
1709
- role: "assistant" as const,
1710
- content: [
1711
- { type: "text", text: "completed after mid-loop compaction" },
1712
- ] as ContentBlock[],
1279
+ name: "bash",
1280
+ description: "Run a shell command",
1281
+ input_schema: {
1282
+ type: "object",
1283
+ properties: { command: { type: "string" } },
1284
+ },
1713
1285
  },
1714
- ];
1715
- };
1716
-
1717
- const ctx = makeCtx({
1718
- agentLoopRun,
1286
+ ],
1287
+ toolExecutor: async () => ({
1288
+ content: "x".repeat(10_000),
1289
+ isError: false,
1290
+ }),
1719
1291
  contextWindowManager: {
1720
1292
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1721
1293
  maybeCompact: async () => {
@@ -1762,8 +1334,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1762
1334
  // The provider should NEVER have rejected with context_too_large
1763
1335
  expect(contextTooLargeEmitted).toBe(false);
1764
1336
 
1765
- // Agent loop called twice: once (yielded at tool 3), once after compaction
1766
- expect(agentLoopCallCount).toBe(2);
1337
+ // Provider called four times: three tool rounds (the third trips the
1338
+ // mid-loop gate) plus the post-compaction text turn that completes.
1339
+ expect(calls.length).toBe(4);
1767
1340
 
1768
1341
  // No conversation_error
1769
1342
  const conversationError = events.find(
@@ -1792,85 +1365,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1792
1365
  return 170_000;
1793
1366
  };
1794
1367
 
1795
- let agentLoopCallCount = 0;
1796
- const agentLoopRun: AgentLoopRun = async (
1797
- messages,
1798
- onEvent,
1799
- _signal,
1800
- _requestId,
1801
- onCheckpoint,
1802
- ) => {
1803
- agentLoopCallCount++;
1804
-
1805
- // Every call: simulate tool progress then yield at checkpoint
1806
- const withProgress: Message[] = [
1807
- ...messages,
1808
- {
1809
- role: "assistant" as const,
1810
- content: [
1811
- { type: "text", text: `Tool call ${agentLoopCallCount}` },
1812
- {
1813
- type: "tool_use",
1814
- id: `tu-${agentLoopCallCount}`,
1815
- name: "bash",
1816
- input: { command: "ls" },
1817
- },
1818
- ] as ContentBlock[],
1819
- },
1820
- {
1821
- role: "user" as const,
1822
- content: [
1823
- {
1824
- type: "tool_result",
1825
- tool_use_id: `tu-${agentLoopCallCount}`,
1826
- content: "output",
1827
- is_error: false,
1828
- },
1829
- ] as ContentBlock[],
1830
- },
1831
- ];
1832
-
1833
- onEvent({
1834
- type: "message_complete",
1835
- message: {
1836
- role: "assistant",
1837
- content: [
1838
- { type: "text", text: `Tool call ${agentLoopCallCount}` },
1839
- {
1840
- type: "tool_use",
1841
- id: `tu-${agentLoopCallCount}`,
1842
- name: "bash",
1843
- input: { command: "ls" },
1844
- },
1845
- ],
1846
- },
1847
- });
1848
- onEvent({
1849
- type: "usage",
1850
- inputTokens: 100,
1851
- outputTokens: 50,
1852
- model: "test-model",
1853
- providerDurationMs: 100,
1854
- });
1855
-
1856
- // Always yield at checkpoint — simulates compaction not helping
1857
- if (onCheckpoint) {
1858
- const decision = await onCheckpoint({
1859
- turnIndex: 0,
1860
- toolCount: 1,
1861
- hasToolUse: true,
1862
- history: withProgress,
1863
- });
1864
- if (decision === "yield") {
1865
- return withProgress;
1866
- }
1867
- }
1868
-
1869
- return withProgress;
1870
- };
1871
-
1872
- let compactionCallCount = 0;
1873
- // Convergence reducer: reduce tokens enough to succeed
1368
+ // The convergence reducer reduces tokens enough for the rerun to recover.
1874
1369
  let convergenceReducerCalled = false;
1875
1370
  mockReducerStepFn = (msgs: Message[]) => {
1876
1371
  convergenceReducerCalled = true;
@@ -1886,15 +1381,43 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1886
1381
  };
1887
1382
  };
1888
1383
 
1384
+ // Every provider call returns a tool_use, so each loop run does a tool
1385
+ // turn that trips the mid-loop budget gate. On the initial run the gate
1386
+ // calls compaction (which surfaces `exhausted: true`); the convergence
1387
+ // rerun runs without a compaction hook and yields "budget" directly.
1388
+ // With the reducer exhausted, the convergence loop terminates with the
1389
+ // turn still over budget and the orchestrator stamps `context_too_large`.
1390
+ const { provider, calls } = createMockProvider([
1391
+ toolUseResponse("tu-1", "bash", { command: "ls" }),
1392
+ ]);
1393
+
1394
+ let compactionCallCount = 0;
1889
1395
  const ctx = makeCtx({
1890
- agentLoopRun,
1396
+ loopProvider: provider,
1397
+ loopTools: [
1398
+ {
1399
+ name: "bash",
1400
+ description: "Run a shell command",
1401
+ input_schema: {
1402
+ type: "object",
1403
+ properties: { command: { type: "string" } },
1404
+ },
1405
+ },
1406
+ ],
1407
+ toolExecutor: async () => ({ content: "output", isError: false }),
1891
1408
  contextWindowManager: {
1892
1409
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1893
1410
  maybeCompact: async () => {
1894
1411
  compactionCallCount++;
1895
- // Compaction "succeeds" but doesn't actually shrink enough
1412
+ // Compaction's internal retry budget is exhausted — the
1413
+ // compactor itself ran maxAttempts passes and still couldn't
1414
+ // drop below the auto-threshold. `maybeCompact` surfaces this
1415
+ // via `exhausted: true` so the loop yields "budget" and the
1416
+ // orchestrator escalates straight to the convergence loop
1417
+ // instead of looping on a stuck compactor.
1896
1418
  return {
1897
1419
  compacted: true,
1420
+ exhausted: true,
1898
1421
  messages: [
1899
1422
  {
1900
1423
  role: "user" as const,
@@ -1919,14 +1442,20 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1919
1442
 
1920
1443
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
1921
1444
 
1922
- // 1 initial auto-compact + 3 mid-loop compaction attempts = 4 total
1923
- expect(compactionCallCount).toBe(4);
1445
+ // 1 initial auto-compact + 1 mid-loop compaction = 2 total. The
1446
+ // first mid-loop call surfaces `exhausted: true`, so the
1447
+ // orchestrator escalates immediately without retrying maybeCompact
1448
+ // — the retry budget for the compactor itself lives inside
1449
+ // `ContextWindowManager.maybeCompact`.
1450
+ expect(compactionCallCount).toBe(2);
1924
1451
 
1925
- // Agent loop: 1 initial + 3 mid-loop re-entries + 1 convergence re-run = 5 calls
1926
- expect(agentLoopCallCount).toBe(5);
1452
+ // Provider calls: 1 initial tool turn (yields budget) + 1 convergence
1453
+ // rerun that recovers. No mid-loop re-entries because the orchestrator
1454
+ // broke out on `exhausted` before re-invoking the loop.
1455
+ expect(calls.length).toBe(2);
1927
1456
 
1928
- // After exhausting mid-loop attempts, the convergence loop should
1929
- // have been triggered (contextTooLargeDetected set to true)
1457
+ // After the compactor exhausted itself, the convergence loop
1458
+ // should have been triggered (contextTooLargeDetected set to true)
1930
1459
  expect(convergenceReducerCalled).toBe(true);
1931
1460
  expect(setAgentLoopExitReasonOnLatestLogMock).toHaveBeenCalledWith(
1932
1461
  "test-conv",
@@ -1934,6 +1463,102 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1934
1463
  );
1935
1464
  });
1936
1465
 
1466
+ // ── Test 8b ───────────────────────────────────────────────────────
1467
+ // Counterpart to Test 8: when a mid-loop `maybeCompact` returns
1468
+ // productive (`compacted: true`, no `exhausted` flag), the loop
1469
+ // compacts in place and continues the run itself — it never yields
1470
+ // "budget", so the orchestrator does not escalate to the convergence
1471
+ // loop. Mid-loop iteration is now wholly internal to `AgentLoop.run`;
1472
+ // the orchestrator only reacts to the binary `exhausted`/timeout
1473
+ // signal carried back as a "budget" exit.
1474
+ test("productive mid-loop compaction continues in place without escalating", async () => {
1475
+ const events: ServerMessage[] = [];
1476
+
1477
+ // Budget = 200_000 * 0.95 = 190_000
1478
+ // Mid-loop threshold = 190_000 * 0.85 = 161_500
1479
+ let estimateCallCount = 0;
1480
+ mockEstimateTokens = () => {
1481
+ estimateCallCount++;
1482
+ // Preflight: below budget.
1483
+ if (estimateCallCount === 1) return 100_000;
1484
+ // Every checkpoint estimate: above threshold — always trips the
1485
+ // yield. Simulates a long turn where each tool call's result
1486
+ // inflates the context past 85% even after a successful compaction.
1487
+ return 170_000;
1488
+ };
1489
+
1490
+ // A single tool round reaches one checkpoint; the in-loop budget gate
1491
+ // trips there and compaction runs in place. The loop continues the run
1492
+ // itself — the following provider call returns plain text and the turn
1493
+ // completes — so the orchestrator never re-enters the convergence loop.
1494
+ const { provider, calls } = createMockProvider([
1495
+ toolUseResponse("tu-1", "bash", { command: "ls" }),
1496
+ textResponse("final answer"),
1497
+ ]);
1498
+
1499
+ // Compaction reports `estimatedInputTokens` well below the 161_500
1500
+ // threshold — the "compaction is productive" signal (no `exhausted`
1501
+ // flag) that lets the loop continue in place.
1502
+ let compactionCallCount = 0;
1503
+ const ctx = makeCtx({
1504
+ loopProvider: provider,
1505
+ loopTools: [
1506
+ {
1507
+ name: "bash",
1508
+ description: "Run a shell command",
1509
+ input_schema: {
1510
+ type: "object",
1511
+ properties: { command: { type: "string" } },
1512
+ },
1513
+ },
1514
+ ],
1515
+ toolExecutor: async () => ({ content: "output", isError: false }),
1516
+ contextWindowManager: {
1517
+ shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1518
+ maybeCompact: async () => {
1519
+ compactionCallCount++;
1520
+ return {
1521
+ compacted: true,
1522
+ messages: [
1523
+ {
1524
+ role: "user" as const,
1525
+ content: [{ type: "text", text: "Hello" }],
1526
+ },
1527
+ ] as Message[],
1528
+ compactedPersistedMessages: 5,
1529
+ summaryText: "Compaction summary",
1530
+ previousEstimatedInputTokens: 170_000,
1531
+ estimatedInputTokens: 100_000,
1532
+ maxInputTokens: 200_000,
1533
+ thresholdTokens: 160_000,
1534
+ compactedMessages: 10,
1535
+ summaryCalls: 1,
1536
+ summaryInputTokens: 500,
1537
+ summaryOutputTokens: 200,
1538
+ summaryModel: "mock-model",
1539
+ };
1540
+ },
1541
+ } as unknown as AgentLoopConversationContext["contextWindowManager"],
1542
+ });
1543
+
1544
+ await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
1545
+
1546
+ // 1 initial auto-compact + 1 productive mid-loop compaction.
1547
+ expect(compactionCallCount).toBe(2);
1548
+ // The loop continued in place after compacting: a tool turn followed by
1549
+ // the post-compaction text turn, both within a single run.
1550
+ expect(calls.length).toBe(2);
1551
+
1552
+ // No escalation to the convergence loop because the mid-loop
1553
+ // `maybeCompact` returned productive (no `exhausted` flag), and the turn
1554
+ // completed normally.
1555
+ expect(setAgentLoopExitReasonOnLatestLogMock).not.toHaveBeenCalledWith(
1556
+ "test-conv",
1557
+ "context_too_large",
1558
+ );
1559
+ expect(events.find((e) => e.type === "conversation_error")).toBeUndefined();
1560
+ });
1561
+
1937
1562
  // ── Test 9 ────────────────────────────────────────────────────────
1938
1563
  // When the convergence loop reruns the agent loop and it still yields
1939
1564
  // at checkpoint (yieldedForBudget), the loop must continue reducing
@@ -1953,81 +1578,13 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
1953
1578
  return 170_000;
1954
1579
  };
1955
1580
 
1956
- let agentLoopCallCount = 0;
1957
- const agentLoopRun: AgentLoopRun = async (
1958
- messages,
1959
- onEvent,
1960
- _signal,
1961
- _requestId,
1962
- onCheckpoint,
1963
- ) => {
1964
- agentLoopCallCount++;
1965
-
1966
- const withProgress: Message[] = [
1967
- ...messages,
1968
- {
1969
- role: "assistant" as const,
1970
- content: [
1971
- { type: "text", text: `Tool call ${agentLoopCallCount}` },
1972
- {
1973
- type: "tool_use",
1974
- id: `tu-${agentLoopCallCount}`,
1975
- name: "bash",
1976
- input: { command: "ls" },
1977
- },
1978
- ] as ContentBlock[],
1979
- },
1980
- {
1981
- role: "user" as const,
1982
- content: [
1983
- {
1984
- type: "tool_result",
1985
- tool_use_id: `tu-${agentLoopCallCount}`,
1986
- content: "output",
1987
- is_error: false,
1988
- },
1989
- ] as ContentBlock[],
1990
- },
1991
- ];
1992
-
1993
- onEvent({
1994
- type: "message_complete",
1995
- message: {
1996
- role: "assistant",
1997
- content: [
1998
- { type: "text", text: `Tool call ${agentLoopCallCount}` },
1999
- {
2000
- type: "tool_use",
2001
- id: `tu-${agentLoopCallCount}`,
2002
- name: "bash",
2003
- input: { command: "ls" },
2004
- },
2005
- ],
2006
- },
2007
- });
2008
- onEvent({
2009
- type: "usage",
2010
- inputTokens: 100,
2011
- outputTokens: 50,
2012
- model: "test-model",
2013
- providerDurationMs: 100,
2014
- });
2015
-
2016
- // Always yield at checkpoint — simulates reduction not helping enough
2017
- if (onCheckpoint) {
2018
- const decision = await onCheckpoint({
2019
- turnIndex: 0,
2020
- toolCount: 1,
2021
- hasToolUse: true,
2022
- history: withProgress,
2023
- });
2024
- if (decision === "yield") {
2025
- return withProgress;
2026
- }
2027
- }
2028
-
2029
- return withProgress;
2030
- };
1581
+ // Every provider call returns a tool_use, so each loop run does a tool
1582
+ // turn that trips the mid-loop budget gate and yields "budget". The
1583
+ // initial run's gate calls compaction (exhausted); the convergence
1584
+ // reruns run without a compaction hook and yield directly.
1585
+ const { provider, calls } = createMockProvider([
1586
+ toolUseResponse("tu-1", "bash", { command: "ls" }),
1587
+ ]);
2031
1588
 
2032
1589
  // Convergence reducer: first call returns non-exhausted, second returns exhausted
2033
1590
  let reducerCallCount = 0;
@@ -2059,9 +1616,25 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
2059
1616
  };
2060
1617
 
2061
1618
  const ctx = makeCtx({
2062
- agentLoopRun,
1619
+ loopProvider: provider,
1620
+ loopTools: [
1621
+ {
1622
+ name: "bash",
1623
+ description: "Run a shell command",
1624
+ input_schema: {
1625
+ type: "object",
1626
+ properties: { command: { type: "string" } },
1627
+ },
1628
+ },
1629
+ ],
1630
+ toolExecutor: async () => ({ content: "output", isError: false }),
2063
1631
  contextWindowManager: {
2064
1632
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
1633
+ // Under the new architecture (Compaction Re-homing Arc, Bullet 1)
1634
+ // the retry budget lives inside `ContextWindowManager._maybeCompact`,
1635
+ // so a single daemon-level call represents the full manager retry
1636
+ // sequence. Signal `exhausted: true` immediately to escalate the
1637
+ // mid-loop to the convergence reducer.
2065
1638
  maybeCompact: async () => ({
2066
1639
  compacted: true,
2067
1640
  messages: [
@@ -2081,6 +1654,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
2081
1654
  summaryInputTokens: 500,
2082
1655
  summaryOutputTokens: 200,
2083
1656
  summaryModel: "mock-model",
1657
+ exhausted: true,
2084
1658
  }),
2085
1659
  } as unknown as AgentLoopConversationContext["contextWindowManager"],
2086
1660
  });
@@ -2091,8 +1665,11 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
2091
1665
  // once more after yieldedForBudget triggered re-entry
2092
1666
  expect(reducerCallCount).toBe(2);
2093
1667
 
2094
- // Agent loop: 1 initial + 3 mid-loop re-entries + 2 convergence re-runs = 6 calls
2095
- expect(agentLoopCallCount).toBe(6);
1668
+ // Provider calls: 1 initial run + 2 convergence reruns = 3 calls, each a
1669
+ // tool turn that yields "budget". The mid-loop no longer drives
1670
+ // daemon-level retries — the manager owns its retry budget and signals
1671
+ // exhaustion via the `exhausted` flag.
1672
+ expect(calls.length).toBe(3);
2096
1673
  expect(setAgentLoopExitReasonOnLatestLogMock).toHaveBeenCalledWith(
2097
1674
  "test-conv",
2098
1675
  "context_too_large",
@@ -2192,32 +1769,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
2192
1769
  };
2193
1770
  };
2194
1771
 
2195
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
2196
- onEvent({
2197
- type: "message_complete",
2198
- message: {
2199
- role: "assistant",
2200
- content: [{ type: "text", text: "done" }],
2201
- },
2202
- });
2203
- onEvent({
2204
- type: "usage",
2205
- inputTokens: 170_000,
2206
- outputTokens: 200,
2207
- model: "test-model",
2208
- providerDurationMs: 500,
2209
- });
2210
- return [
2211
- ...messages,
2212
- {
2213
- role: "assistant" as const,
2214
- content: [{ type: "text", text: "done" }] as ContentBlock[],
2215
- },
2216
- ];
2217
- };
2218
-
1772
+ // The preflight overflow reducer runs in the orchestrator before the loop,
1773
+ // so a single successful provider turn is enough to drive the path.
2219
1774
  const ctx = makeCtx({
2220
- agentLoopRun,
1775
+ providerResponses: [textResponse("done")],
2221
1776
  contextWindowManager: {
2222
1777
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
2223
1778
  maybeCompact: async () => ({ compacted: false }),
@@ -2288,108 +1843,100 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
2288
1843
  // emergency compaction + final agentLoop.run path executes.
2289
1844
  mockOverflowAction = "auto_compress_latest_turn";
2290
1845
 
2291
- let agentLoopCallCount = 0;
2292
- const agentLoopRun: AgentLoopRun = async (
2293
- messages,
2294
- onEvent,
2295
- _signal,
2296
- _requestId,
2297
- onCheckpoint,
2298
- ) => {
2299
- agentLoopCallCount++;
2300
-
2301
- const withProgress: Message[] = [
2302
- ...messages,
2303
- {
2304
- role: "assistant" as const,
2305
- content: [
2306
- { type: "text", text: `tool call ${agentLoopCallCount}` },
2307
- {
2308
- type: "tool_use",
2309
- id: `tu-${agentLoopCallCount}`,
2310
- name: "bash",
2311
- input: { command: "ls" },
2312
- },
2313
- ] as ContentBlock[],
2314
- },
2315
- {
2316
- role: "user" as const,
2317
- content: [
2318
- {
2319
- type: "tool_result",
2320
- tool_use_id: `tu-${agentLoopCallCount}`,
2321
- content: "output",
2322
- is_error: false,
2323
- },
2324
- ] as ContentBlock[],
2325
- },
2326
- ];
2327
-
2328
- onEvent({
2329
- type: "message_complete",
2330
- message: {
2331
- role: "assistant",
2332
- content: [
2333
- { type: "text", text: `tool call ${agentLoopCallCount}` },
2334
- {
2335
- type: "tool_use",
2336
- id: `tu-${agentLoopCallCount}`,
2337
- name: "bash",
2338
- input: { command: "ls" },
2339
- },
2340
- ],
2341
- },
2342
- });
2343
- onEvent({
2344
- type: "usage",
2345
- inputTokens: 100,
2346
- outputTokens: 50,
2347
- model: "test-model",
2348
- providerDurationMs: 100,
2349
- });
2350
-
2351
- // Every checkpoint yields — including the final auto_compress rerun.
2352
- if (onCheckpoint) {
2353
- const decision = await onCheckpoint({
2354
- turnIndex: 0,
2355
- toolCount: 1,
2356
- hasToolUse: true,
2357
- history: withProgress,
2358
- });
2359
- if (decision === "yield") {
2360
- return withProgress;
2361
- }
2362
- }
2363
-
2364
- return withProgress;
2365
- };
1846
+ // Every provider call returns a tool_use, so each loop run does a tool
1847
+ // turn that trips the mid-loop budget gate and yields "budget" —
1848
+ // including the final auto_compress rerun.
1849
+ const { provider } = createMockProvider([
1850
+ toolUseResponse("tu-1", "bash", { command: "ls" }),
1851
+ ]);
2366
1852
 
1853
+ // `maybeCompact` is invoked through three distinct call sites:
1854
+ // 1. Start-of-turn compaction (no `force` option) — return a no-op
1855
+ // so the start-of-turn pass doesn't perturb state. The mock's
1856
+ // `shouldCompact` already returns `needed: false`, but the
1857
+ // orchestrator still invokes the compaction pipeline.
1858
+ // 2. Mid-loop after the initial agent-loop yield (`force: true`) —
1859
+ // must signal `exhausted: true` so the daemon escalates to the
1860
+ // convergence reducer instead of looping forever.
1861
+ // 3. auto_compress_latest_turn emergency compaction (`force: true`,
1862
+ // `minKeepRecentUserTurns: 0`) — succeeds and drops tokens below
1863
+ // threshold; the subsequent rerun yields again and is classified
1864
+ // as BUDGET_YIELD_UNRECOVERED.
1865
+ let forcedMaybeCompactCallCount = 0;
2367
1866
  const ctx = makeCtx({
2368
- agentLoopRun,
1867
+ loopProvider: provider,
1868
+ loopTools: [
1869
+ {
1870
+ name: "bash",
1871
+ description: "Run a shell command",
1872
+ input_schema: {
1873
+ type: "object",
1874
+ properties: { command: { type: "string" } },
1875
+ },
1876
+ },
1877
+ ],
1878
+ toolExecutor: async () => ({ content: "output", isError: false }),
2369
1879
  contextWindowManager: {
2370
1880
  shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
2371
- // The compaction pipeline (default terminal) routes through this
2372
- // for the emergency `auto_compress_latest_turn` path.
2373
- maybeCompact: async () => ({
2374
- compacted: true,
2375
- messages: [
2376
- {
2377
- role: "user" as const,
2378
- content: [{ type: "text", text: "compacted" }],
2379
- },
2380
- ] as Message[],
2381
- compactedPersistedMessages: 5,
2382
- summaryText: "Emergency summary",
2383
- previousEstimatedInputTokens: 170_000,
2384
- estimatedInputTokens: 90_000,
2385
- maxInputTokens: 200_000,
2386
- thresholdTokens: 160_000,
2387
- compactedMessages: 10,
2388
- summaryCalls: 1,
2389
- summaryInputTokens: 500,
2390
- summaryOutputTokens: 200,
2391
- summaryModel: "mock-model",
2392
- }),
1881
+ maybeCompact: async (
1882
+ _msgs: Message[],
1883
+ _signal: AbortSignal,
1884
+ opts?: { force?: boolean },
1885
+ ) => {
1886
+ // Start-of-turn calls pass no `force` option; route them to a
1887
+ // no-op so only the mid-loop and emergency paths drive the test.
1888
+ if (!opts?.force) {
1889
+ return { compacted: false };
1890
+ }
1891
+ forcedMaybeCompactCallCount++;
1892
+ if (forcedMaybeCompactCallCount === 1) {
1893
+ // Mid-loop call — under the new architecture (Compaction
1894
+ // Re-homing Arc, Bullet 1) the manager owns its own retry
1895
+ // budget; signal exhaustion to escalate to convergence.
1896
+ return {
1897
+ compacted: true,
1898
+ messages: [
1899
+ {
1900
+ role: "user" as const,
1901
+ content: [{ type: "text", text: "mid-loop compacted" }],
1902
+ },
1903
+ ] as Message[],
1904
+ compactedPersistedMessages: 5,
1905
+ summaryText: "Mid-loop summary",
1906
+ previousEstimatedInputTokens: 170_000,
1907
+ estimatedInputTokens: 165_000,
1908
+ maxInputTokens: 200_000,
1909
+ thresholdTokens: 160_000,
1910
+ compactedMessages: 10,
1911
+ summaryCalls: 1,
1912
+ summaryInputTokens: 500,
1913
+ summaryOutputTokens: 200,
1914
+ summaryModel: "mock-model",
1915
+ exhausted: true,
1916
+ };
1917
+ }
1918
+ // Emergency compaction call from auto_compress_latest_turn.
1919
+ return {
1920
+ compacted: true,
1921
+ messages: [
1922
+ {
1923
+ role: "user" as const,
1924
+ content: [{ type: "text", text: "compacted" }],
1925
+ },
1926
+ ] as Message[],
1927
+ compactedPersistedMessages: 5,
1928
+ summaryText: "Emergency summary",
1929
+ previousEstimatedInputTokens: 170_000,
1930
+ estimatedInputTokens: 90_000,
1931
+ maxInputTokens: 200_000,
1932
+ thresholdTokens: 160_000,
1933
+ compactedMessages: 10,
1934
+ summaryCalls: 1,
1935
+ summaryInputTokens: 500,
1936
+ summaryOutputTokens: 200,
1937
+ summaryModel: "mock-model",
1938
+ };
1939
+ },
2393
1940
  } as unknown as AgentLoopConversationContext["contextWindowManager"],
2394
1941
  });
2395
1942