@vellumai/assistant 0.8.6 → 0.8.7

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 (891) hide show
  1. package/AGENTS.md +4 -4
  2. package/Dockerfile +1 -0
  3. package/bun.lock +11 -2
  4. package/docker-entrypoint.sh +8 -6
  5. package/docs/plugins.md +63 -28
  6. package/examples/plugins/echo/register.ts +4 -7
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/environments/bun.lock +24 -0
  9. package/node_modules/@vellumai/environments/package.json +18 -0
  10. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +95 -0
  11. package/node_modules/@vellumai/environments/src/index.ts +11 -0
  12. package/node_modules/@vellumai/environments/src/seeds.ts +73 -0
  13. package/node_modules/@vellumai/environments/src/types.ts +70 -0
  14. package/node_modules/@vellumai/environments/tsconfig.json +20 -0
  15. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +11 -0
  16. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +3 -4
  17. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -2
  18. package/openapi.yaml +3735 -353
  19. package/package.json +7 -3
  20. package/scripts/generate-openapi.ts +20 -13
  21. package/src/__tests__/agent-loop-callsite-precedence.test.ts +42 -80
  22. package/src/__tests__/agent-loop-exit-reason.test.ts +240 -39
  23. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +141 -0
  24. package/src/__tests__/agent-loop-override-profile.test.ts +19 -32
  25. package/src/__tests__/agent-loop-provider-error-recording.test.ts +6 -4
  26. package/src/__tests__/agent-loop-thinking.test.ts +17 -12
  27. package/src/__tests__/agent-loop.test.ts +207 -341
  28. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +4 -2
  29. package/src/__tests__/agent-wake-override-profile.test.ts +22 -40
  30. package/src/__tests__/anthropic-provider.test.ts +201 -55
  31. package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
  32. package/src/__tests__/app-control-flow.test.ts +5 -0
  33. package/src/__tests__/approval-cascade.test.ts +4 -11
  34. package/src/__tests__/approval-routes-http.test.ts +4 -2
  35. package/src/__tests__/assistant-event.test.ts +15 -0
  36. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  37. package/src/__tests__/avatar-e2e.test.ts +7 -37
  38. package/src/__tests__/avatar-generator.test.ts +12 -42
  39. package/src/__tests__/avatar-identity-sync.test.ts +28 -3
  40. package/src/__tests__/background-shell-bash.test.ts +3 -7
  41. package/src/__tests__/btw-routes.test.ts +7 -12
  42. package/src/__tests__/call-pointer-messages.test.ts +5 -3
  43. package/src/__tests__/call-site-routing-provider.test.ts +22 -40
  44. package/src/__tests__/catalog-files.test.ts +1 -0
  45. package/src/__tests__/channel-approval-routes.test.ts +48 -20
  46. package/src/__tests__/channel-approvals.test.ts +3 -1
  47. package/src/__tests__/channel-invite-transport.test.ts +1 -5
  48. package/src/__tests__/channel-readiness-routes.test.ts +0 -4
  49. package/src/__tests__/channel-readiness-slack-remote.test.ts +2 -7
  50. package/src/__tests__/channel-retry-sweep.test.ts +71 -79
  51. package/src/__tests__/circuit-breaker-pipeline.test.ts +3 -3
  52. package/src/__tests__/clawhub-files.test.ts +1 -0
  53. package/src/__tests__/compaction-events.test.ts +5 -17
  54. package/src/__tests__/compaction-pipeline.test.ts +1 -1
  55. package/src/__tests__/compaction-timeout-recovery.test.ts +37 -48
  56. package/src/__tests__/compaction-trail-store.test.ts +1 -79
  57. package/src/__tests__/compactor-image-manifest-trust.test.ts +112 -0
  58. package/src/__tests__/computer-use-tools.test.ts +2 -2
  59. package/src/__tests__/config-watcher.test.ts +28 -0
  60. package/src/__tests__/context-search-agent-runner.test.ts +6 -3
  61. package/src/__tests__/context-token-estimator.test.ts +34 -0
  62. package/src/__tests__/context-window-manager-compact-retry.test.ts +291 -0
  63. package/src/__tests__/conversation-abort-tool-results.test.ts +14 -7
  64. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -2
  65. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +12 -27
  66. package/src/__tests__/conversation-agent-loop-overflow.test.ts +430 -90
  67. package/src/__tests__/conversation-agent-loop.test.ts +581 -62
  68. package/src/__tests__/conversation-analysis-routes.test.ts +1 -3
  69. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  70. package/src/__tests__/conversation-clear-safety.test.ts +20 -10
  71. package/src/__tests__/conversation-confirmation-signals.test.ts +15 -45
  72. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  73. package/src/__tests__/conversation-disk-view.test.ts +10 -17
  74. package/src/__tests__/conversation-fork-crud.test.ts +86 -172
  75. package/src/__tests__/conversation-fork-route.test.ts +16 -14
  76. package/src/__tests__/conversation-init.benchmark.test.ts +6 -6
  77. package/src/__tests__/conversation-lifecycle.test.ts +3 -2
  78. package/src/__tests__/conversation-load-history-repair.test.ts +3 -2
  79. package/src/__tests__/conversation-load-history-stripped.test.ts +1 -1
  80. package/src/__tests__/conversation-message-sync-tags.test.ts +3 -4
  81. package/src/__tests__/conversation-pairing.test.ts +34 -4
  82. package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
  83. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -0
  84. package/src/__tests__/conversation-process-callsite.test.ts +27 -30
  85. package/src/__tests__/conversation-provider-retry-repair.test.ts +53 -44
  86. package/src/__tests__/conversation-queue.test.ts +270 -164
  87. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -2
  88. package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
  89. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -2
  90. package/src/__tests__/conversation-runtime-assembly.test.ts +20 -22
  91. package/src/__tests__/conversation-runtime-workspace.test.ts +19 -1
  92. package/src/__tests__/conversation-slash-queue.test.ts +37 -31
  93. package/src/__tests__/conversation-slash-unknown.test.ts +13 -15
  94. package/src/__tests__/conversation-speed-override.test.ts +8 -22
  95. package/src/__tests__/conversation-stream-state.test.ts +484 -0
  96. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +6 -15
  97. package/src/__tests__/conversation-surfaces-app-control.test.ts +32 -4
  98. package/src/__tests__/conversation-surfaces-state-update.test.ts +5 -2
  99. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -15
  100. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +23 -11
  101. package/src/__tests__/conversation-unread-route.test.ts +14 -2
  102. package/src/__tests__/conversation-usage.test.ts +0 -2
  103. package/src/__tests__/conversation-wipe.test.ts +1 -1
  104. package/src/__tests__/conversation-workspace-cache-state.test.ts +3 -1
  105. package/src/__tests__/conversation-workspace-injection.test.ts +48 -22
  106. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +27 -7
  107. package/src/__tests__/credential-execution-tools.test.ts +1 -2
  108. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  109. package/src/__tests__/cross-provider-web-search.test.ts +6 -2
  110. package/src/__tests__/cu-unified-flow.test.ts +26 -1
  111. package/src/__tests__/db-schedule-syntax-migration.test.ts +11 -0
  112. package/src/__tests__/disk-pressure-guard.test.ts +66 -0
  113. package/src/__tests__/disk-pressure-routes.test.ts +9 -2
  114. package/src/__tests__/dm-persistence.test.ts +7 -2
  115. package/src/__tests__/dynamic-page-surface.test.ts +68 -0
  116. package/src/__tests__/edit-propagation.test.ts +1 -2
  117. package/src/__tests__/empty-response-pipeline.test.ts +127 -5
  118. package/src/__tests__/filing-service.test.ts +2 -2
  119. package/src/__tests__/first-greeting.test.ts +55 -14
  120. package/src/__tests__/gemini-inline-media.test.ts +78 -0
  121. package/src/__tests__/gemini-provider.test.ts +351 -28
  122. package/src/__tests__/guardian-routing-state.test.ts +60 -71
  123. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +9 -7
  124. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  125. package/src/__tests__/heartbeat-service.test.ts +2 -1
  126. package/src/__tests__/history-repair-hook.test.ts +161 -0
  127. package/src/__tests__/history-repair-observability.test.ts +1 -1
  128. package/src/__tests__/history-repair.test.ts +2 -1
  129. package/src/__tests__/host-app-control-proxy.test.ts +2 -0
  130. package/src/__tests__/host-cu-proxy.test.ts +2 -0
  131. package/src/__tests__/host-file-edit-tool.test.ts +4 -2
  132. package/src/__tests__/host-file-proxy.test.ts +31 -0
  133. package/src/__tests__/host-file-read-tool.test.ts +4 -2
  134. package/src/__tests__/host-file-write-tool.test.ts +9 -3
  135. package/src/__tests__/host-proxy-preactivation.test.ts +53 -14
  136. package/src/__tests__/host-shell-tool.test.ts +9 -4
  137. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  138. package/src/__tests__/identity-intro-cache.test.ts +35 -14
  139. package/src/__tests__/inbound-slack-persistence.test.ts +7 -2
  140. package/src/__tests__/injector-background-turn.test.ts +1 -1
  141. package/src/__tests__/injector-chain.test.ts +1 -1
  142. package/src/__tests__/injector-disk-pressure.test.ts +1 -1
  143. package/src/__tests__/injector-document-comments.test.ts +1 -1
  144. package/src/__tests__/injector-pkb-v2-silenced.test.ts +1 -1
  145. package/src/__tests__/injector-v3-suppression.test.ts +220 -0
  146. package/src/__tests__/list-messages-attachments.test.ts +7 -8
  147. package/src/__tests__/list-messages-hidden-metadata.test.ts +17 -15
  148. package/src/__tests__/list-messages-page-latest.test.ts +0 -1
  149. package/src/__tests__/list-messages-tool-merge.test.ts +36 -6
  150. package/src/__tests__/llm-call-pipeline.test.ts +21 -15
  151. package/src/__tests__/llm-request-log-turn-query.test.ts +42 -86
  152. package/src/__tests__/llm-resolver.test.ts +23 -47
  153. package/src/__tests__/llm-usage-store.test.ts +45 -0
  154. package/src/__tests__/log-export-routes.test.ts +59 -0
  155. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -8
  156. package/src/__tests__/mcp-auth-routes.test.ts +15 -10
  157. package/src/__tests__/mcp-health-check.test.ts +18 -13
  158. package/src/__tests__/memory-retrieval-pipeline.test.ts +1 -1
  159. package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
  160. package/src/__tests__/messaging-send-tool.test.ts +8 -4
  161. package/src/__tests__/migration-export-http.test.ts +12 -12
  162. package/src/__tests__/migration-import-commit-http.test.ts +8 -8
  163. package/src/__tests__/migration-import-preflight-http.test.ts +7 -7
  164. package/src/__tests__/migration-validate-http.test.ts +3 -3
  165. package/src/__tests__/native-web-search.test.ts +14 -20
  166. package/src/__tests__/notification-decision-identity.test.ts +9 -18
  167. package/src/__tests__/notification-decision-recipient-context.test.ts +3 -6
  168. package/src/__tests__/oauth-commands-routes.test.ts +1 -1
  169. package/src/__tests__/onboarding-template-contract.test.ts +10 -0
  170. package/src/__tests__/openai-provider.test.ts +66 -70
  171. package/src/__tests__/openai-responses-provider.test.ts +21 -77
  172. package/src/__tests__/outbound-slack-persistence.test.ts +2 -1
  173. package/src/__tests__/overflow-reduce-pipeline.test.ts +2 -4
  174. package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
  175. package/src/__tests__/persistence-pipeline.test.ts +15 -26
  176. package/src/__tests__/persistence-secret-redaction.test.ts +2 -1
  177. package/src/__tests__/pipeline-runner.test.ts +2 -3
  178. package/src/__tests__/plugin-bootstrap.test.ts +51 -25
  179. package/src/__tests__/plugin-route-contribution.test.ts +6 -16
  180. package/src/__tests__/plugin-skill-contribution.test.ts +7 -17
  181. package/src/__tests__/plugin-tool-contribution.test.ts +10 -26
  182. package/src/__tests__/plugin-types.test.ts +7 -14
  183. package/src/__tests__/prechat-onboarding-contract.test.ts +23 -0
  184. package/src/__tests__/process-message-background-slack.test.ts +17 -16
  185. package/src/__tests__/process-message-display-content.test.ts +30 -42
  186. package/src/__tests__/provider-commit-message-generator.test.ts +19 -14
  187. package/src/__tests__/provider-error-scenarios.test.ts +7 -6
  188. package/src/__tests__/provider-platform-proxy-integration.test.ts +3 -8
  189. package/src/__tests__/provider-send-message-override-profile.test.ts +9 -25
  190. package/src/__tests__/provider-streaming.benchmark.test.ts +12 -22
  191. package/src/__tests__/provider-usage-tracking.test.ts +0 -6
  192. package/src/__tests__/ratelimit.test.ts +9 -4
  193. package/src/__tests__/relay-server.test.ts +20 -13
  194. package/src/__tests__/retry-openrouter-only-normalization.test.ts +5 -8
  195. package/src/__tests__/retry-thinking-tool-choice.test.ts +10 -13
  196. package/src/__tests__/retry-verbosity-normalization.test.ts +5 -8
  197. package/src/__tests__/runtime-events-sse-reconnect.test.ts +353 -0
  198. package/src/__tests__/schedule-routes.test.ts +80 -10
  199. package/src/__tests__/schedule-store.test.ts +67 -0
  200. package/src/__tests__/schedule-tools.test.ts +125 -0
  201. package/src/__tests__/secret-ingress-http.test.ts +2 -2
  202. package/src/__tests__/secret-prompt-log-hygiene.test.ts +11 -7
  203. package/src/__tests__/secret-prompter-channel-fallback.test.ts +11 -9
  204. package/src/__tests__/secret-response-routing.test.ts +13 -11
  205. package/src/__tests__/send-endpoint-busy.test.ts +2 -1
  206. package/src/__tests__/shell-observability.test.ts +249 -0
  207. package/src/__tests__/skill-feature-flags-integration.test.ts +11 -11
  208. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  209. package/src/__tests__/skill-load-feature-flag.test.ts +10 -10
  210. package/src/__tests__/skills-files-catalog-fallback.test.ts +10 -0
  211. package/src/__tests__/skillssh-files.test.ts +1 -0
  212. package/src/__tests__/starter-task-flow.test.ts +6 -6
  213. package/src/__tests__/strip-memory-injections.test.ts +102 -14
  214. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  215. package/src/__tests__/suggestion-routes.test.ts +3 -3
  216. package/src/__tests__/sync-message-contract.test.ts +19 -16
  217. package/src/__tests__/system-prompt.test.ts +54 -0
  218. package/src/__tests__/terminal-tools.test.ts +3 -24
  219. package/src/__tests__/thread-backfill.test.ts +4 -9
  220. package/src/__tests__/title-generate-pipeline.test.ts +1 -1
  221. package/src/__tests__/token-estimate-pipeline.test.ts +2 -4
  222. package/src/__tests__/tool-error-pipeline.test.ts +2 -2
  223. package/src/__tests__/tool-execute-pipeline.test.ts +1 -1
  224. package/src/__tests__/tool-preview-lifecycle.test.ts +13 -11
  225. package/src/__tests__/tool-result-truncate-pipeline.test.ts +9 -12
  226. package/src/__tests__/tool-result-truncation.test.ts +3 -1
  227. package/src/__tests__/tools-audio-read.test.ts +113 -0
  228. package/src/__tests__/turn-boundary-resolution.test.ts +44 -84
  229. package/src/__tests__/turn-events-store.test.ts +11 -7
  230. package/src/__tests__/voice-scoped-grant-consumer.test.ts +8 -6
  231. package/src/__tests__/voice-session-bridge.test.ts +13 -7
  232. package/src/acp/__tests__/prepare-agent-env.test.ts +143 -31
  233. package/src/acp/prepare-agent-env.ts +52 -11
  234. package/src/agent/compaction-circuit.ts +140 -0
  235. package/src/agent/loop.ts +409 -85
  236. package/src/api/README.md +19 -17
  237. package/src/api/constants/tool-execution.ts +21 -0
  238. package/src/api/events/assistant-activity-state.ts +75 -0
  239. package/src/api/events/assistant-outbound-attachment.ts +25 -27
  240. package/src/api/events/assistant-text-delta.ts +6 -8
  241. package/src/api/events/assistant-turn-start.ts +5 -7
  242. package/src/api/events/avatar-updated.ts +24 -0
  243. package/src/api/events/compaction-circuit-closed.ts +26 -0
  244. package/src/api/events/compaction-circuit-open.ts +28 -0
  245. package/src/api/events/confirmation-request.ts +114 -0
  246. package/src/api/events/contact-request.ts +33 -0
  247. package/src/api/events/conversation-error.ts +77 -0
  248. package/src/api/events/conversation-list-invalidated.ts +38 -0
  249. package/src/api/events/conversation-title-updated.ts +24 -0
  250. package/src/api/events/disk-pressure-status-changed.ts +61 -0
  251. package/src/api/events/document-comment-created.ts +24 -28
  252. package/src/api/events/document-comment-deleted.ts +6 -8
  253. package/src/api/events/document-comment-reopened.ts +6 -8
  254. package/src/api/events/document-comment-resolved.ts +8 -10
  255. package/src/api/events/document-editor-update.ts +27 -0
  256. package/src/api/events/error.ts +32 -0
  257. package/src/api/events/generation-cancelled.ts +4 -6
  258. package/src/api/events/generation-handoff.ts +13 -15
  259. package/src/api/events/home-feed-updated.ts +26 -0
  260. package/src/api/events/identity-changed.ts +32 -0
  261. package/src/api/events/interaction-resolved.ts +50 -0
  262. package/src/api/events/message-complete.ts +10 -12
  263. package/src/api/events/message-dequeued.ts +21 -0
  264. package/src/api/events/message-queued-deleted.ts +23 -0
  265. package/src/api/events/message-queued.ts +22 -0
  266. package/src/api/events/message-request-complete.ts +29 -0
  267. package/src/api/events/navigate-settings.ts +20 -0
  268. package/src/api/events/notification-intent.ts +33 -0
  269. package/src/api/events/open-url.ts +6 -8
  270. package/src/api/events/question-request.ts +67 -0
  271. package/src/api/events/relationship-state-updated.ts +4 -6
  272. package/src/api/events/secret-request.ts +42 -0
  273. package/src/api/events/subagent-event.ts +79 -0
  274. package/src/api/events/subagent-spawned.ts +40 -0
  275. package/src/api/events/subagent-status-changed.ts +65 -0
  276. package/src/api/events/sync-changed.ts +29 -0
  277. package/src/api/events/tool-result.ts +129 -0
  278. package/src/api/events/tool-use-start.ts +8 -10
  279. package/src/api/events/turn-profile-auto-routed.ts +28 -0
  280. package/src/api/events/ui-surface-complete.ts +30 -0
  281. package/src/api/events/ui-surface-dismiss.ts +22 -0
  282. package/src/api/events/ui-surface-show.ts +67 -0
  283. package/src/api/events/ui-surface-update.ts +26 -0
  284. package/src/api/events/usage-update.ts +34 -0
  285. package/src/api/events/user-message-echo.ts +35 -0
  286. package/src/api/index.ts +354 -0
  287. package/src/api/requests/dictation.ts +45 -0
  288. package/src/api/responses/disk-pressure-status.ts +26 -0
  289. package/src/api/responses/home.ts +217 -0
  290. package/src/api/responses/llm-context-response.ts +2 -0
  291. package/src/api/responses/memory-v3-selection-log.ts +50 -0
  292. package/src/api/responses/subagent-detail.ts +48 -0
  293. package/src/approvals/guardian-decision-primitive.ts +7 -15
  294. package/src/approvals/guardian-request-resolvers.ts +6 -9
  295. package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
  296. package/src/avatar/__tests__/avatar-store.test.ts +193 -0
  297. package/src/avatar/avatar-manifest.ts +195 -0
  298. package/src/avatar/avatar-store.ts +113 -0
  299. package/src/avatar/traits-png-sync.ts +8 -2
  300. package/src/background-wake/next-wake.test.ts +31 -1
  301. package/src/background-wake/next-wake.ts +4 -1
  302. package/src/calls/call-conversation-messages.ts +6 -4
  303. package/src/calls/guardian-action-sweep.ts +6 -4
  304. package/src/calls/relay-server.ts +12 -8
  305. package/src/calls/voice-session-bridge.ts +13 -27
  306. package/src/cli/commands/__tests__/memory-v3.test.ts +245 -0
  307. package/src/cli/commands/avatar.ts +17 -11
  308. package/src/cli/commands/conversations.ts +15 -1
  309. package/src/cli/commands/db/__tests__/repair.test.ts +540 -0
  310. package/src/cli/commands/db/__tests__/status.test.ts +253 -0
  311. package/src/cli/commands/db/format.ts +48 -0
  312. package/src/cli/commands/db/index.ts +29 -0
  313. package/src/cli/commands/db/repair-step-conversation-backfill.ts +345 -0
  314. package/src/cli/commands/db/repair-step-integrity.ts +146 -0
  315. package/src/cli/commands/db/repair-steps.ts +164 -0
  316. package/src/cli/commands/db/repair.ts +141 -0
  317. package/src/cli/commands/db/status.ts +366 -0
  318. package/src/cli/commands/memory-v3.ts +159 -445
  319. package/src/cli/lib/cli-colors.ts +24 -6
  320. package/src/cli/program.ts +4 -5
  321. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  322. package/src/config/assistant-feature-flags.ts +2 -2
  323. package/src/config/bundled-skills/app-builder/SKILL.md +14 -3
  324. package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
  325. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +7 -2
  326. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  327. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  328. package/src/config/call-site-defaults.ts +2 -7
  329. package/src/config/feature-flag-registry.json +25 -9
  330. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -226
  331. package/src/config/schemas/call-site-catalog.ts +8 -15
  332. package/src/config/schemas/llm.ts +2 -3
  333. package/src/config/schemas/memory-lifecycle.ts +24 -0
  334. package/src/config/schemas/memory-v2.ts +0 -253
  335. package/src/config/schemas/memory-v3.ts +39 -0
  336. package/src/config/schemas/memory.ts +6 -1
  337. package/src/config/schemas/timeouts.ts +3 -1
  338. package/src/context/compactor.ts +54 -31
  339. package/src/context/token-estimator.ts +19 -0
  340. package/src/context/tool-result-truncation.ts +1 -43
  341. package/src/context/window-manager.ts +138 -20
  342. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +2 -2
  343. package/src/daemon/__tests__/web-search-status-text.test.ts +10 -6
  344. package/src/daemon/approval-generators.ts +4 -4
  345. package/src/daemon/config-watcher.ts +7 -1
  346. package/src/daemon/conversation-agent-loop-handlers.ts +225 -88
  347. package/src/daemon/conversation-agent-loop.ts +284 -584
  348. package/src/daemon/conversation-error.ts +7 -7
  349. package/src/daemon/conversation-history.ts +22 -6
  350. package/src/daemon/conversation-launch.ts +4 -8
  351. package/src/daemon/conversation-lifecycle.ts +10 -38
  352. package/src/daemon/conversation-messaging.ts +1 -3
  353. package/src/daemon/conversation-notifiers.ts +7 -5
  354. package/src/daemon/conversation-process.ts +100 -79
  355. package/src/daemon/conversation-runtime-assembly.ts +47 -21
  356. package/src/daemon/conversation-store.ts +6 -5
  357. package/src/daemon/conversation-surfaces.ts +55 -69
  358. package/src/daemon/conversation-tool-setup.ts +3 -0
  359. package/src/daemon/conversation.ts +91 -126
  360. package/src/daemon/daemon-skill-host.ts +2 -6
  361. package/src/daemon/disk-pressure-guard.ts +35 -29
  362. package/src/daemon/external-plugins-bootstrap.ts +46 -24
  363. package/src/daemon/first-greeting.ts +26 -4
  364. package/src/daemon/guardian-action-generators.ts +2 -2
  365. package/src/daemon/handlers/conversations.ts +6 -22
  366. package/src/daemon/handlers/shared.ts +4 -0
  367. package/src/daemon/handlers/skills.ts +15 -14
  368. package/src/daemon/host-app-control-proxy.ts +54 -1
  369. package/src/daemon/host-cu-proxy.ts +46 -22
  370. package/src/daemon/host-file-proxy.ts +25 -1
  371. package/src/daemon/host-proxy-preactivation.ts +25 -6
  372. package/src/daemon/lifecycle.ts +28 -55
  373. package/src/daemon/message-protocol.ts +2 -3
  374. package/src/daemon/message-provenance.ts +49 -0
  375. package/src/daemon/message-types/contacts.ts +3 -20
  376. package/src/daemon/message-types/conversations.ts +13 -111
  377. package/src/daemon/message-types/documents.ts +3 -9
  378. package/src/daemon/message-types/home.ts +4 -17
  379. package/src/daemon/message-types/integrations.ts +2 -6
  380. package/src/daemon/message-types/messages.ts +28 -343
  381. package/src/daemon/message-types/notifications.ts +2 -32
  382. package/src/daemon/message-types/settings.ts +3 -8
  383. package/src/daemon/message-types/skills.ts +2 -0
  384. package/src/daemon/message-types/surfaces.ts +2 -0
  385. package/src/daemon/message-types/sync.ts +12 -25
  386. package/src/daemon/message-types/workspace.ts +3 -11
  387. package/src/daemon/process-message.ts +49 -46
  388. package/src/daemon/server.ts +12 -0
  389. package/src/daemon/tool-side-effects.ts +10 -7
  390. package/src/daemon/trust-context.ts +13 -0
  391. package/src/daemon/wake-target-adapter.ts +11 -1
  392. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -1
  393. package/src/heartbeat/heartbeat-run-store.ts +31 -0
  394. package/src/heartbeat/heartbeat-service.ts +16 -0
  395. package/src/home/feature-gate.ts +22 -0
  396. package/src/home/feed-types.ts +36 -221
  397. package/src/ipc/__tests__/email-ipc.test.ts +0 -9
  398. package/src/ipc/routes/__tests__/route-adapter.test.ts +244 -0
  399. package/src/ipc/routes/route-adapter.ts +45 -6
  400. package/src/ipc/skill-routes/__tests__/memory.test.ts +18 -9
  401. package/src/ipc/skill-routes/__tests__/providers.test.ts +10 -10
  402. package/src/ipc/skill-routes/__tests__/registries.test.ts +28 -18
  403. package/src/ipc/skill-routes/memory.ts +26 -13
  404. package/src/ipc/skill-routes/providers.ts +5 -6
  405. package/src/ipc/skill-routes/registries.ts +13 -61
  406. package/src/live-voice/__tests__/live-voice-archive.test.ts +24 -11
  407. package/src/memory/__tests__/conversation-queries.test.ts +192 -8
  408. package/src/memory/__tests__/db-maintenance.test.ts +128 -0
  409. package/src/memory/__tests__/jobs-store-job-classes.test.ts +5 -4
  410. package/src/memory/__tests__/memory-retrospective-job.test.ts +10 -6
  411. package/src/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
  412. package/src/memory/context-search/agent-runner.ts +2 -4
  413. package/src/memory/conversation-crud.ts +39 -8
  414. package/src/memory/conversation-queries.ts +78 -22
  415. package/src/memory/db-init.ts +8 -0
  416. package/src/memory/db-maintenance.ts +18 -2
  417. package/src/memory/graph/consolidation.ts +8 -11
  418. package/src/memory/graph/conversation-graph-memory.ts +41 -8
  419. package/src/memory/graph/extraction.ts +6 -9
  420. package/src/memory/graph/narrative.ts +2 -2
  421. package/src/memory/graph/pattern-scan.ts +2 -2
  422. package/src/memory/graph/retriever.ts +20 -26
  423. package/src/memory/graph/tools.ts +4 -4
  424. package/src/memory/job-handlers/conversation-starters.ts +32 -32
  425. package/src/memory/job-handlers/summarization.ts +1 -2
  426. package/src/memory/jobs-store.ts +3 -1
  427. package/src/memory/jobs-worker.ts +51 -39
  428. package/src/memory/llm-request-log-source-clickhouse.ts +5 -31
  429. package/src/memory/llm-request-log-source-local.ts +0 -11
  430. package/src/memory/llm-request-log-source.ts +9 -25
  431. package/src/memory/llm-request-log-store.ts +0 -41
  432. package/src/memory/llm-usage-store.ts +10 -0
  433. package/src/memory/memory-marker.ts +17 -0
  434. package/src/memory/memory-retrospective-job.ts +6 -2
  435. package/src/memory/memory-v2-activation-log-store.ts +1 -83
  436. package/src/memory/migrations/267-llm-usage-events-add-assistant-version.ts +46 -0
  437. package/src/memory/migrations/268-add-memory-v3-selections.ts +28 -0
  438. package/src/memory/migrations/269-schedule-script-timeout.ts +11 -0
  439. package/src/memory/migrations/270-messages-role-created-at-index.ts +18 -0
  440. package/src/memory/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
  441. package/src/memory/migrations/index.ts +4 -0
  442. package/src/memory/schema/infrastructure.ts +11 -0
  443. package/src/memory/v2/__tests__/consolidation-job.test.ts +124 -0
  444. package/src/memory/v2/__tests__/migration.test.ts +11 -3
  445. package/src/memory/v2/__tests__/page-index.test.ts +37 -1
  446. package/src/memory/v2/__tests__/router.test.ts +14 -4
  447. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -5
  448. package/src/memory/v2/backfill-jobs.ts +6 -0
  449. package/src/memory/v2/consolidation-job.ts +89 -9
  450. package/src/memory/v2/migration.ts +5 -3
  451. package/src/memory/v2/page-index.ts +11 -0
  452. package/src/memory/v2/router.ts +8 -11
  453. package/src/memory/v2/sweep-job.ts +8 -11
  454. package/src/memory/v2/types.ts +1 -0
  455. package/src/memory/v3/__tests__/assign.test.ts +242 -0
  456. package/src/memory/v3/__tests__/capabilities.test.ts +118 -0
  457. package/src/memory/v3/__tests__/core.test.ts +39 -0
  458. package/src/memory/v3/__tests__/fixtures/eval-turns.json +36 -0
  459. package/src/memory/v3/__tests__/fixtures/live-turns.json +37 -0
  460. package/src/memory/v3/__tests__/health.test.ts +203 -0
  461. package/src/memory/v3/__tests__/live-integration.test.ts +330 -0
  462. package/src/memory/v3/__tests__/maintain-job.test.ts +288 -0
  463. package/src/memory/v3/__tests__/needle.test.ts +107 -0
  464. package/src/memory/v3/__tests__/orchestrate.test.ts +400 -0
  465. package/src/memory/v3/__tests__/reconcile.test.ts +274 -0
  466. package/src/memory/v3/__tests__/render-injection.test.ts +61 -0
  467. package/src/memory/v3/__tests__/router.test.ts +260 -0
  468. package/src/memory/v3/__tests__/selection-log-store.test.ts +179 -0
  469. package/src/memory/v3/__tests__/selector.test.ts +404 -0
  470. package/src/memory/v3/__tests__/shadow-plugin.test.ts +414 -0
  471. package/src/memory/v3/__tests__/snapshot.test.ts +168 -0
  472. package/src/memory/v3/__tests__/tree.test.ts +192 -0
  473. package/src/memory/v3/__tests__/types.test.ts +54 -0
  474. package/src/memory/v3/__tests__/working-set-eviction.test.ts +106 -0
  475. package/src/memory/v3/__tests__/working-set-skeleton.test.ts +44 -0
  476. package/src/memory/v3/assign.ts +268 -0
  477. package/src/memory/v3/capabilities.ts +124 -0
  478. package/src/memory/v3/core.ts +26 -0
  479. package/src/memory/v3/data/README.md +84 -0
  480. package/src/memory/v3/data/assignments.json +5 -0
  481. package/src/memory/v3/data/core.json +1 -0
  482. package/src/memory/v3/data/leaves/domain-a/topic-x.md +9 -0
  483. package/src/memory/v3/data/leaves/domain-a/topic-y.md +9 -0
  484. package/src/memory/v3/data/leaves/domain-b/topic-z.md +9 -0
  485. package/src/memory/v3/health.ts +0 -0
  486. package/src/memory/v3/maintain-job.ts +314 -0
  487. package/src/memory/v3/needle.ts +115 -0
  488. package/src/memory/v3/orchestrate.ts +114 -0
  489. package/src/memory/v3/page-content.ts +34 -0
  490. package/src/memory/v3/provider-blocks.ts +16 -0
  491. package/src/memory/v3/reconcile.ts +523 -0
  492. package/src/memory/v3/render-injection.ts +32 -0
  493. package/src/memory/v3/router.ts +184 -0
  494. package/src/memory/v3/selection-log-store.ts +84 -0
  495. package/src/memory/v3/selector.ts +211 -0
  496. package/src/memory/v3/shadow-plugin.ts +379 -0
  497. package/src/memory/v3/snapshot.ts +209 -0
  498. package/src/memory/v3/tree.ts +174 -0
  499. package/src/memory/v3/types.ts +46 -60
  500. package/src/memory/v3/working-set.ts +88 -0
  501. package/src/messaging/providers/slack/render-transcript.test.ts +1 -1
  502. package/src/messaging/providers/slack/render-transcript.ts +2 -2
  503. package/src/messaging/style-analyzer.ts +8 -11
  504. package/src/notifications/conversation-pairing.ts +8 -6
  505. package/src/notifications/decision-engine.ts +10 -13
  506. package/src/notifications/preference-extractor.ts +11 -14
  507. package/src/permissions/prompter.ts +42 -36
  508. package/src/permissions/question-prompter.test.ts +35 -26
  509. package/src/permissions/question-prompter.ts +6 -10
  510. package/src/plugin-api/index.ts +2 -0
  511. package/src/plugin-api/types.ts +25 -3
  512. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
  513. package/src/plugins/defaults/circuit-breaker/package.json +15 -0
  514. package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
  515. package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
  516. package/src/plugins/defaults/compaction/package.json +15 -0
  517. package/src/plugins/defaults/compaction/register.ts +35 -0
  518. package/src/plugins/defaults/compaction/terminal.ts +73 -0
  519. package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +22 -0
  520. package/src/plugins/defaults/empty-response/package.json +15 -0
  521. package/src/plugins/defaults/empty-response/register.ts +28 -0
  522. package/src/plugins/defaults/empty-response/terminal.ts +106 -0
  523. package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +35 -0
  524. package/src/plugins/defaults/history-repair/package.json +15 -0
  525. package/src/plugins/defaults/history-repair/register.ts +24 -0
  526. package/src/{daemon/history-repair.ts → plugins/defaults/history-repair/terminal.ts} +48 -35
  527. package/src/plugins/defaults/index.ts +29 -40
  528. package/src/plugins/defaults/injectors/package.json +15 -0
  529. package/src/plugins/defaults/{injectors.ts → injectors/register.ts} +14 -38
  530. package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +17 -0
  531. package/src/plugins/defaults/llm-call/package.json +15 -0
  532. package/src/plugins/defaults/{llm-call.ts → llm-call/register.ts} +6 -38
  533. package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +17 -0
  534. package/src/plugins/defaults/memory-retrieval/package.json +15 -0
  535. package/src/plugins/defaults/{memory-retrieval.ts → memory-retrieval/register.ts} +10 -48
  536. package/src/plugins/defaults/{overflow-reduce.ts → overflow-reduce/middlewares/overflowReduce.ts} +18 -77
  537. package/src/plugins/defaults/overflow-reduce/package.json +15 -0
  538. package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
  539. package/src/plugins/defaults/persistence/middlewares/persistence.ts +19 -0
  540. package/src/plugins/defaults/persistence/package.json +15 -0
  541. package/src/plugins/defaults/persistence/register.ts +38 -0
  542. package/src/plugins/defaults/persistence/terminal.ts +83 -0
  543. package/src/plugins/defaults/title-generate/package.json +15 -0
  544. package/src/plugins/defaults/title-generate/register.ts +35 -0
  545. package/src/plugins/defaults/title-generate/terminal.ts +31 -0
  546. package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +23 -0
  547. package/src/plugins/defaults/token-estimate/package.json +15 -0
  548. package/src/plugins/defaults/token-estimate/register.ts +34 -0
  549. package/src/plugins/defaults/token-estimate/terminal.ts +40 -0
  550. package/src/plugins/defaults/tool-error/middlewares/toolError.ts +21 -0
  551. package/src/plugins/defaults/tool-error/package.json +15 -0
  552. package/src/plugins/defaults/tool-error/register.ts +35 -0
  553. package/src/plugins/defaults/tool-error/terminal.ts +47 -0
  554. package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +23 -0
  555. package/src/plugins/defaults/tool-execute/package.json +15 -0
  556. package/src/plugins/defaults/{tool-execute.ts → tool-execute/register.ts} +8 -46
  557. package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +23 -0
  558. package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
  559. package/src/plugins/defaults/tool-result-truncate/register.ts +35 -0
  560. package/src/plugins/defaults/tool-result-truncate/terminal.ts +113 -0
  561. package/src/plugins/defaults/tool-result-truncate/types.ts +22 -0
  562. package/src/plugins/external-plugin-loader.ts +2 -2
  563. package/src/plugins/pipeline.ts +0 -12
  564. package/src/plugins/types.ts +51 -90
  565. package/src/plugins/user-loader.ts +4 -3
  566. package/src/proactive-artifact/aux-message-injector.ts +0 -1
  567. package/src/proactive-artifact/job.test.ts +20 -8
  568. package/src/proactive-artifact/job.ts +3 -1
  569. package/src/prompts/sections.ts +20 -7
  570. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +2 -2
  571. package/src/prompts/templates/BOOTSTRAP.md +5 -1
  572. package/src/prompts/templates/system-sections.ts +6 -0
  573. package/src/providers/__tests__/retry-callsite.test.ts +25 -25
  574. package/src/providers/__tests__/satellite-connection-routing.test.ts +7 -21
  575. package/src/providers/anthropic/client.ts +24 -5
  576. package/src/providers/call-site-routing.ts +1 -9
  577. package/src/providers/gemini/client.ts +152 -34
  578. package/src/providers/gemini/inline-media.ts +74 -0
  579. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +0 -2
  580. package/src/providers/openai/chat-completions-provider.ts +1 -4
  581. package/src/providers/openai/responses-provider.ts +1 -4
  582. package/src/providers/openrouter/client.ts +1 -6
  583. package/src/providers/provider-send-message.ts +6 -6
  584. package/src/providers/ratelimit.ts +1 -9
  585. package/src/providers/retry.ts +0 -5
  586. package/src/providers/types.ts +11 -2
  587. package/src/providers/usage-tracking.ts +1 -9
  588. package/src/runtime/__tests__/agent-wake.test.ts +131 -26
  589. package/src/runtime/__tests__/background-job-runner.test.ts +1 -3
  590. package/src/runtime/agent-wake.ts +93 -18
  591. package/src/runtime/assistant-event-hub.ts +2 -2
  592. package/src/runtime/auth/__tests__/guard-tests.test.ts +75 -109
  593. package/src/runtime/auth/__tests__/route-policy.test.ts +153 -170
  594. package/src/runtime/auth/route-policy.ts +42 -1079
  595. package/src/runtime/background-job-runner.ts +1 -4
  596. package/src/runtime/btw-sidechain.ts +3 -1
  597. package/src/runtime/channel-approvals.ts +3 -14
  598. package/src/runtime/channel-invite-transport.ts +5 -6
  599. package/src/runtime/channel-readiness-service.ts +2 -5
  600. package/src/runtime/channel-retry-sweep.ts +12 -16
  601. package/src/runtime/conversation-stream-state.ts +294 -0
  602. package/src/runtime/http-router.ts +19 -22
  603. package/src/runtime/http-types.ts +12 -6
  604. package/src/runtime/invite-instruction-generator.ts +3 -3
  605. package/src/runtime/pending-interactions.ts +2 -2
  606. package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +565 -0
  607. package/src/runtime/routes/__tests__/content-source-routes.test.ts +4 -4
  608. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +62 -32
  609. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +237 -0
  610. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -22
  611. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +7 -2
  612. package/src/runtime/routes/__tests__/sanity-routes.test.ts +6 -6
  613. package/src/runtime/routes/__tests__/stt-routes.test.ts +3 -3
  614. package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +5 -2
  615. package/src/runtime/routes/__tests__/tts-routes.test.ts +3 -3
  616. package/src/runtime/routes/acp-routes.test.ts +97 -75
  617. package/src/runtime/routes/acp-routes.ts +29 -6
  618. package/src/runtime/routes/app-management-routes.ts +97 -24
  619. package/src/runtime/routes/app-routes.ts +25 -5
  620. package/src/runtime/routes/approval-routes.ts +16 -4
  621. package/src/runtime/routes/attachment-routes.ts +25 -1
  622. package/src/runtime/routes/audio-routes.ts +1 -0
  623. package/src/runtime/routes/audit-routes.ts +5 -0
  624. package/src/runtime/routes/auth-routes.ts +5 -0
  625. package/src/runtime/routes/avatar-routes.ts +238 -59
  626. package/src/runtime/routes/background-tool-routes.ts +9 -0
  627. package/src/runtime/routes/background-wake-routes.ts +13 -3
  628. package/src/runtime/routes/backup-routes.ts +45 -0
  629. package/src/runtime/routes/bookmark-routes.ts +13 -0
  630. package/src/runtime/routes/brain-graph-routes.ts +9 -0
  631. package/src/runtime/routes/browser-routes.ts +5 -0
  632. package/src/runtime/routes/browser-tabs-routes.ts +5 -0
  633. package/src/runtime/routes/btw-routes.ts +5 -1
  634. package/src/runtime/routes/cache-routes.ts +13 -0
  635. package/src/runtime/routes/call-routes.ts +21 -10
  636. package/src/runtime/routes/channel-availability-routes.ts +5 -1
  637. package/src/runtime/routes/channel-readiness-routes.ts +37 -4
  638. package/src/runtime/routes/channel-route-definitions.ts +21 -0
  639. package/src/runtime/routes/channel-verification-routes.ts +21 -0
  640. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +9 -2
  641. package/src/runtime/routes/client-routes.ts +9 -0
  642. package/src/runtime/routes/consolidation-routes.ts +13 -5
  643. package/src/runtime/routes/contact-prompt-routes.ts +9 -0
  644. package/src/runtime/routes/contact-routes.ts +90 -23
  645. package/src/runtime/routes/content-source-routes.ts +5 -1
  646. package/src/runtime/routes/conversation-analysis-routes.ts +5 -1
  647. package/src/runtime/routes/conversation-attention-routes.ts +5 -0
  648. package/src/runtime/routes/conversation-cli-routes.ts +54 -7
  649. package/src/runtime/routes/conversation-compaction-routes.ts +54 -25
  650. package/src/runtime/routes/conversation-list-routes.ts +81 -12
  651. package/src/runtime/routes/conversation-management-routes.ts +57 -14
  652. package/src/runtime/routes/conversation-query-routes.ts +88 -41
  653. package/src/runtime/routes/conversation-routes.ts +74 -19
  654. package/src/runtime/routes/conversation-starter-routes.ts +22 -13
  655. package/src/runtime/routes/conversations-import-routes.ts +6 -1
  656. package/src/runtime/routes/credential-prompt-routes.ts +5 -0
  657. package/src/runtime/routes/credential-routes.ts +25 -6
  658. package/src/runtime/routes/debug-bash-routes.ts +5 -0
  659. package/src/runtime/routes/debug-routes.ts +11 -2
  660. package/src/runtime/routes/defer-routes.ts +13 -0
  661. package/src/runtime/routes/diagnostics-routes.ts +37 -46
  662. package/src/runtime/routes/disk-pressure-routes.ts +17 -31
  663. package/src/runtime/routes/document-comments-routes.ts +46 -27
  664. package/src/runtime/routes/documents-routes.ts +21 -10
  665. package/src/runtime/routes/domain-routes.ts +61 -28
  666. package/src/runtime/routes/email-routes.ts +33 -0
  667. package/src/runtime/routes/events-routes.ts +114 -9
  668. package/src/runtime/routes/filing-routes.ts +9 -4
  669. package/src/runtime/routes/gateway-log-routes.ts +5 -0
  670. package/src/runtime/routes/global-search-routes.ts +53 -50
  671. package/src/runtime/routes/group-routes.ts +21 -5
  672. package/src/runtime/routes/guardian-action-routes.ts +9 -0
  673. package/src/runtime/routes/guardian-approval-interception.ts +0 -31
  674. package/src/runtime/routes/heartbeat-routes.ts +25 -9
  675. package/src/runtime/routes/home-feed-routes.ts +23 -19
  676. package/src/runtime/routes/home-state-routes.ts +8 -40
  677. package/src/runtime/routes/host-app-control-routes.ts +5 -0
  678. package/src/runtime/routes/host-bash-routes.ts +5 -0
  679. package/src/runtime/routes/host-browser-routes.ts +13 -0
  680. package/src/runtime/routes/host-cu-routes.ts +5 -0
  681. package/src/runtime/routes/host-file-routes.ts +26 -6
  682. package/src/runtime/routes/host-transfer-routes.ts +13 -2
  683. package/src/runtime/routes/http-adapter.ts +1 -2
  684. package/src/runtime/routes/identity-intro-cache.ts +17 -6
  685. package/src/runtime/routes/identity-routes.ts +12 -2
  686. package/src/runtime/routes/image-generation-routes.ts +5 -0
  687. package/src/runtime/routes/inbound-message-handler.ts +15 -11
  688. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +0 -12
  689. package/src/runtime/routes/inbound-stages/background-dispatch.ts +15 -19
  690. package/src/runtime/routes/inference-profile-session-routes.ts +13 -3
  691. package/src/runtime/routes/inference-provider-connection-routes.ts +21 -5
  692. package/src/runtime/routes/inference-send-routes.ts +11 -11
  693. package/src/runtime/routes/integrations/a2a.ts +30 -7
  694. package/src/runtime/routes/integrations/slack/channel.ts +19 -3
  695. package/src/runtime/routes/integrations/slack/share.ts +9 -2
  696. package/src/runtime/routes/integrations/telegram.ts +28 -9
  697. package/src/runtime/routes/integrations/twilio.ts +35 -7
  698. package/src/runtime/routes/integrations/vercel.ts +3 -3
  699. package/src/runtime/routes/internal-oauth-routes.ts +5 -0
  700. package/src/runtime/routes/internal-twilio-routes.ts +13 -0
  701. package/src/runtime/routes/llm-call-sites-routes.ts +39 -4
  702. package/src/runtime/routes/log-export-routes.ts +28 -10
  703. package/src/runtime/routes/mcp-auth-routes.ts +25 -0
  704. package/src/runtime/routes/memory-item-routes.ts +21 -10
  705. package/src/runtime/routes/memory-v2-routes.ts +90 -36
  706. package/src/runtime/routes/memory-v3-routes.ts +273 -407
  707. package/src/runtime/routes/migration-rollback-routes.ts +5 -1
  708. package/src/runtime/routes/migration-routes.ts +29 -0
  709. package/src/runtime/routes/notification-routes.ts +17 -1
  710. package/src/runtime/routes/oauth-apps.ts +33 -11
  711. package/src/runtime/routes/oauth-commands-routes.ts +37 -14
  712. package/src/runtime/routes/oauth-connect-routes.ts +9 -0
  713. package/src/runtime/routes/oauth-lifecycle-routes.ts +5 -1
  714. package/src/runtime/routes/oauth-providers.ts +35 -10
  715. package/src/runtime/routes/platform-routes.ts +21 -0
  716. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +3 -2
  717. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +37 -16
  718. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +7 -3
  719. package/src/runtime/routes/playground/__tests__/state.test.ts +10 -3
  720. package/src/runtime/routes/playground/force-compact.ts +1 -1
  721. package/src/runtime/routes/playground/helpers.ts +0 -1
  722. package/src/runtime/routes/playground/inject-failures.ts +13 -8
  723. package/src/runtime/routes/playground/reset-circuit.ts +14 -9
  724. package/src/runtime/routes/playground/seed-conversation.ts +1 -1
  725. package/src/runtime/routes/playground/seeded-conversations.ts +3 -3
  726. package/src/runtime/routes/playground/state.ts +4 -3
  727. package/src/runtime/routes/plugins-routes.ts +22 -19
  728. package/src/runtime/routes/profiler-routes.ts +17 -4
  729. package/src/runtime/routes/ps-routes.ts +5 -0
  730. package/src/runtime/routes/publish-routes.ts +13 -3
  731. package/src/runtime/routes/question-routes.ts +5 -0
  732. package/src/runtime/routes/recording-routes.ts +25 -12
  733. package/src/runtime/routes/rename-conversation-routes.ts +5 -0
  734. package/src/runtime/routes/sanity-routes.ts +9 -2
  735. package/src/runtime/routes/schedule-routes.ts +137 -47
  736. package/src/runtime/routes/secret-routes.ts +17 -4
  737. package/src/runtime/routes/sequence-routes.ts +33 -0
  738. package/src/runtime/routes/settings-routes.ts +65 -19
  739. package/src/runtime/routes/skills-routes.ts +133 -69
  740. package/src/runtime/routes/slack-channel-routes.ts +5 -0
  741. package/src/runtime/routes/stt-routes.ts +13 -6
  742. package/src/runtime/routes/subagents-routes.ts +24 -18
  743. package/src/runtime/routes/suggest-trust-rule-routes.ts +7 -2
  744. package/src/runtime/routes/surface-action-routes.ts +9 -0
  745. package/src/runtime/routes/surface-content-routes.ts +10 -2
  746. package/src/runtime/routes/task-routes.ts +37 -0
  747. package/src/runtime/routes/telemetry-routes.ts +9 -0
  748. package/src/runtime/routes/trace-event-routes.ts +42 -1
  749. package/src/runtime/routes/trust-rules-routes.ts +5 -0
  750. package/src/runtime/routes/tts-routes.ts +13 -6
  751. package/src/runtime/routes/types.ts +17 -8
  752. package/src/runtime/routes/ui-request-routes.ts +5 -0
  753. package/src/runtime/routes/upgrade-broadcast-routes.ts +5 -0
  754. package/src/runtime/routes/usage-routes.ts +71 -3
  755. package/src/runtime/routes/user-routes-cli.ts +9 -0
  756. package/src/runtime/routes/user-routes.ts +5 -1
  757. package/src/runtime/routes/wake-conversation-routes.ts +5 -0
  758. package/src/runtime/routes/watcher-routes.ts +21 -0
  759. package/src/runtime/routes/webhook-routes.ts +9 -0
  760. package/src/runtime/routes/wipe-conversation-routes.ts +5 -0
  761. package/src/runtime/routes/work-items-routes.ts +47 -19
  762. package/src/runtime/routes/workspace-commit-routes.ts +5 -0
  763. package/src/runtime/routes/workspace-routes.test.ts +42 -0
  764. package/src/runtime/routes/workspace-routes.ts +120 -9
  765. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -4
  766. package/src/runtime/services/analyze-conversation.ts +3 -6
  767. package/src/runtime/services/conversation-serializer.ts +24 -2
  768. package/src/runtime/sync/resource-sync-events.ts +16 -2
  769. package/src/runtime/sync/sync-publisher.ts +2 -2
  770. package/src/schedule/run-script.ts +28 -3
  771. package/src/schedule/schedule-store.ts +8 -0
  772. package/src/schedule/scheduler.ts +3 -1
  773. package/src/signals/user-message.ts +5 -8
  774. package/src/skills/catalog-files.ts +4 -1
  775. package/src/skills/clawhub-files.ts +2 -0
  776. package/src/skills/skillssh-files.ts +2 -0
  777. package/src/subagent/manager.ts +3 -6
  778. package/src/telemetry/types.ts +26 -0
  779. package/src/telemetry/usage-telemetry-reporter.test.ts +138 -1
  780. package/src/telemetry/usage-telemetry-reporter.ts +31 -0
  781. package/src/tools/acp/spawn.test.ts +88 -38
  782. package/src/tools/apps/definitions.ts +8 -4
  783. package/src/tools/ask-question/ask-question-tool.test.ts +120 -105
  784. package/src/tools/ask-question/ask-question-tool.ts +85 -90
  785. package/src/tools/computer-use/definitions.ts +28 -24
  786. package/src/tools/credential-execution/make-authenticated-request.ts +56 -51
  787. package/src/tools/credential-execution/manage-secure-command-tool.ts +2 -2
  788. package/src/tools/credential-execution/run-authenticated-command.ts +82 -77
  789. package/src/tools/credentials/vault.ts +112 -111
  790. package/src/tools/execution-target.ts +1 -1
  791. package/src/tools/execution-timeout.ts +3 -4
  792. package/src/tools/filesystem/edit.ts +45 -42
  793. package/src/tools/filesystem/list.ts +33 -30
  794. package/src/tools/filesystem/read.ts +54 -35
  795. package/src/tools/filesystem/write.ts +34 -31
  796. package/src/tools/host-filesystem/edit.ts +44 -42
  797. package/src/tools/host-filesystem/read.ts +49 -35
  798. package/src/tools/host-filesystem/transfer.ts +121 -108
  799. package/src/tools/host-filesystem/write.ts +33 -31
  800. package/src/tools/host-terminal/host-shell.ts +50 -48
  801. package/src/tools/memory/register.ts +23 -24
  802. package/src/tools/network/web-fetch.ts +49 -46
  803. package/src/tools/network/web-search.ts +16 -13
  804. package/src/tools/registry.ts +39 -16
  805. package/src/tools/schedule/create.ts +11 -0
  806. package/src/tools/schedule/update.ts +16 -0
  807. package/src/tools/shared/filesystem/audio-read.ts +122 -0
  808. package/src/tools/shared/filesystem/image-read.ts +1 -1
  809. package/src/tools/skills/execute.ts +34 -31
  810. package/src/tools/skills/load.ts +29 -23
  811. package/src/tools/subagent/notify-parent.ts +35 -32
  812. package/src/tools/system/avatar-generator.ts +13 -22
  813. package/src/tools/system/request-permission.ts +30 -27
  814. package/src/tools/terminal/shell.ts +190 -61
  815. package/src/tools/tool-defaults.ts +20 -9
  816. package/src/tools/tool-manifest.ts +4 -4
  817. package/src/tools/types.ts +74 -23
  818. package/src/tools/ui-surface/definitions.ts +69 -9
  819. package/src/usage/types.ts +10 -0
  820. package/src/util/errors.ts +2 -2
  821. package/src/util/map-limit.ts +27 -0
  822. package/src/util/platform.ts +15 -12
  823. package/src/work-items/work-item-runner.ts +7 -2
  824. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +7 -20
  825. package/src/workspace/migrations/092-backfill-v3-leaves.ts +169 -0
  826. package/src/workspace/migrations/093-backfill-leaf-ids.ts +144 -0
  827. package/src/workspace/migrations/094-seed-avatar-manifest.ts +155 -0
  828. package/src/workspace/migrations/__tests__/094-seed-avatar-manifest.test.ts +136 -0
  829. package/src/workspace/migrations/__tests__/backfill-leaf-ids.test.ts +175 -0
  830. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +124 -0
  831. package/src/workspace/migrations/registry.ts +6 -0
  832. package/src/workspace/provider-commit-message-generator.ts +15 -17
  833. package/tsconfig.json +4 -1
  834. package/src/__tests__/history-repair-pipeline.test.ts +0 -396
  835. package/src/cli/commands/__tests__/memory-v3-render.test.ts +0 -340
  836. package/src/cli/commands/memory-v3-render.ts +0 -491
  837. package/src/daemon/message-types/disk-pressure.ts +0 -9
  838. package/src/email/feature-gate.ts +0 -23
  839. package/src/memory/v3/__tests__/coactivation-store.test.ts +0 -422
  840. package/src/memory/v3/__tests__/consolidation-job.test.ts +0 -466
  841. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +0 -270
  842. package/src/memory/v3/__tests__/edge-learning-job.test.ts +0 -324
  843. package/src/memory/v3/__tests__/edges.test.ts +0 -706
  844. package/src/memory/v3/__tests__/filter.test.ts +0 -560
  845. package/src/memory/v3/__tests__/gate.test.ts +0 -637
  846. package/src/memory/v3/__tests__/index-composition.test.ts +0 -291
  847. package/src/memory/v3/__tests__/loop.test.ts +0 -775
  848. package/src/memory/v3/__tests__/retriever.test.ts +0 -226
  849. package/src/memory/v3/__tests__/scouts.test.ts +0 -489
  850. package/src/memory/v3/__tests__/shadow-diff.test.ts +0 -225
  851. package/src/memory/v3/__tests__/shadow-middleware.test.ts +0 -398
  852. package/src/memory/v3/__tests__/system-prompts.test.ts +0 -154
  853. package/src/memory/v3/__tests__/traversal.test.ts +0 -508
  854. package/src/memory/v3/__tests__/tree-index.test.ts +0 -280
  855. package/src/memory/v3/__tests__/tree-store.test.ts +0 -529
  856. package/src/memory/v3/__tests__/tree-walk.test.ts +0 -784
  857. package/src/memory/v3/__tests__/validate.test.ts +0 -277
  858. package/src/memory/v3/auto-edges.ts +0 -223
  859. package/src/memory/v3/coactivation-store.ts +0 -124
  860. package/src/memory/v3/consolidation-job.ts +0 -323
  861. package/src/memory/v3/coretrieval-seed.ts +0 -240
  862. package/src/memory/v3/edge-learning-job.ts +0 -160
  863. package/src/memory/v3/edges.ts +0 -286
  864. package/src/memory/v3/filter.ts +0 -286
  865. package/src/memory/v3/gate.ts +0 -349
  866. package/src/memory/v3/index-composition.ts +0 -126
  867. package/src/memory/v3/llm-capture.ts +0 -46
  868. package/src/memory/v3/loop.ts +0 -430
  869. package/src/memory/v3/maintenance.ts +0 -144
  870. package/src/memory/v3/prompt-context.ts +0 -33
  871. package/src/memory/v3/prompts/consolidation.ts +0 -458
  872. package/src/memory/v3/prompts/system-prompts.ts +0 -196
  873. package/src/memory/v3/retriever.ts +0 -33
  874. package/src/memory/v3/scouts.ts +0 -431
  875. package/src/memory/v3/shadow-diff.ts +0 -287
  876. package/src/memory/v3/shadow-middleware.ts +0 -347
  877. package/src/memory/v3/traversal.ts +0 -211
  878. package/src/memory/v3/tree-index.ts +0 -237
  879. package/src/memory/v3/tree-store.ts +0 -394
  880. package/src/memory/v3/tree-walk.ts +0 -356
  881. package/src/memory/v3/validate.ts +0 -323
  882. package/src/plugins/defaults/circuit-breaker.ts +0 -141
  883. package/src/plugins/defaults/compaction.ts +0 -141
  884. package/src/plugins/defaults/empty-response.ts +0 -124
  885. package/src/plugins/defaults/history-repair.ts +0 -83
  886. package/src/plugins/defaults/persistence.ts +0 -146
  887. package/src/plugins/defaults/title-generate.ts +0 -90
  888. package/src/plugins/defaults/token-estimate.ts +0 -101
  889. package/src/plugins/defaults/tool-error.ts +0 -119
  890. package/src/plugins/defaults/tool-result-truncate.ts +0 -84
  891. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +0 -35
package/src/agent/loop.ts CHANGED
@@ -7,23 +7,34 @@ import {
7
7
  getCalibrationProviderKey,
8
8
  } from "../context/token-estimator.js";
9
9
  import { calculateMaxToolResultChars } from "../context/tool-result-truncation.js";
10
+ import type { ContextWindowResult } from "../context/window-manager.js";
10
11
  import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
11
- import { defaultEmptyResponseTerminal } from "../plugins/defaults/empty-response.js";
12
- import { defaultToolErrorTerminal } from "../plugins/defaults/tool-error.js";
13
- import { defaultToolResultTruncateTerminal } from "../plugins/defaults/tool-result-truncate.js";
12
+ import { defaultCompactionTerminal } from "../plugins/defaults/compaction/terminal.js";
13
+ import { defaultEmptyResponseTerminal } from "../plugins/defaults/empty-response/terminal.js";
14
+ import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate/terminal.js";
15
+ import { defaultToolErrorTerminal } from "../plugins/defaults/tool-error/terminal.js";
16
+ import { defaultToolResultTruncateTerminal } from "../plugins/defaults/tool-result-truncate/terminal.js";
17
+ import type {
18
+ ToolResultTruncateArgs,
19
+ ToolResultTruncateResult,
20
+ } from "../plugins/defaults/tool-result-truncate/types.js";
14
21
  import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
15
22
  import { getMiddlewaresFor } from "../plugins/registry.js";
16
23
  import type {
24
+ CompactionArgs,
25
+ CompactionCircuitEvent,
26
+ CompactionResult,
17
27
  EmptyResponseArgs,
18
28
  EmptyResponseDecision,
29
+ EstimateArgs,
30
+ EstimateResult,
19
31
  LLMCallArgs,
20
32
  LLMCallResult,
21
33
  ToolErrorArgs,
22
34
  ToolErrorDecision,
23
- ToolResultTruncateArgs,
24
- ToolResultTruncateResult,
25
35
  TurnContext,
26
36
  } from "../plugins/types.js";
37
+ import { PluginTimeoutError } from "../plugins/types.js";
27
38
  import { normalizeThinkingConfigForWire } from "../providers/thinking-config.js";
28
39
  import type {
29
40
  ContentBlock,
@@ -40,9 +51,17 @@ import {
40
51
  import { AssistantError, ErrorCode, ProviderError } from "../util/errors.js";
41
52
  import { getLogger } from "../util/logger.js";
42
53
  import { isRetryableNetworkError } from "../util/retry.js";
54
+ import { CompactionCircuit } from "./compaction-circuit.js";
43
55
 
44
56
  const log = getLogger("agent-loop");
45
57
 
58
+ /** Fraction of the preflight budget at which a checkpoint triggers mid-loop compaction. */
59
+ const MID_LOOP_YIELD_THRESHOLD_RATIO = 0.85;
60
+
61
+ /** In-context message count above which the budget gate raises the safety-margin floor. */
62
+ const LONG_HISTORY_MESSAGE_THRESHOLD = 50;
63
+ const LONG_HISTORY_SAFETY_MARGIN_FLOOR = 0.15;
64
+
46
65
  export interface AgentLoopConfig {
47
66
  maxTokens: number;
48
67
  maxInputTokens?: number; // context window size for tool result truncation
@@ -66,7 +85,28 @@ export interface CheckpointInfo {
66
85
  history: Message[]; // current history snapshot for token estimation
67
86
  }
68
87
 
69
- export type CheckpointDecision = "continue" | "yield";
88
+ /**
89
+ * Why a checkpoint paused the loop. Surfaced back to the caller via
90
+ * {@link AgentLoopRunResult.exitReason} so the orchestrator reacts to
91
+ * the loop's own signal (hand off to a queued message vs. compact and
92
+ * re-enter) instead of the checkpoint callback mutating orchestrator state.
93
+ */
94
+ export type ExitReason = "handoff" | "budget";
95
+
96
+ export type CheckpointDecision = "continue" | ExitReason;
97
+
98
+ /**
99
+ * Result of {@link AgentLoop.run}.
100
+ *
101
+ * `exitReason` carries the reason the loop paused at a checkpoint so the
102
+ * orchestrator reads the loop's own signal instead of inferring it from
103
+ * callback side-effects. It is `null` whenever the loop reached a terminal
104
+ * stop (completion, error, abort, or a tool-requested yield-to-user).
105
+ */
106
+ export interface AgentLoopRunResult {
107
+ history: Message[];
108
+ exitReason: ExitReason | null;
109
+ }
70
110
 
71
111
  /**
72
112
  * Why an agent turn reached a terminal state.
@@ -246,6 +286,24 @@ export type AgentEvent =
246
286
  */
247
287
  estimatedInputTokens?: number;
248
288
  }
289
+ | {
290
+ /**
291
+ * Emitted when the loop begins compacting the running history because
292
+ * the mid-loop budget gate tripped. The daemon's event dispatcher
293
+ * translates it into a "compacting context" activity state so clients
294
+ * surface that the turn paused to summarize context.
295
+ */
296
+ type: "context_compacting";
297
+ }
298
+ /**
299
+ * Circuit-breaker transitions emitted when auto-compaction is paused
300
+ * (`compaction_circuit_open`, after three consecutive summary-LLM
301
+ * failures) or resumed (`compaction_circuit_closed`). These are already
302
+ * in wire-contract shape; the daemon's event dispatcher forwards them to
303
+ * the client unchanged so the "auto-compaction paused" banner shows and
304
+ * dismisses.
305
+ */
306
+ | CompactionCircuitEvent
249
307
  | {
250
308
  /**
251
309
  * Emitted when an agent turn reaches a terminal state. Checkpoint
@@ -378,6 +436,86 @@ export interface ResolvedSystemPrompt {
378
436
  model?: string;
379
437
  }
380
438
 
439
+ /**
440
+ * Orchestrator-supplied hooks the loop invokes when the mid-loop budget gate
441
+ * trips and inline compaction runs. The loop owns the trigger, the
442
+ * `compaction` pipeline call, the result interpretation (circuit-breaker
443
+ * bookkeeping + the exhaustion decision), and the inline continue; these hooks
444
+ * bridge the durable / injection state the loop is intentionally blind to.
445
+ * Durable persistence ({@link applyResult}) and re-injection
446
+ * ({@link reinject}) remain orchestrator-supplied for now and are expected to
447
+ * move into the loop in a future change.
448
+ */
449
+ export interface MidLoopCompaction {
450
+ /** Strip runtime injections, commit stripped messages, and resolve pipeline options. */
451
+ prepare: (history: Message[]) => {
452
+ rawHistory: Message[];
453
+ options: CompactionArgs["options"];
454
+ };
455
+ /** Commit a successful compaction result to durable state. */
456
+ applyResult: (
457
+ result: ContextWindowResult,
458
+ rawHistory: Message[],
459
+ ) => Promise<void>;
460
+ /** Re-apply runtime injections and return the history to continue from. */
461
+ reinject: () => Promise<Message[]>;
462
+ }
463
+
464
+ export interface AgentLoopRunOptions {
465
+ signal?: AbortSignal;
466
+ requestId?: string;
467
+ onCheckpoint?: (
468
+ checkpoint: CheckpointInfo,
469
+ ) => CheckpointDecision | Promise<CheckpointDecision>;
470
+ callSite?: LLMCallSite;
471
+ /**
472
+ * Per-turn context supplied by the orchestrator. Every pipeline
473
+ * invocation inside the loop clones from this value (overwriting only
474
+ * `turnIndex`/`requestId`) so middleware sees the real conversation
475
+ * identity, trust class, and `contextWindowManager` rather than the
476
+ * `"agent-loop"` sentinel used when the loop is instantiated standalone
477
+ * in unit tests.
478
+ */
479
+ turnContext?: TurnContext;
480
+ /**
481
+ * Ad-hoc inference-profile override applied to every LLM call the loop
482
+ * issues. When set, each `SendMessageOptions.config` carries
483
+ * `overrideProfile = <name>` so the provider's resolver layers
484
+ * `llm.profiles[<name>]` between the workspace `activeProfile` and any
485
+ * call-site named profile. Missing profile names silently fall through.
486
+ */
487
+ overrideProfile?: string;
488
+ resolveOverrideProfile?: () => string | undefined;
489
+ /**
490
+ * Resolves the orchestrator's effective context window for this turn: the
491
+ * provider max-input-token ceiling (read by tool-result truncation) plus the
492
+ * `overflowRecovery` config that drives the mid-loop budget gate. Resolved
493
+ * fresh per checkpoint so a mid-turn profile change is reflected. Absent →
494
+ * truncation falls back to `this.config.maxInputTokens` and the budget gate
495
+ * is skipped (agent wakes pass `overflowRecovery.enabled = false`).
496
+ */
497
+ resolveContextWindow?: () => {
498
+ maxInputTokens: number;
499
+ overflowRecovery: { enabled: boolean; safetyMarginRatio: number };
500
+ };
501
+ /**
502
+ * Hooks for inline mid-loop compaction. When supplied and the budget gate
503
+ * trips, the loop compacts in place and continues instead of yielding
504
+ * `exitReason = "budget"`. Callers without a compaction path (agent wakes,
505
+ * convergence/auto-compress reruns) omit this and keep yielding for budget.
506
+ */
507
+ compaction?: MidLoopCompaction;
508
+ /**
509
+ * When true, the latest user message carries a volatile per-turn block
510
+ * (e.g. a memory-v3 `<memory>` injection) that varies across otherwise
511
+ * identical turns. Forwarded to each `SendMessageOptions.config` so the
512
+ * provider anchors its long-TTL cache breakpoint on the most recent STABLE
513
+ * user message instead of the volatile latest one, keeping the cached
514
+ * prefix reusable. Default unset → existing behavior.
515
+ */
516
+ mutableLatestUserMessage?: boolean;
517
+ }
518
+
381
519
  /**
382
520
  * Callback shape the loop uses to execute a tool invocation.
383
521
  *
@@ -425,6 +563,20 @@ export type LoopToolExecutor = (
425
563
  activityMetadata?: ToolActivityMetadata;
426
564
  }>;
427
565
 
566
+ export interface AgentLoopConstructorOptions {
567
+ config?: Partial<AgentLoopConfig>;
568
+ tools?: ToolDefinition[];
569
+ toolExecutor?: LoopToolExecutor;
570
+ resolveTools?: (history: Message[]) => ToolDefinition[];
571
+ resolveSystemPrompt?: (history: Message[]) => ResolvedSystemPrompt;
572
+ /**
573
+ * Conversation this loop drives. Used to scope the loop-held compaction
574
+ * circuit breaker; defaults to an empty key for test loops that never
575
+ * exercise compaction.
576
+ */
577
+ conversationId?: string;
578
+ }
579
+
428
580
  export class AgentLoop {
429
581
  private provider: Provider;
430
582
  private systemPrompt: string;
@@ -436,15 +588,28 @@ export class AgentLoop {
436
588
  | null;
437
589
  private toolExecutor: LoopToolExecutor | null;
438
590
 
591
+ /**
592
+ * Loop-held compaction circuit breaker. The loop has a 1:1 lifetime with its
593
+ * conversation, so it is the source of truth for the cross-turn failure
594
+ * counter and cooldown deadline. Non-loop callers (the orchestrator's
595
+ * compaction paths, `Conversation.forceCompact`, and the dev-only playground
596
+ * routes) reach it via `agentLoop.compactionCircuit`.
597
+ */
598
+ readonly compactionCircuit: CompactionCircuit;
599
+
439
600
  constructor(
440
601
  provider: Provider,
441
602
  systemPrompt: string,
442
- config?: Partial<AgentLoopConfig>,
443
- tools?: ToolDefinition[],
444
- toolExecutor?: LoopToolExecutor,
445
- resolveTools?: (history: Message[]) => ToolDefinition[],
446
- resolveSystemPrompt?: (history: Message[]) => ResolvedSystemPrompt,
603
+ options?: AgentLoopConstructorOptions,
447
604
  ) {
605
+ const {
606
+ config,
607
+ tools,
608
+ toolExecutor,
609
+ resolveTools,
610
+ resolveSystemPrompt,
611
+ conversationId,
612
+ } = options ?? {};
448
613
  this.provider = provider;
449
614
  this.systemPrompt = systemPrompt;
450
615
  this.config = { ...DEFAULT_CONFIG, ...config };
@@ -452,6 +617,7 @@ export class AgentLoop {
452
617
  this.resolveTools = resolveTools ?? null;
453
618
  this.resolveSystemPrompt = resolveSystemPrompt ?? null;
454
619
  this.toolExecutor = toolExecutor ?? null;
620
+ this.compactionCircuit = new CompactionCircuit(conversationId ?? "");
455
621
  }
456
622
 
457
623
  /**
@@ -481,44 +647,148 @@ export class AgentLoop {
481
647
  return estimateToolsTokens(this.getResolvedTools(history));
482
648
  }
483
649
 
650
+ /**
651
+ * Estimate total prompt tokens for `history` via the `tokenEstimate`
652
+ * pipeline. Args are shallow-frozen so a mutating middleware cannot strip
653
+ * context from the loop's live `history`.
654
+ */
655
+ private estimateTokens(
656
+ history: Message[],
657
+ turnContext: TurnContext,
658
+ ): Promise<EstimateResult> {
659
+ return runPipeline<EstimateArgs, EstimateResult>(
660
+ "tokenEstimate",
661
+ getMiddlewaresFor("tokenEstimate"),
662
+ defaultTokenEstimateTerminal,
663
+ {
664
+ history: Object.freeze([...history]) as Message[],
665
+ systemPrompt: this.systemPrompt,
666
+ tools: Object.freeze([
667
+ ...this.getResolvedTools(history),
668
+ ]) as ToolDefinition[],
669
+ providerName: getCalibrationProviderKey(this.provider),
670
+ },
671
+ turnContext,
672
+ DEFAULT_TIMEOUTS.tokenEstimate,
673
+ );
674
+ }
675
+
676
+ /**
677
+ * Record a compaction outcome against the loop's circuit breaker. Three
678
+ * consecutive failures trip a cooldown that suspends auto-compaction; a
679
+ * success resets the counter. Any open/closed transition is emitted on the
680
+ * loop's own event channel via `onEvent`.
681
+ *
682
+ * Bookkeeping is best-effort — a failure here must not turn a recoverable
683
+ * compaction outcome into a user-visible turn failure.
684
+ */
685
+ private async recordCompactionOutcome(
686
+ turnContext: TurnContext,
687
+ summaryFailed: boolean,
688
+ onEvent: (event: AgentEvent) => void | Promise<void>,
689
+ ): Promise<void> {
690
+ try {
691
+ await this.compactionCircuit.recordOutcome(
692
+ {
693
+ currentRequestId: turnContext.requestId,
694
+ currentTurnTrustContext: turnContext.trust,
695
+ turnCount: turnContext.turnIndex,
696
+ },
697
+ summaryFailed,
698
+ onEvent,
699
+ );
700
+ } catch (recordError) {
701
+ log.error(
702
+ { err: recordError, requestId: turnContext.requestId },
703
+ "Recording a compaction outcome against the circuit breaker failed; suppressing to keep the agent loop alive",
704
+ );
705
+ }
706
+ }
707
+
708
+ /**
709
+ * Compact the running history in place when the mid-loop budget gate trips.
710
+ *
711
+ * Runs the `compaction` pipeline natively (like {@link estimateTokens}) on
712
+ * the stripped history, then re-applies injections via the supplied hooks.
713
+ * Returns the history to continue from, or `null` when the compactor timed
714
+ * out or exhausted its retry budget so the caller yields
715
+ * `exitReason = "budget"` and the orchestrator escalates.
716
+ */
717
+ private async compact(
718
+ history: Message[],
719
+ turnContext: TurnContext,
720
+ compaction: MidLoopCompaction,
721
+ signal: AbortSignal | undefined,
722
+ onEvent: (event: AgentEvent) => void | Promise<void>,
723
+ ): Promise<Message[] | null> {
724
+ await onEvent({ type: "context_compacting" });
725
+ const { rawHistory, options } = compaction.prepare(history);
726
+ let result: CompactionResult;
727
+ try {
728
+ result = await runPipeline<CompactionArgs, CompactionResult>(
729
+ "compaction",
730
+ getMiddlewaresFor("compaction"),
731
+ (args) => defaultCompactionTerminal(args, turnContext),
732
+ { messages: rawHistory, signal, options },
733
+ turnContext,
734
+ DEFAULT_TIMEOUTS.compaction,
735
+ );
736
+ } catch (error) {
737
+ if (error instanceof PluginTimeoutError) {
738
+ // A timeout counts as a compaction failure against the circuit breaker.
739
+ await this.recordCompactionOutcome(turnContext, true, onEvent);
740
+ return null;
741
+ }
742
+ throw error;
743
+ }
744
+ // `CompactionResult` is intentionally `unknown` at the plugin boundary so
745
+ // plugin consumers don't import the window manager; the loop ran the
746
+ // pipeline, so it interprets the concrete result here.
747
+ const compactResult = result as ContextWindowResult;
748
+ // `force: true` bypasses the cooldown/threshold gates, but early returns
749
+ // for "no eligible messages" / "insufficient messages" still leave
750
+ // `summaryFailed` undefined. Only record an outcome when the summary LLM
751
+ // actually ran.
752
+ if (compactResult.summaryFailed !== undefined) {
753
+ await this.recordCompactionOutcome(
754
+ turnContext,
755
+ compactResult.summaryFailed,
756
+ onEvent,
757
+ );
758
+ }
759
+ if (compactResult.compacted) {
760
+ await compaction.applyResult(compactResult, rawHistory);
761
+ }
762
+ if (compactResult.exhausted ?? false) {
763
+ return null;
764
+ }
765
+ return compaction.reinject();
766
+ }
767
+
484
768
  async run(
485
769
  messages: Message[],
486
770
  onEvent: (event: AgentEvent) => void | Promise<void>,
487
- signal?: AbortSignal,
488
- requestId?: string,
489
- onCheckpoint?: (
490
- checkpoint: CheckpointInfo,
491
- ) => CheckpointDecision | Promise<CheckpointDecision>,
492
- callSite?: LLMCallSite,
493
- /**
494
- * Optional per-turn context supplied by the orchestrator. Every pipeline
495
- * invocation inside the loop clones from this value (overwriting only
496
- * `turnIndex`/`requestId`) so middleware sees the real conversation
497
- * identity, trust class, and `contextWindowManager` rather than the
498
- * `"agent-loop"` sentinel used when the loop is instantiated standalone
499
- * in unit tests.
500
- */
501
- turnContext?: TurnContext,
502
- /**
503
- * Optional ad-hoc inference-profile override applied to every LLM call
504
- * the loop issues. When set, each `SendMessageOptions.config` carries
505
- * `overrideProfile = <name>` so the provider's resolver layers
506
- * `llm.profiles[<name>]` between the workspace `activeProfile` and any
507
- * call-site named profile. Missing profile names silently fall through.
508
- * Used by per-conversation pinned profiles to override the workspace
509
- * default for the lifetime of an agent loop run.
510
- */
511
- overrideProfile?: string,
512
- effectiveMaxInputTokens?: number,
513
- resolveOverrideProfile?: () => string | undefined,
514
- resolveEffectiveMaxInputTokens?: () => number | undefined,
515
- ): Promise<Message[]> {
516
- const history = [...messages];
517
- const initialHistoryLength = messages.length;
771
+ options?: AgentLoopRunOptions,
772
+ ): Promise<AgentLoopRunResult> {
773
+ const {
774
+ signal,
775
+ requestId,
776
+ onCheckpoint,
777
+ callSite,
778
+ turnContext,
779
+ overrideProfile,
780
+ resolveOverrideProfile,
781
+ resolveContextWindow,
782
+ compaction,
783
+ mutableLatestUserMessage,
784
+ } = options ?? {};
785
+ let history = [...messages];
786
+ let producedVisibleTextThisRun = false;
518
787
  let toolUseTurns = 0;
519
788
  let consecutiveErrorTurns = 0;
520
789
  let emptyResponseRetries = 0;
521
790
  let lastLlmCallTime = 0;
791
+ let exitReason: ExitReason | null = null;
522
792
  const rlog = requestId ? log.child({ requestId }) : log;
523
793
 
524
794
  // Per-run substitution map for sensitive output placeholders.
@@ -617,6 +887,15 @@ export class AgentLoop {
617
887
  providerConfig.cacheTtl = this.config.cacheTtl;
618
888
  }
619
889
 
890
+ // Cache-anchor signal for volatile latest-user-message turns (e.g.
891
+ // memory-v3 injects its `<memory>` block into the latest user
892
+ // message). Not part of the call-site schema, so it is always sourced
893
+ // from the per-run option regardless of `callSite`. Only set when true
894
+ // so the wire/config stays byte-identical when off.
895
+ if (mutableLatestUserMessage) {
896
+ providerConfig.mutableLatestUserMessage = true;
897
+ }
898
+
620
899
  // Per-call LLM call-site identifier. Surfaces on the per-call
621
900
  // `config.callSite` so `RetryProvider.normalizeSendMessageOptions`
622
901
  // can route through `resolveCallSiteConfig` against
@@ -692,7 +971,7 @@ export class AgentLoop {
692
971
  // Also strip old AX tree snapshots to keep TTFT from growing
693
972
  // linearly with step count in computer-use sessions.
694
973
  const providerHistory = compactAxTreeHistory(
695
- stripOldImageBlocks(history),
974
+ stripOldMediaBlocks(history),
696
975
  );
697
976
 
698
977
  // Wrap the provider call in the `llmCall` pipeline so middleware
@@ -711,9 +990,9 @@ export class AgentLoop {
711
990
  const llmCallArgs: LLMCallArgs = {
712
991
  provider: this.provider,
713
992
  messages: providerHistory,
714
- tools: currentTools.length > 0 ? currentTools : undefined,
715
- systemPrompt: turnSystemPrompt,
716
993
  options: {
994
+ tools: currentTools.length > 0 ? currentTools : undefined,
995
+ systemPrompt: turnSystemPrompt,
717
996
  config: providerConfig,
718
997
  onEvent: (event) => {
719
998
  if (event.type === "text_delta") {
@@ -811,13 +1090,7 @@ export class AgentLoop {
811
1090
  response = await runPipeline<LLMCallArgs, LLMCallResult>(
812
1091
  "llmCall",
813
1092
  getMiddlewaresFor("llmCall"),
814
- (args) =>
815
- args.provider.sendMessage(
816
- args.messages,
817
- args.tools,
818
- args.systemPrompt,
819
- args.options,
820
- ),
1093
+ (args) => args.provider.sendMessage(args.messages, args.options),
821
1094
  llmCallArgs,
822
1095
  turnCtx,
823
1096
  DEFAULT_TIMEOUTS.llmCall,
@@ -839,8 +1112,8 @@ export class AgentLoop {
839
1112
  const rawRequest = {
840
1113
  provider: this.provider.name,
841
1114
  messages: llmCallArgs.messages,
842
- tools: llmCallArgs.tools,
843
- systemPrompt: llmCallArgs.systemPrompt,
1115
+ tools: llmCallArgs.options?.tools,
1116
+ systemPrompt: llmCallArgs.options?.systemPrompt,
844
1117
  config: llmCallArgs.options?.config,
845
1118
  };
846
1119
  onEvent({
@@ -972,25 +1245,20 @@ export class AgentLoop {
972
1245
  // The actual decision (nudge vs. accept vs. error) is delegated to
973
1246
  // the `emptyResponse` plugin pipeline. The pipeline returns a
974
1247
  // decision; the loop carries out the side-effect (pushing the nudge
975
- // or surfacing the error). See `plugins/defaults/empty-response.ts`
1248
+ // or surfacing the error). See `plugins/defaults/empty-response/register.ts`
976
1249
  // for the default decision logic.
977
1250
  const hasVisibleText = response.content.some(
978
1251
  (block) => block.type === "text" && block.text.trim().length > 0,
979
1252
  );
980
- const priorAssistantHadVisibleText = (() => {
981
- for (let i = history.length - 1; i >= initialHistoryLength; i--) {
982
- const msg = history[i];
983
- if (msg.role !== "assistant") continue;
984
- const hasText = msg.content.some(
985
- (block) =>
986
- block.type === "text" &&
987
- typeof (block as { text?: unknown }).text === "string" &&
988
- (block as { text: string }).text.trim().length > 0,
989
- );
990
- if (hasText) return true;
991
- }
992
- return false;
993
- })();
1253
+ // Track whether the model produced visible text earlier in this
1254
+ // run() invocation. Run-scoped rather than derived from `history` so
1255
+ // it survives inline compaction rewriting the message array: an empty
1256
+ // completion after a compaction must not be nudged into re-sending
1257
+ // text the user already saw.
1258
+ const priorAssistantHadVisibleText = producedVisibleTextThisRun;
1259
+ if (hasVisibleText) {
1260
+ producedVisibleTextThisRun = true;
1261
+ }
994
1262
 
995
1263
  const emptyResponseArgs: EmptyResponseArgs = {
996
1264
  responseContent: response.content,
@@ -999,6 +1267,7 @@ export class AgentLoop {
999
1267
  emptyResponseRetries,
1000
1268
  maxEmptyResponseRetries: MAX_EMPTY_RESPONSE_RETRIES,
1001
1269
  priorAssistantHadVisibleText,
1270
+ stopReason: response.stopReason,
1002
1271
  };
1003
1272
  const emptyResponseCtx = resolveLoopTurnContext(
1004
1273
  turnContext,
@@ -1201,8 +1470,7 @@ export class AgentLoop {
1201
1470
  // truncation strategy (e.g. a summariser) while the default
1202
1471
  // middleware preserves the historical tail-drop behaviour.
1203
1472
  const contextWindowTokens =
1204
- resolveEffectiveMaxInputTokens?.() ??
1205
- effectiveMaxInputTokens ??
1473
+ resolveContextWindow?.().maxInputTokens ??
1206
1474
  this.config.maxInputTokens ??
1207
1475
  180_000;
1208
1476
  const maxChars = calculateMaxToolResultChars(contextWindowTokens);
@@ -1352,8 +1620,8 @@ export class AgentLoop {
1352
1620
  history.push({ role: "user", content: resultBlocks });
1353
1621
 
1354
1622
  // Invoke checkpoint callback after tool results are in history.
1355
- // The callback may be async the mid-loop budget check delegates
1356
- // to the `tokenEstimate` plugin pipeline, which is asynchronous.
1623
+ // Handoff is offered first so a queued message takes precedence over
1624
+ // the mid-loop budget yield below.
1357
1625
  if (onCheckpoint) {
1358
1626
  const decision = await onCheckpoint({
1359
1627
  turnIndex: toolUseTurns - 1, // 0-based (toolUseTurns was already incremented)
@@ -1361,7 +1629,60 @@ export class AgentLoop {
1361
1629
  hasToolUse: true,
1362
1630
  history,
1363
1631
  });
1364
- if (decision === "yield") {
1632
+ if (decision !== "continue") {
1633
+ exitReason = decision;
1634
+ break;
1635
+ }
1636
+ }
1637
+
1638
+ // Mid-loop budget gate: when overflow recovery is enabled, estimate
1639
+ // the running context size as it approaches the preflight budget.
1640
+ // With a `compaction` hook the loop compacts in place and continues;
1641
+ // without one it yields (`exitReason = "budget"`) so the orchestrator
1642
+ // can recover before the next provider call risks a hard
1643
+ // context-too-large rejection. Keyed off the loop's own
1644
+ // `history.length` (the messages actually in context this turn,
1645
+ // including tool iterations) rather than the durable conversation
1646
+ // count.
1647
+ const contextWindow = resolveContextWindow?.();
1648
+ if (contextWindow?.overflowRecovery.enabled) {
1649
+ const { maxInputTokens, overflowRecovery } = contextWindow;
1650
+ const safetyMargin =
1651
+ history.length > LONG_HISTORY_MESSAGE_THRESHOLD
1652
+ ? Math.max(
1653
+ overflowRecovery.safetyMarginRatio,
1654
+ LONG_HISTORY_SAFETY_MARGIN_FLOOR,
1655
+ )
1656
+ : overflowRecovery.safetyMarginRatio;
1657
+ const preflightBudget = Math.floor(
1658
+ maxInputTokens * (1 - safetyMargin),
1659
+ );
1660
+ const midLoopThreshold =
1661
+ preflightBudget * MID_LOOP_YIELD_THRESHOLD_RATIO;
1662
+ const estimated = await this.estimateTokens(history, turnCtx);
1663
+ if (estimated > midLoopThreshold) {
1664
+ if (compaction) {
1665
+ rlog.info(
1666
+ { phase: "mid-loop", estimated, threshold: midLoopThreshold },
1667
+ "Token estimate approaching budget — compacting in place",
1668
+ );
1669
+ const compacted = await this.compact(
1670
+ history,
1671
+ turnCtx,
1672
+ compaction,
1673
+ signal,
1674
+ onEvent,
1675
+ );
1676
+ if (compacted) {
1677
+ history = compacted;
1678
+ continue;
1679
+ }
1680
+ }
1681
+ rlog.warn(
1682
+ { phase: "mid-loop", estimated, threshold: midLoopThreshold },
1683
+ "Token estimate approaching budget — yielding for compaction",
1684
+ );
1685
+ exitReason = "budget";
1365
1686
  break;
1366
1687
  }
1367
1688
  }
@@ -1412,7 +1733,7 @@ export class AgentLoop {
1412
1733
  "Agent loop exited",
1413
1734
  );
1414
1735
 
1415
- return history;
1736
+ return { history, exitReason };
1416
1737
  }
1417
1738
  }
1418
1739
 
@@ -1513,7 +1834,7 @@ export function compactAxTreeHistory(messages: Message[]): Message[] {
1513
1834
  * turn. Using the last user message unconditionally would leave the most
1514
1835
  * recent tool screenshots unprotected from stripping.
1515
1836
  */
1516
- function stripOldImageBlocks(history: Message[]): Message[] {
1837
+ function stripOldMediaBlocks(history: Message[]): Message[] {
1517
1838
  // Find the last user message that contains tool_result blocks.
1518
1839
  let lastToolResultUserIdx = -1;
1519
1840
  for (let i = history.length - 1; i >= 0; i--) {
@@ -1530,29 +1851,32 @@ function stripOldImageBlocks(history: Message[]): Message[] {
1530
1851
  // Keep the most recent tool-result user message intact (current turn)
1531
1852
  if (idx === lastToolResultUserIdx || msg.role !== "user") return msg;
1532
1853
 
1533
- // Check if any tool_result blocks have image contentBlocks
1534
- const hasImages = msg.content.some(
1854
+ // Check if any tool_result blocks carry embedded media (image or audio).
1855
+ const isMedia = (cb: ContentBlock) =>
1856
+ cb.type === "image" || cb.type === "file";
1857
+ const hasMedia = msg.content.some(
1535
1858
  (b) =>
1536
1859
  b.type === "tool_result" &&
1537
- (b as ToolResultContent).contentBlocks?.some(
1538
- (cb) => cb.type === "image",
1539
- ),
1860
+ (b as ToolResultContent).contentBlocks?.some(isMedia),
1540
1861
  );
1541
- if (!hasImages) return msg;
1862
+ if (!hasMedia) return msg;
1542
1863
 
1543
- // Strip images from tool_result blocks, replacing with text marker
1864
+ // Strip media from tool_result blocks, replacing with a text marker. The
1865
+ // model already saw/heard the media in the turn it was captured; resending
1866
+ // the bytes every turn (a 12 MB audio clip isn't optimized like images)
1867
+ // bloats the request until compaction.
1544
1868
  return {
1545
1869
  ...msg,
1546
1870
  content: msg.content.map((b) => {
1547
1871
  if (b.type !== "tool_result") return b;
1548
1872
  const tr = b as ToolResultContent;
1549
- if (!tr.contentBlocks?.some((cb) => cb.type === "image")) return b;
1873
+ if (!tr.contentBlocks?.some(isMedia)) return b;
1550
1874
  return {
1551
1875
  ...tr,
1552
1876
  contentBlocks: undefined,
1553
1877
  content:
1554
1878
  (tr.content || "") +
1555
- "\n[Screenshot was captured and shown previously — image data removed to save context.]",
1879
+ "\n[Media (image/audio) was captured and shown previously — binary data removed to save context.]",
1556
1880
  };
1557
1881
  }),
1558
1882
  };