@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
@@ -1,13 +1,25 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
3
3
 
4
+ import { CompactionCircuit } from "../agent/compaction-circuit.js";
4
5
  import type {
5
6
  AgentEvent,
6
- CheckpointDecision,
7
- CheckpointInfo,
7
+ AgentLoopRunOptions,
8
+ AgentLoopRunResult,
9
+ MidLoopCompaction,
8
10
  } from "../agent/loop.js";
11
+ import type { ContextWindowResult } from "../context/window-manager.js";
9
12
  import type { ServerMessage } from "../daemon/message-protocol.js";
13
+ import { defaultCompactionTerminal } from "../plugins/defaults/compaction/terminal.js";
10
14
  import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
15
+ import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
16
+ import { getMiddlewaresFor } from "../plugins/registry.js";
17
+ import type {
18
+ CompactionArgs,
19
+ CompactionResult,
20
+ TurnContext,
21
+ } from "../plugins/types.js";
22
+ import { PluginTimeoutError } from "../plugins/types.js";
11
23
  import type { ContentBlock, Message } from "../providers/types.js";
12
24
 
13
25
  const conversationCrudRealSnapshot = {
@@ -407,7 +419,7 @@ mock.module("../daemon/date-context.js", () => ({
407
419
  resolveTurnTimezoneContext: resolveTurnTimezoneContextMock,
408
420
  }));
409
421
 
410
- mock.module("../daemon/history-repair.js", () => ({
422
+ mock.module("../plugins/defaults/history-repair/terminal.js", () => ({
411
423
  repairHistory: (msgs: Message[]) => ({
412
424
  messages: msgs,
413
425
  stats: {
@@ -548,13 +560,149 @@ import {
548
560
  type AgentLoopRun = (
549
561
  messages: Message[],
550
562
  onEvent: (event: AgentEvent) => void | Promise<void>,
551
- signal?: AbortSignal,
552
- requestId?: string,
553
- onCheckpoint?: (
554
- checkpoint: CheckpointInfo,
555
- ) => CheckpointDecision | Promise<CheckpointDecision>,
563
+ options?: AgentLoopRunOptions,
556
564
  ) => Promise<Message[]>;
557
565
 
566
+ /**
567
+ * Faithful re-implementation of `AgentLoop.compact()` for the mock loop: run
568
+ * the compaction pipeline against the supplied turn context (which carries the
569
+ * test's `contextWindowManager`), invoke the orchestrator-supplied hooks, and
570
+ * return the continuation history — or `null` on timeout/exhaustion so the
571
+ * caller yields "budget".
572
+ */
573
+ async function simulateInlineCompaction(
574
+ compaction: MidLoopCompaction,
575
+ history: Message[],
576
+ turnContext: TurnContext | undefined,
577
+ signal: AbortSignal | undefined,
578
+ onEvent: (event: AgentEvent) => void | Promise<void>,
579
+ compactionCircuit: CompactionCircuit,
580
+ ): Promise<Message[] | null> {
581
+ await onEvent({ type: "context_compacting" });
582
+ const { rawHistory, options } = compaction.prepare(history);
583
+ let result: CompactionResult;
584
+ try {
585
+ result = await runPipeline<CompactionArgs, CompactionResult>(
586
+ "compaction",
587
+ getMiddlewaresFor("compaction"),
588
+ (args) => defaultCompactionTerminal(args, turnContext as TurnContext),
589
+ { messages: rawHistory, signal, options },
590
+ turnContext as TurnContext,
591
+ DEFAULT_TIMEOUTS.compaction,
592
+ );
593
+ } catch (error) {
594
+ if (error instanceof PluginTimeoutError) {
595
+ await compactionCircuit.recordOutcome(
596
+ {
597
+ currentRequestId: turnContext?.requestId,
598
+ currentTurnTrustContext: turnContext?.trust,
599
+ turnCount: turnContext?.turnIndex ?? 0,
600
+ },
601
+ true,
602
+ onEvent,
603
+ );
604
+ return null;
605
+ }
606
+ throw error;
607
+ }
608
+ const compactResult = result as ContextWindowResult;
609
+ if (compactResult.summaryFailed !== undefined) {
610
+ await compactionCircuit.recordOutcome(
611
+ {
612
+ currentRequestId: turnContext?.requestId,
613
+ currentTurnTrustContext: turnContext?.trust,
614
+ turnCount: turnContext?.turnIndex ?? 0,
615
+ },
616
+ compactResult.summaryFailed,
617
+ onEvent,
618
+ );
619
+ }
620
+ if (compactResult.compacted) {
621
+ await compaction.applyResult(compactResult, rawHistory);
622
+ }
623
+ if (compactResult.exhausted ?? false) {
624
+ return null;
625
+ }
626
+ return compaction.reinject();
627
+ }
628
+
629
+ /**
630
+ * Adapt a `Message[]`-returning mock loop body into `run()`'s real result
631
+ * shape. Mirrors the production loop: the pause-reason carried back is
632
+ * whatever the most recent `onCheckpoint` call yielded with (null when it
633
+ * never yielded), so the orchestrator derives its yield bookkeeping the same
634
+ * way it does against the real loop.
635
+ */
636
+ const asAgentLoopRun = (
637
+ fn: AgentLoopRun,
638
+ compactionCircuit: CompactionCircuit,
639
+ ): ((
640
+ messages: Message[],
641
+ onEvent: (event: AgentEvent) => void | Promise<void>,
642
+ options?: AgentLoopRunOptions,
643
+ ) => Promise<AgentLoopRunResult>) => {
644
+ return async (messages, onEvent, options) => {
645
+ let exitReason: AgentLoopRunResult["exitReason"] = null;
646
+ let wrapped = options;
647
+ if (options?.onCheckpoint) {
648
+ const inner = options.onCheckpoint;
649
+ wrapped = {
650
+ ...options,
651
+ onCheckpoint: async (info) => {
652
+ // Handoff is offered first, mirroring the loop's ordering.
653
+ const decision = await inner(info);
654
+ if (decision !== "continue") {
655
+ exitReason = decision;
656
+ return decision;
657
+ }
658
+ // The mid-loop budget gate and inline compaction both live inside
659
+ // `AgentLoop.run`. Replicate them here — same formula, stubbed
660
+ // estimator, and the loop's own `compact()` ceremony — so these
661
+ // orchestrator tests drive the real escalation path now that the
662
+ // orchestrator's `onCheckpoint` is handoff-only and compaction runs
663
+ // inline rather than via an orchestrator re-entry loop.
664
+ const contextWindow = options.resolveContextWindow?.();
665
+ if (contextWindow?.overflowRecovery.enabled) {
666
+ const { maxInputTokens, overflowRecovery } = contextWindow;
667
+ const safetyMargin =
668
+ info.history.length > 50
669
+ ? Math.max(overflowRecovery.safetyMarginRatio, 0.15)
670
+ : overflowRecovery.safetyMarginRatio;
671
+ const preflightBudget = Math.floor(
672
+ maxInputTokens * (1 - safetyMargin),
673
+ );
674
+ if (mockEstimateTokens > preflightBudget * 0.85) {
675
+ // Mirror `AgentLoop.compact()`: when a compaction path is
676
+ // supplied, run it in place and continue; on timeout or
677
+ // exhaustion it returns null, so the loop yields "budget".
678
+ const compacted = options.compaction
679
+ ? await simulateInlineCompaction(
680
+ options.compaction,
681
+ info.history,
682
+ options.turnContext,
683
+ options.signal,
684
+ onEvent,
685
+ compactionCircuit,
686
+ )
687
+ : null;
688
+ if (compacted) {
689
+ exitReason = null;
690
+ return "continue";
691
+ }
692
+ exitReason = "budget";
693
+ return "budget";
694
+ }
695
+ }
696
+ exitReason = null;
697
+ return "continue";
698
+ },
699
+ };
700
+ }
701
+ const history = await fn(messages, onEvent, wrapped);
702
+ return { history, exitReason };
703
+ };
704
+ };
705
+
558
706
  function makeCtx(
559
707
  overrides?: Partial<AgentLoopConversationContext> & {
560
708
  agentLoopRun?: AgentLoopRun;
@@ -570,6 +718,8 @@ function makeCtx(
570
718
  },
571
719
  ]);
572
720
 
721
+ const compactionCircuit = new CompactionCircuit("test-conv");
722
+
573
723
  return {
574
724
  conversationId: "test-conv",
575
725
  messages: [
@@ -580,12 +730,13 @@ function makeCtx(
580
730
  currentRequestId: "test-req",
581
731
 
582
732
  agentLoop: {
583
- run: agentLoopRun,
733
+ run: asAgentLoopRun(agentLoopRun, compactionCircuit),
584
734
  getToolTokenBudget: () => 0,
585
735
  getResolvedTools: () => [],
586
736
  // Tests here don't exercise calibration; returning undefined makes
587
737
  // the estimator use the per-provider aggregate key.
588
738
  getActiveModel: () => undefined,
739
+ compactionCircuit,
589
740
  } as unknown as AgentLoopConversationContext["agentLoop"],
590
741
  provider: {
591
742
  name: "mock-provider",
@@ -805,7 +956,7 @@ describe("session-agent-loop", () => {
805
956
  });
806
957
 
807
958
  describe("proactive artifact trigger", () => {
808
- test("suppresses proactive app build when the foreground turn used app tools", async () => {
959
+ test("does not start proactive artifact jobs after foreground user turns", async () => {
809
960
  mockConversationRow = {
810
961
  ...mockConversationRow,
811
962
  id: "test-conv",
@@ -819,13 +970,7 @@ describe("session-agent-loop", () => {
819
970
  mockHasProactiveArtifactCompleted = false;
820
971
  mockTryClaimProactiveArtifactTrigger = true;
821
972
 
822
- const agentLoopRun: AgentLoopRun = async (
823
- messages,
824
- onEvent,
825
- _signal,
826
- _requestId,
827
- onCheckpoint,
828
- ) => {
973
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent, options) => {
829
974
  // Prime the assistant row anchor for LLM call 1 — production code
830
975
  // emits this from `AgentLoop.run` just before `provider.sendMessage`.
831
976
  await onEvent({ type: "llm_call_started" });
@@ -848,7 +993,7 @@ describe("session-agent-loop", () => {
848
993
  content: "{}",
849
994
  isError: false,
850
995
  });
851
- await onCheckpoint?.({
996
+ await options?.onCheckpoint?.({
852
997
  turnIndex: 0,
853
998
  toolCount: 1,
854
999
  hasToolUse: true,
@@ -888,11 +1033,7 @@ describe("session-agent-loop", () => {
888
1033
  );
889
1034
  await new Promise((resolve) => setTimeout(resolve, 0));
890
1035
 
891
- expect(runProactiveArtifactJobMock).toHaveBeenCalledTimes(1);
892
- expect(runProactiveArtifactJobMock.mock.calls[0]?.[0]).toMatchObject({
893
- conversationId: "test-conv",
894
- suppressAppBuild: true,
895
- });
1036
+ expect(runProactiveArtifactJobMock).toHaveBeenCalledTimes(0);
896
1037
  });
897
1038
  });
898
1039
 
@@ -1030,7 +1171,10 @@ describe("session-agent-loop", () => {
1030
1171
  },
1031
1172
  } as unknown as AgentLoopConversationContext["traceEmitter"],
1032
1173
  });
1033
- ctx.agentLoop.run = agentLoopRun as AgentLoopRun;
1174
+ ctx.agentLoop.run = asAgentLoopRun(
1175
+ agentLoopRun,
1176
+ ctx.agentLoop.compactionCircuit,
1177
+ );
1034
1178
 
1035
1179
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
1036
1180
 
@@ -1039,8 +1183,7 @@ describe("session-agent-loop", () => {
1039
1183
  expect(activityStates).toContainEqual([
1040
1184
  "idle",
1041
1185
  "error_terminal",
1042
- "global",
1043
- "test-req",
1186
+ { anchor: "global", requestId: "test-req" },
1044
1187
  ]);
1045
1188
  expect(traceEvents[0]).toEqual([
1046
1189
  "request_error",
@@ -1102,8 +1245,7 @@ describe("session-agent-loop", () => {
1102
1245
  expect(activityStates).toContainEqual([
1103
1246
  "idle",
1104
1247
  "error_terminal",
1105
- "global",
1106
- "test-req",
1248
+ { anchor: "global", requestId: "test-req" },
1107
1249
  ]);
1108
1250
  });
1109
1251
  });
@@ -2150,13 +2292,7 @@ describe("session-agent-loop", () => {
2150
2292
  // call). 90k satisfies both so the path reaches call 3.
2151
2293
  mockEstimateTokens = 90_000;
2152
2294
 
2153
- const agentLoopRun: AgentLoopRun = async (
2154
- messages,
2155
- onEvent,
2156
- _signal,
2157
- _reqId,
2158
- onCheckpoint,
2159
- ) => {
2295
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent, options) => {
2160
2296
  callCount++;
2161
2297
  if (callCount <= 2) {
2162
2298
  // Calls 1 (initial) and 2 (convergence rerun): error so
@@ -2180,8 +2316,8 @@ describe("session-agent-loop", () => {
2180
2316
  // flips `yieldedForBudget` to true, then return without
2181
2317
  // finishing — mirroring what AgentLoop.run does when its
2182
2318
  // checkpoint returns "yield".
2183
- if (onCheckpoint) {
2184
- await onCheckpoint({
2319
+ if (options?.onCheckpoint) {
2320
+ await options.onCheckpoint({
2185
2321
  turnIndex: 0,
2186
2322
  toolCount: 1,
2187
2323
  hasToolUse: true,
@@ -2461,13 +2597,7 @@ describe("session-agent-loop", () => {
2461
2597
  test("yields at checkpoint when canHandoffAtCheckpoint returns true", async () => {
2462
2598
  const events: ServerMessage[] = [];
2463
2599
 
2464
- const agentLoopRun: AgentLoopRun = async (
2465
- messages,
2466
- onEvent,
2467
- _signal,
2468
- _reqId,
2469
- onCheckpoint,
2470
- ) => {
2600
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent, options) => {
2471
2601
  // Prime the assistant row anchor — production code emits this from
2472
2602
  // `AgentLoop.run` just before `provider.sendMessage`. Retry branches
2473
2603
  // need this on every invocation: each agent-loop iteration reserves
@@ -2495,14 +2625,14 @@ describe("session-agent-loop", () => {
2495
2625
  model: "test-model",
2496
2626
  providerDurationMs: 100,
2497
2627
  });
2498
- if (onCheckpoint) {
2499
- const decision = await onCheckpoint({
2628
+ if (options?.onCheckpoint) {
2629
+ const decision = await options.onCheckpoint({
2500
2630
  turnIndex: 0,
2501
2631
  toolCount: 1,
2502
2632
  hasToolUse: true,
2503
2633
  history: messages,
2504
2634
  });
2505
- if (decision === "yield") {
2635
+ if (decision !== "continue") {
2506
2636
  return [
2507
2637
  ...messages,
2508
2638
  {
@@ -2539,13 +2669,7 @@ describe("session-agent-loop", () => {
2539
2669
  test("continues when canHandoffAtCheckpoint returns false", async () => {
2540
2670
  const events: ServerMessage[] = [];
2541
2671
 
2542
- const agentLoopRun: AgentLoopRun = async (
2543
- messages,
2544
- onEvent,
2545
- _signal,
2546
- _reqId,
2547
- onCheckpoint,
2548
- ) => {
2672
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent, options) => {
2549
2673
  // Prime the assistant row anchor — production code emits this from
2550
2674
  // `AgentLoop.run` just before `provider.sendMessage`. Retry branches
2551
2675
  // need this on every invocation: each agent-loop iteration reserves
@@ -2572,8 +2696,8 @@ describe("session-agent-loop", () => {
2572
2696
  model: "test-model",
2573
2697
  providerDurationMs: 100,
2574
2698
  });
2575
- if (onCheckpoint) {
2576
- await onCheckpoint({
2699
+ if (options?.onCheckpoint) {
2700
+ await options.onCheckpoint({
2577
2701
  turnIndex: 0,
2578
2702
  toolCount: 1,
2579
2703
  hasToolUse: true,
@@ -3444,6 +3568,400 @@ describe("session-agent-loop", () => {
3444
3568
  });
3445
3569
  });
3446
3570
 
3571
+ describe("partial persistence", () => {
3572
+ // The legacy flow reserves an empty assistant row at `llm_call_started`
3573
+ // (`content: "[]"`) and never touches it again until
3574
+ // `handleMessageComplete` fires the single authoritative
3575
+ // `updateContent`. Between those events the row is empty for the full
3576
+ // duration of a turn — a browser refresh mid-turn sees nothing where
3577
+ // the in-progress assistant reply should be.
3578
+ //
3579
+ // Partial persistence closes that durability gap with a debounced
3580
+ // flush from `handleTextDelta` (250ms timer). `handleToolUse`
3581
+ // intentionally does NOT flush — `AgentLoop.run` emits `tool_use`
3582
+ // strictly AFTER `message_complete`, so any flush from that handler
3583
+ // would land after the authoritative finalize and overwrite the
3584
+ // finalized row. The indexer + projector still fire ONLY at
3585
+ // `message_complete` — partial rows are never indexed.
3586
+ //
3587
+ // These tests pin down the wire-level contract by counting
3588
+ // `updateMessageContent` calls and inspecting the JSON payload of the
3589
+ // partial-flush writes. The indexing / sync-invalidation paths are
3590
+ // covered by the pre-allocation block above.
3591
+
3592
+ test("debounced time gate flushes one partial write after PARTIAL_PERSIST_DEBOUNCE_MS", async () => {
3593
+ mockMessageById = {
3594
+ id: "msg-reserve",
3595
+ conversationId: "test-conv",
3596
+ createdAt: 1234567,
3597
+ role: "assistant",
3598
+ content: "[]",
3599
+ metadata: null,
3600
+ };
3601
+
3602
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3603
+ await onEvent({ type: "llm_call_started" });
3604
+ // Two small deltas — well under the 1024-char size gate — should
3605
+ // schedule a single debounced flush.
3606
+ onEvent({ type: "text_delta", text: "Hello, " });
3607
+ onEvent({ type: "text_delta", text: "world." });
3608
+ // Wait long enough for the 250ms debounce to fire.
3609
+ await new Promise((resolve) => setTimeout(resolve, 1100));
3610
+ await onEvent({
3611
+ type: "message_complete",
3612
+ message: {
3613
+ role: "assistant",
3614
+ content: [{ type: "text", text: "Hello, world." }],
3615
+ },
3616
+ });
3617
+ onEvent({
3618
+ type: "usage",
3619
+ inputTokens: 10,
3620
+ outputTokens: 5,
3621
+ model: "test",
3622
+ providerDurationMs: 50,
3623
+ });
3624
+ return [
3625
+ ...messages,
3626
+ {
3627
+ role: "assistant" as const,
3628
+ content: [
3629
+ { type: "text", text: "Hello, world." },
3630
+ ] as ContentBlock[],
3631
+ },
3632
+ ];
3633
+ };
3634
+
3635
+ const ctx = makeCtx({ agentLoopRun });
3636
+ await runAgentLoopImpl(ctx, "hi", "msg-1", () => {});
3637
+
3638
+ // Exactly two `updateContent` calls land:
3639
+ // 1. the debounced partial flush after both deltas accumulated, and
3640
+ // 2. the final authoritative flush in `handleMessageComplete`.
3641
+ // Without the debounce gate this would be one-per-delta + one final
3642
+ // (3). Without the partial flush at all it would be just 1.
3643
+ expect(updateMessageContentMock).toHaveBeenCalledTimes(2);
3644
+ const calls = updateMessageContentMock.mock.calls as unknown as Array<
3645
+ [string, string]
3646
+ >;
3647
+ const partialFlush = calls[0];
3648
+ expect(partialFlush?.[0]).toBe("msg-reserve");
3649
+ const partialBlocks = JSON.parse(partialFlush?.[1] ?? "[]") as Array<{
3650
+ type: string;
3651
+ text?: string;
3652
+ }>;
3653
+ expect(partialBlocks).toEqual([{ type: "text", text: "Hello, world." }]);
3654
+ });
3655
+
3656
+ test("handleToolUse does NOT trigger a partial flush of its own", async () => {
3657
+ // `AgentLoop.run` emits `tool_use` strictly AFTER `message_complete`,
3658
+ // so a flush from the tool_use handler would land after the
3659
+ // authoritative final `updateContent` and overwrite the finalized
3660
+ // row (Codex P1 / Vargas review feedback). The handler must be a
3661
+ // no-op for the partial-persist accumulator.
3662
+ mockMessageById = {
3663
+ id: "msg-reserve",
3664
+ conversationId: "test-conv",
3665
+ createdAt: 1234567,
3666
+ role: "assistant",
3667
+ content: "[]",
3668
+ metadata: null,
3669
+ };
3670
+
3671
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3672
+ await onEvent({ type: "llm_call_started" });
3673
+ // No text delta — only a tool_use. If `handleToolUse` were
3674
+ // flushing, this would land a partial write before
3675
+ // `message_complete`.
3676
+ onEvent({
3677
+ type: "tool_use",
3678
+ id: "tu-no-flush",
3679
+ name: "file_read",
3680
+ input: { path: "/foo" },
3681
+ });
3682
+ // Yield a microtask so any (incorrectly) fire-and-forget
3683
+ // pipeline call has a chance to land before message_complete.
3684
+ await new Promise((resolve) => setImmediate(resolve));
3685
+ onEvent({
3686
+ type: "tool_result",
3687
+ toolUseId: "tu-no-flush",
3688
+ content: "ok",
3689
+ isError: false,
3690
+ });
3691
+ await onEvent({
3692
+ type: "message_complete",
3693
+ message: {
3694
+ role: "assistant",
3695
+ content: [
3696
+ {
3697
+ type: "tool_use",
3698
+ id: "tu-no-flush",
3699
+ name: "file_read",
3700
+ input: { path: "/foo" },
3701
+ },
3702
+ ],
3703
+ },
3704
+ });
3705
+ onEvent({
3706
+ type: "usage",
3707
+ inputTokens: 10,
3708
+ outputTokens: 5,
3709
+ model: "test",
3710
+ providerDurationMs: 50,
3711
+ });
3712
+ return [
3713
+ ...messages,
3714
+ {
3715
+ role: "assistant" as const,
3716
+ content: [
3717
+ {
3718
+ type: "tool_use",
3719
+ id: "tu-no-flush",
3720
+ name: "file_read",
3721
+ input: { path: "/foo" },
3722
+ },
3723
+ ] as ContentBlock[],
3724
+ },
3725
+ ];
3726
+ };
3727
+
3728
+ const ctx = makeCtx({ agentLoopRun });
3729
+ await runAgentLoopImpl(ctx, "hi", "msg-1", () => {});
3730
+
3731
+ // Only the authoritative final flush from `handleMessageComplete`
3732
+ // lands. A partial flush from `handleToolUse` would have made this
3733
+ // 2; that's the regression this test guards against.
3734
+ expect(updateMessageContentMock).toHaveBeenCalledTimes(1);
3735
+ });
3736
+
3737
+ test("handleMessageComplete clears any pending debounce timer before the final flush", async () => {
3738
+ mockMessageById = {
3739
+ id: "msg-reserve",
3740
+ conversationId: "test-conv",
3741
+ createdAt: 1234567,
3742
+ role: "assistant",
3743
+ content: "[]",
3744
+ metadata: null,
3745
+ };
3746
+
3747
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3748
+ await onEvent({ type: "llm_call_started" });
3749
+ // Short delta — schedules a debounce timer but does NOT trip the
3750
+ // size gate. message_complete then arrives immediately after,
3751
+ // before the 250ms timer can fire.
3752
+ onEvent({ type: "text_delta", text: "Quick reply." });
3753
+ await onEvent({
3754
+ type: "message_complete",
3755
+ message: {
3756
+ role: "assistant",
3757
+ content: [{ type: "text", text: "Quick reply." }],
3758
+ },
3759
+ });
3760
+ onEvent({
3761
+ type: "usage",
3762
+ inputTokens: 10,
3763
+ outputTokens: 5,
3764
+ model: "test",
3765
+ providerDurationMs: 50,
3766
+ });
3767
+ // Wait past the original debounce window to prove a late timer
3768
+ // does NOT fire a stray partial flush.
3769
+ await new Promise((resolve) => setTimeout(resolve, 1100));
3770
+ return [
3771
+ ...messages,
3772
+ {
3773
+ role: "assistant" as const,
3774
+ content: [{ type: "text", text: "Quick reply." }] as ContentBlock[],
3775
+ },
3776
+ ];
3777
+ };
3778
+
3779
+ const ctx = makeCtx({ agentLoopRun });
3780
+ await runAgentLoopImpl(ctx, "hi", "msg-1", () => {});
3781
+
3782
+ // Only the final flush from `handleMessageComplete` lands. The
3783
+ // debounced partial would have fired around T+250ms; the timer-clear
3784
+ // at the top of `handleMessageComplete` cancels it.
3785
+ expect(updateMessageContentMock).toHaveBeenCalledTimes(1);
3786
+ });
3787
+
3788
+ test("partial flushes never trigger the indexer or attention projector", async () => {
3789
+ mockMessageById = {
3790
+ id: "msg-reserve",
3791
+ conversationId: "test-conv",
3792
+ createdAt: 1234567,
3793
+ role: "assistant",
3794
+ content: "[]",
3795
+ metadata: null,
3796
+ };
3797
+
3798
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3799
+ await onEvent({ type: "llm_call_started" });
3800
+ onEvent({ type: "text_delta", text: "hello world" });
3801
+ // Wait past the 250ms debounce so the partial flush definitely
3802
+ // lands BEFORE message_complete fires.
3803
+ await new Promise((resolve) => setTimeout(resolve, 1100));
3804
+ // Snapshot the indexer/projector call counts AFTER the partial
3805
+ // flush has run but BEFORE message_complete. They must be zero.
3806
+ const indexerCallsBeforeComplete =
3807
+ indexMessageNowMock.mock.calls.length;
3808
+ const projectorCallsBeforeComplete =
3809
+ projectAssistantMessageMock.mock.calls.length;
3810
+ // Stash on a side channel the assertion phase can read.
3811
+ (
3812
+ ctx as unknown as { __partialSnapshot?: [number, number] }
3813
+ ).__partialSnapshot = [
3814
+ indexerCallsBeforeComplete,
3815
+ projectorCallsBeforeComplete,
3816
+ ];
3817
+ await onEvent({
3818
+ type: "message_complete",
3819
+ message: {
3820
+ role: "assistant",
3821
+ content: [{ type: "text", text: "hello world" }],
3822
+ },
3823
+ });
3824
+ onEvent({
3825
+ type: "usage",
3826
+ inputTokens: 10,
3827
+ outputTokens: 5,
3828
+ model: "test",
3829
+ providerDurationMs: 50,
3830
+ });
3831
+ return [
3832
+ ...messages,
3833
+ {
3834
+ role: "assistant" as const,
3835
+ content: [{ type: "text", text: "hello world" }] as ContentBlock[],
3836
+ },
3837
+ ];
3838
+ };
3839
+
3840
+ const ctx = makeCtx({ agentLoopRun });
3841
+ await runAgentLoopImpl(ctx, "hi", "msg-1", () => {});
3842
+
3843
+ const snapshot = (
3844
+ ctx as unknown as { __partialSnapshot?: [number, number] }
3845
+ ).__partialSnapshot;
3846
+ expect(snapshot).toBeDefined();
3847
+ // Indexer + projector were both ZERO during the mid-turn partial
3848
+ // flush — they only fire from `handleMessageComplete` after the
3849
+ // authoritative `updateContent`.
3850
+ expect(snapshot![0]).toBe(0);
3851
+ expect(snapshot![1]).toBe(0);
3852
+ // After the loop completes the indexer + projector each ran exactly
3853
+ // once (the pre-allocation finalize path).
3854
+ expect(indexMessageNowMock).toHaveBeenCalledTimes(1);
3855
+ expect(projectAssistantMessageMock).toHaveBeenCalledTimes(1);
3856
+ });
3857
+
3858
+ test("partial flushes redact secrets from text blocks before writing", async () => {
3859
+ mockMessageById = {
3860
+ id: "msg-reserve",
3861
+ conversationId: "test-conv",
3862
+ createdAt: 1234567,
3863
+ role: "assistant",
3864
+ content: "[]",
3865
+ metadata: null,
3866
+ };
3867
+ // A GitHub PAT-shaped token mid-stream — the redaction discipline
3868
+ // mirrors `handleMessageComplete`'s final flush so a refresh mid-turn
3869
+ // never sees plaintext credentials in the persisted row.
3870
+ const ghToken = "ghp_" + "a".repeat(36);
3871
+ const payload = "Here's the key: " + ghToken + " enjoy.";
3872
+
3873
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3874
+ await onEvent({ type: "llm_call_started" });
3875
+ onEvent({ type: "text_delta", text: payload });
3876
+ // Wait past the 250ms debounce so the partial flush lands.
3877
+ await new Promise((resolve) => setTimeout(resolve, 1100));
3878
+ await onEvent({
3879
+ type: "message_complete",
3880
+ message: {
3881
+ role: "assistant",
3882
+ content: [{ type: "text", text: payload }],
3883
+ },
3884
+ });
3885
+ onEvent({
3886
+ type: "usage",
3887
+ inputTokens: 10,
3888
+ outputTokens: 5,
3889
+ model: "test",
3890
+ providerDurationMs: 50,
3891
+ });
3892
+ return [
3893
+ ...messages,
3894
+ {
3895
+ role: "assistant" as const,
3896
+ content: [{ type: "text", text: payload }] as ContentBlock[],
3897
+ },
3898
+ ];
3899
+ };
3900
+
3901
+ const ctx = makeCtx({ agentLoopRun });
3902
+ await runAgentLoopImpl(ctx, "hi", "msg-1", () => {});
3903
+
3904
+ expect(updateMessageContentMock).toHaveBeenCalledTimes(2);
3905
+ const partialPayload = (
3906
+ updateMessageContentMock.mock.calls[0] as unknown as [string, string]
3907
+ )[1];
3908
+ // The raw PAT must never appear in the persisted snapshot. The
3909
+ // redaction substitute is implementation-defined; the contract here
3910
+ // is "the literal token string is gone".
3911
+ expect(partialPayload).not.toContain(ghToken);
3912
+ });
3913
+
3914
+ test("provider-error cleanup deletes a row that has accumulated partial content", async () => {
3915
+ // Regression check: the pre-allocation orphan-cleanup branch
3916
+ // already deletes the reserved row when the LLM call exits via
3917
+ // `provider_error`. Partial-persist writes content to that row
3918
+ // mid-turn; the cleanup must still fire and the row (along with
3919
+ // its partial content) must still be deleted before the synthetic
3920
+ // error message lands.
3921
+ reserveMessageMock.mockImplementationOnce(async () => ({
3922
+ id: "msg-orphan-with-partial",
3923
+ }));
3924
+
3925
+ const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3926
+ await onEvent({ type: "llm_call_started" });
3927
+ // A debounced delta lands a partial flush BEFORE the provider
3928
+ // error fires.
3929
+ onEvent({ type: "text_delta", text: "hello world" });
3930
+ await new Promise((resolve) => setTimeout(resolve, 1100));
3931
+ onEvent({
3932
+ type: "provider_error",
3933
+ error: new Error("upstream 500"),
3934
+ rawRequest: { model: "gpt-4.1", messages: [] },
3935
+ actualProvider: "openai",
3936
+ });
3937
+ onEvent({
3938
+ type: "error",
3939
+ error: new Error("upstream 500"),
3940
+ });
3941
+ return messages;
3942
+ };
3943
+
3944
+ const ctx = makeCtx({ agentLoopRun });
3945
+ await runAgentLoopImpl(ctx, "hi", "msg-1", () => {});
3946
+
3947
+ // Partial flush fired exactly once (before the provider error).
3948
+ // The orphan row was then deleted; the synthetic error message is
3949
+ // inserted separately via `addMessage` (`mock-msg-id`) and never
3950
+ // touched by `updateContent`.
3951
+ const partialFlushes = (
3952
+ updateMessageContentMock.mock.calls as unknown as Array<
3953
+ [string, string]
3954
+ >
3955
+ ).filter(([id]) => id === "msg-orphan-with-partial");
3956
+ expect(partialFlushes).toHaveLength(1);
3957
+ expect(deleteMessageByIdMock).toHaveBeenCalledTimes(1);
3958
+ const deleteCall = deleteMessageByIdMock.mock.calls[0] as unknown as [
3959
+ string,
3960
+ ];
3961
+ expect(deleteCall[0]).toBe("msg-orphan-with-partial");
3962
+ });
3963
+ });
3964
+
3447
3965
  describe("pkbSystemReminderBlock metadata persistence", () => {
3448
3966
  test("persists pkbSystemReminderBlock in full mode with PKB active", async () => {
3449
3967
  const reminder = "<system_reminder>\npkb content\n</system_reminder>";
@@ -3939,21 +4457,22 @@ describe("session-agent-loop", () => {
3939
4457
  const agentLoopRun: AgentLoopRun = async (
3940
4458
  messages,
3941
4459
  _onEvent,
3942
- _signal,
3943
- _reqId,
3944
- onCheckpoint,
4460
+ options,
3945
4461
  ) => {
3946
4462
  runCount++;
3947
4463
  if (runCount === 1) {
4464
+ // The loop reaches its mid-loop budget checkpoint with the raw
4465
+ // persistent basis as its in-loop history; the wrapped onCheckpoint
4466
+ // trips the gate and runs inline compaction over that basis.
3948
4467
  mockEstimateTokens = 90_000;
3949
- const decision = await onCheckpoint?.({
4468
+ const decision = await options?.onCheckpoint?.({
3950
4469
  turnIndex: 0,
3951
4470
  toolCount: 1,
3952
4471
  hasToolUse: true,
3953
- history: messages,
4472
+ history: rawMidLoopBasis,
3954
4473
  });
3955
4474
  mockEstimateTokens = 1000;
3956
- if (decision === "yield") {
4475
+ if (decision !== "continue") {
3957
4476
  return rawMidLoopBasis;
3958
4477
  }
3959
4478
  }