@vellumai/assistant 0.8.3 → 0.8.5

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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -21,9 +21,11 @@
21
21
  * since NOW.md only changes when the model rewrites it. We set the 1h
22
22
  * TTL explicitly here to match the provider-side breakpoints; the
23
23
  * default 5m would force unnecessary cache re-creation.
24
- * The Anthropic provider also auto-applies a 1h breakpoint on the last text
25
- * block of a turn-starting user message, so the trailing uncached block does
26
- * not need an explicit `cache_control`.
24
+ * The trailing user-message block holds `<last_turn>` content that changes
25
+ * every call (new user turn + new prior assistant reply), so we pass
26
+ * `disableTurnStartCache: true` to the provider to suppress its auto-applied
27
+ * 1h breakpoint there — caching it would create unused cache entries (pure
28
+ * cache_creation cost with no future hit).
27
29
  *
28
30
  * This module is pure orchestration — it does not mutate activation state,
29
31
  * write any files, or update the conversation. PR 10 wires it into
@@ -47,7 +49,15 @@ import type {
47
49
  ToolDefinition,
48
50
  } from "../../providers/types.js";
49
51
  import { getLogger } from "../../util/logger.js";
50
- import { getPageIndex } from "./page-index.js";
52
+ import type { DrizzleDb } from "../db-connection.js";
53
+ import { computeInjectionScores } from "./injection-events.js";
54
+ import type { PageIndex } from "./page-index.js";
55
+ import {
56
+ getPageIndex,
57
+ partitionPageIndex,
58
+ splitTier1,
59
+ splitTier2,
60
+ } from "./page-index.js";
51
61
  import { resolveRouterPrompt } from "./prompts/router.js";
52
62
  import type { EverInjectedEntry } from "./types.js";
53
63
 
@@ -66,14 +76,28 @@ export type RouterFailureReason =
66
76
  | "api_error"
67
77
  | "empty_index";
68
78
 
79
+ /**
80
+ * Tags which batch a router-selected slug came from. Tier 3 carries the
81
+ * batch index so the inspector can distinguish e.g. `tier3:0` from
82
+ * `tier3:3` — useful for debugging hash bucketing and batch-quality
83
+ * regressions per tier 3 bucket.
84
+ */
85
+ export type RouterSource = "tier1" | "tier2" | `tier3:${number}`;
86
+
69
87
  /**
70
88
  * Result of a single router call. `selectedSlugs` preserves the order the
71
89
  * model returned and is already capped at `config.memory.v2.router.max_page_ids`
72
- * with out-of-range IDs dropped.
90
+ * with out-of-range IDs dropped. `sourceBySlug` attributes each selection
91
+ * to the batch it came from for inspector display.
73
92
  */
74
93
  export interface RouterResult {
75
94
  /** Selected page slugs in the order the model returned them. */
76
95
  selectedSlugs: string[];
96
+ /**
97
+ * Per-slug provenance covering every entry in `selectedSlugs`. Empty when
98
+ * `failureReason !== null` or no batch returned any selections.
99
+ */
100
+ sourceBySlug: ReadonlyMap<string, RouterSource>;
77
101
  /** `null` on success; one of the failure reasons above otherwise. */
78
102
  failureReason: RouterFailureReason | null;
79
103
  }
@@ -112,98 +136,305 @@ const RouterResultSchema = z.object({
112
136
  page_ids: z.array(z.number().int()),
113
137
  });
114
138
 
115
- /** Empty-result helper so call sites don't reconstruct the shape inline. */
139
+ /**
140
+ * Per-batch internal result. The orchestrator stamps provenance during the
141
+ * union so individual batches never need to know their own tier tag.
142
+ */
143
+ interface RouterBatchResult {
144
+ selectedSlugs: string[];
145
+ failureReason: RouterFailureReason | null;
146
+ }
147
+
148
+ /** Empty orchestrator result. */
116
149
  function emptyResult(reason: RouterFailureReason | null): RouterResult {
150
+ return { selectedSlugs: [], sourceBySlug: new Map(), failureReason: reason };
151
+ }
152
+
153
+ /** Empty batch result — slimmer shape; orchestrator builds provenance. */
154
+ function emptyBatchResult(
155
+ reason: RouterFailureReason | null,
156
+ ): RouterBatchResult {
117
157
  return { selectedSlugs: [], failureReason: reason };
118
158
  }
119
159
 
160
+ /**
161
+ * One `(assistant, user)` turn pair rendered inside `<last_turn>`. The
162
+ * pair represents the assistant's reply followed by the user message
163
+ * that came after. The most recent pair's `userMessage` is the
164
+ * just-arrived turn that triggered the router; older pairs are walked
165
+ * back from conversation history. `assistantMessage` is the empty
166
+ * string for the oldest pair when there was no prior assistant reply
167
+ * (conversation start) — `runRouterBatch` skips the `[assistant]:`
168
+ * line entirely in that case.
169
+ */
170
+ export interface RouterTurnPair {
171
+ assistantMessage: string;
172
+ userMessage: string;
173
+ }
174
+
120
175
  interface RunRouterParams {
121
176
  workspaceDir: string;
122
- userMessage: string;
123
- assistantMessage: string;
177
+ /**
178
+ * Recent assistant/user turn pairs, oldest first. Must contain at
179
+ * least one entry. The last entry's `userMessage` is the just-arrived
180
+ * user turn the router is routing for; entries before it are walked
181
+ * back from conversation history. The number of pairs the production
182
+ * caller passes is controlled by `memory.v2.router.historical_pairs`.
183
+ */
184
+ recentTurnPairs: readonly RouterTurnPair[];
124
185
  /** Verbatim contents to inject into `<now>...</now>` on this turn. */
125
186
  nowText: string;
126
187
  /** Slugs already injected on prior turns (used to seed `<already_injected_ids>`). */
127
188
  priorEverInjected: readonly EverInjectedEntry[];
128
189
  config: AssistantConfig;
129
190
  signal?: AbortSignal;
191
+ /**
192
+ * Database handle for reading EMA scores when `tier2_size` is set. When
193
+ * absent, tier 2 is silently skipped (pages flow tier 1 → tier 3). The
194
+ * production caller (`injectViaRouter`) always passes it; tests that
195
+ * only exercise tier 1 / tier 3 paths can omit it.
196
+ */
197
+ database?: DrizzleDb;
198
+ /**
199
+ * Per-call profile override forwarded to `getConfiguredProvider`. When
200
+ * set, the `memoryRouter` call site resolves against this profile name
201
+ * instead of the workspace active profile. The simulator route uses
202
+ * this to compare different profiles against the same query; live
203
+ * router callers leave it unset.
204
+ */
205
+ overrideProfile?: string;
206
+ /**
207
+ * Skip the post-union truncation to `max_page_ids`. Used by the
208
+ * simulator so the playground can show the full untruncated router
209
+ * output across all batches. Live callers (`injectViaRouter`) leave
210
+ * this unset so the bounded-injection contract holds.
211
+ */
212
+ disableUnionCap?: boolean;
213
+ /**
214
+ * Per-call inline router system-prompt override. Takes precedence
215
+ * over `memory.v2.router.router_prompt_path` and the bundled body.
216
+ * Used by the simulator playground for ad-hoc prompt comparisons.
217
+ * Live callers leave this unset.
218
+ */
219
+ routerPromptOverride?: string;
130
220
  }
131
221
 
132
222
  /**
133
- * Run the router for one turn. The implementation steps (mirroring
134
- * `sweep-job.ts` end-to-end):
223
+ * Run the router for one turn.
224
+ *
225
+ * Top-level orchestration. When `config.memory.v2.router.batch_size` is
226
+ * `null` (default), the entire page index is sent in one call — bit-
227
+ * identical to the pre-batching code path so v3's KV cache is preserved.
228
+ * When set, `partitionPageIndex` splits the index into stable hash-bucketed
229
+ * batches and we fire one provider call per batch in parallel; the selected
230
+ * slugs are unioned across batches.
135
231
  *
136
- * 1. Build the page index. If the workspace has no concept pages and no
137
- * seeded skill entries, abstain immediately with `empty_index`.
138
- * 2. Resolve the configured provider for the `memoryRouter` call site.
139
- * Missing `no_provider` so the caller can fall back to spreading
140
- * activation or an empty injection.
141
- * 3. Build system + user prompts. The system prompt is the rendered
142
- * router template with the page index inlined and gets one ephemeral
143
- * breakpoint at the end (the page-index block). The user message is
144
- * *two* text blocks: the cached `<now>` block and the uncached
145
- * already-injected/last-turn block.
146
- * 4. Force `tool_choice` so the model can only emit `select_pages_to_inject`.
147
- * 5. Parse the tool input via Zod. Anything off-shape collapses to
148
- * `schema_mismatch`.
149
- * 6. Map IDs to slugs through the page index, dropping IDs outside
150
- * `[1, N]` and truncating at `max_page_ids`.
232
+ * Per-batch failure does not abort the turn as long as at least one batch
233
+ * returns a usable selection, the union is returned with `failureReason:
234
+ * null`. Only when EVERY batch fails do we surface a failure; in that case
235
+ * the first batch's reason is returned for parity with the single-batch
236
+ * v3 behavior.
151
237
  *
152
- * Any uncaught throw inside the call (network, provider SDK error, abort)
153
- * collapses to `api_error` and is logged at warn so callers can keep going
154
- * without crashing the daemon. `AbortSignal.aborted` errors are *not*
155
- * special-cased; they propagate as `api_error` because the caller treats
156
- * "router didn't finish" the same regardless of cause.
238
+ * Single batch error semantics, preserved from v3:
239
+ * - `empty_index` workspace has no concept pages or skill entries.
240
+ * - `no_provider` `getConfiguredProvider("memoryRouter")` returned null.
241
+ * - `api_error` any uncaught throw during the provider call (incl. abort).
242
+ * - `tool_use_missing` the model returned no `select_pages_to_inject` tool_use.
243
+ * - `schema_mismatch` — tool input failed Zod validation.
157
244
  */
158
245
  export async function runRouter(
159
246
  params: RunRouterParams,
160
247
  ): Promise<RouterResult> {
161
- const {
162
- workspaceDir,
163
- userMessage,
164
- assistantMessage,
165
- nowText,
166
- priorEverInjected,
167
- config,
168
- signal,
169
- } = params;
248
+ const { workspaceDir, priorEverInjected, config } = params;
170
249
 
171
250
  const pageIndex = await getPageIndex(workspaceDir);
172
251
  if (pageIndex.entries.length === 0) {
173
252
  return emptyResult("empty_index");
174
253
  }
175
254
 
176
- const provider = await getConfiguredProvider("memoryRouter");
255
+ const provider = await getConfiguredProvider("memoryRouter", {
256
+ ...(params.overrideProfile !== undefined
257
+ ? { overrideProfile: params.overrideProfile }
258
+ : {}),
259
+ });
177
260
  if (!provider) {
178
261
  log.warn("memoryRouter provider unavailable; router skipped");
179
262
  return emptyResult("no_provider");
180
263
  }
181
264
 
265
+ const batchSize = config.memory?.v2?.router?.batch_size ?? null;
266
+ const tier1Size = config.memory?.v2?.router?.tier1_size ?? null;
267
+ const tier2Size = config.memory?.v2?.router?.tier2_size ?? null;
268
+
269
+ // Carve in tier order so each later tier sees only what's left. With
270
+ // every tier disabled (defaults) we hit the bit-identical single-batch
271
+ // path that preserves v3's KV cache.
272
+ const { tier1, rest: afterTier1 } = splitTier1(pageIndex, tier1Size);
273
+
274
+ let tier2: PageIndex | null = null;
275
+ let afterTier2: PageIndex = afterTier1;
276
+ if (tier2Size !== null && params.database && afterTier1.entries.length > 0) {
277
+ const slugs = afterTier1.entries.map((e) => e.slug);
278
+ const scores = computeInjectionScores(params.database, slugs, Date.now());
279
+ const split = splitTier2(afterTier1, tier2Size, scores);
280
+ tier2 = split.tier2;
281
+ afterTier2 = split.rest;
282
+ } else if (tier2Size !== null && !params.database) {
283
+ log.warn(
284
+ "tier2_size set but no database passed to runRouter; skipping tier 2",
285
+ );
286
+ }
287
+
288
+ const tier3Batches = partitionPageIndex(afterTier2, batchSize).filter(
289
+ (b) => b.entries.length > 0,
290
+ );
291
+
292
+ // Tag each batch with its provenance string. Tier 3 batches carry their
293
+ // bucket index so the inspector can attribute selections per-bucket.
294
+ const taggedBatches: Array<{ source: RouterSource; index: PageIndex }> = [];
295
+ if (tier1) taggedBatches.push({ source: "tier1", index: tier1 });
296
+ if (tier2) taggedBatches.push({ source: "tier2", index: tier2 });
297
+ tier3Batches.forEach((index, i) => {
298
+ taggedBatches.push({ source: `tier3:${i}` as const, index });
299
+ });
300
+ if (taggedBatches.length === 0) {
301
+ return emptyResult("empty_index");
302
+ }
303
+
304
+ const batchResults = await Promise.all(
305
+ taggedBatches.map(({ index }) =>
306
+ runRouterBatch({
307
+ ...params,
308
+ batchIndex: index,
309
+ priorEverInjected,
310
+ provider,
311
+ }),
312
+ ),
313
+ );
314
+
315
+ const successes = batchResults.filter((r) => r.failureReason === null);
316
+ if (successes.length === 0) {
317
+ // For the single-batch (K=null) path this preserves v3's behavior:
318
+ // one batch, one failure reason surfaces directly.
319
+ return emptyResult(batchResults[0].failureReason);
320
+ }
321
+
322
+ // Union selected slugs preserving first-seen order across batches; batch
323
+ // ordering is deterministic so the union and provenance map are stable.
324
+ // First-seen wins if a slug somehow appears in multiple batches (shouldn't
325
+ // happen — tier 1/2/3 partition is disjoint — but be defensive).
326
+ const sourceBySlug = new Map<string, RouterSource>();
327
+ const selectedSlugs: string[] = [];
328
+ for (let i = 0; i < batchResults.length; i++) {
329
+ const result = batchResults[i];
330
+ const source = taggedBatches[i].source;
331
+ for (const slug of result.selectedSlugs) {
332
+ if (sourceBySlug.has(slug)) continue;
333
+ sourceBySlug.set(slug, source);
334
+ selectedSlugs.push(slug);
335
+ }
336
+ }
337
+ if (successes.length < batchResults.length) {
338
+ log.warn(
339
+ {
340
+ totalBatches: batchResults.length,
341
+ failedBatches: batchResults.length - successes.length,
342
+ failureReasons: batchResults
343
+ .filter((r) => r.failureReason !== null)
344
+ .map((r) => r.failureReason),
345
+ },
346
+ "Some router batches failed; returning union of successful batches",
347
+ );
348
+ }
349
+
350
+ // Each per-batch call caps at max_page_ids, but the union across batches can
351
+ // exceed it (e.g. 10 batches × 10 selections each ≫ 25 cap). Apply a final
352
+ // truncation so RouterResult honors the contract that injection.ts trusts.
353
+ // Iteration order above is tier 1 → tier 2 → tier 3:0 → … so earlier-tier
354
+ // slugs win the truncation. The simulator passes `disableUnionCap` so the
355
+ // playground can show the full untruncated union for analysis.
356
+ if (!params.disableUnionCap) {
357
+ const maxPageIds = config.memory?.v2?.router?.max_page_ids ?? 25;
358
+ if (selectedSlugs.length > maxPageIds) {
359
+ log.warn(
360
+ { unionSize: selectedSlugs.length, max: maxPageIds },
361
+ "Router union across batches exceeded max_page_ids; truncating",
362
+ );
363
+ const dropped = selectedSlugs.splice(maxPageIds);
364
+ for (const slug of dropped) sourceBySlug.delete(slug);
365
+ }
366
+ }
367
+ return { selectedSlugs, sourceBySlug, failureReason: null };
368
+ }
369
+
370
+ interface RunRouterBatchParams extends RunRouterParams {
371
+ batchIndex: PageIndex;
372
+ provider: NonNullable<Awaited<ReturnType<typeof getConfiguredProvider>>>;
373
+ }
374
+
375
+ /**
376
+ * Route one batch of the page index. Uses batch-local IDs everywhere
377
+ * (including `<already_injected_ids>`, which is filtered to slugs present
378
+ * in this batch). Provider is passed in by the orchestrator so we don't
379
+ * re-resolve it N times for an N-batch turn.
380
+ */
381
+ async function runRouterBatch(
382
+ params: RunRouterBatchParams,
383
+ ): Promise<RouterBatchResult> {
384
+ const {
385
+ workspaceDir,
386
+ recentTurnPairs,
387
+ nowText,
388
+ priorEverInjected,
389
+ config,
390
+ signal,
391
+ batchIndex,
392
+ provider,
393
+ } = params;
394
+
182
395
  const systemPrompt = resolveRouterPrompt(
183
396
  config.memory?.v2?.router?.router_prompt_path ?? null,
184
397
  workspaceDir,
185
398
  {
186
399
  assistantName: getAssistantName(),
187
400
  userName: resolveUserName(workspaceDir),
188
- pageIndexBlock: pageIndex.rendered,
401
+ pageIndexBlock: batchIndex.rendered,
189
402
  },
403
+ params.routerPromptOverride ?? null,
190
404
  );
191
405
 
192
- // Already-injected slugs that map back to a current index ID. Slugs whose
193
- // page has been deleted since the prior turn drop out silently — the model
194
- // only sees IDs that still resolve.
406
+ // Filter prior-injected to slugs present in THIS batch and map to
407
+ // batch-local IDs. The model in batch B can't reference global IDs that
408
+ // aren't in its prompt, so listing them would just be noise.
195
409
  const priorIds: number[] = [];
196
410
  for (const entry of priorEverInjected) {
197
- const idx = pageIndex.bySlug.get(entry.slug);
198
- if (idx) priorIds.push(idx.id);
411
+ const local = batchIndex.bySlug.get(entry.slug);
412
+ if (local) priorIds.push(local.id);
413
+ }
414
+
415
+ // Trim the pairs down to the configured `<last_turn>` content budget,
416
+ // newest-message-first so the just-arrived user turn keeps full claim
417
+ // on the cap and the oldest still-includable message is front-truncated
418
+ // (rather than dropping the most recent message). `null` is a no-op.
419
+ const cappedPairs = applyHistoricalCharBudget(
420
+ recentTurnPairs,
421
+ config.memory?.v2?.router?.historical_pairs_max_chars ?? null,
422
+ );
423
+
424
+ // Render `<last_turn>` chronologically: each pair emits the prior
425
+ // assistant reply followed by the user message that came after.
426
+ // `assistantMessage` is the empty string on the oldest pair when there
427
+ // was no prior assistant reply (conversation start) — skip that line
428
+ // so we don't emit a dangling `[assistant]:`.
429
+ const lastTurnLines: string[] = [];
430
+ for (const pair of cappedPairs) {
431
+ if (pair.assistantMessage.trim().length > 0) {
432
+ lastTurnLines.push(`[assistant]: ${pair.assistantMessage}`);
433
+ }
434
+ lastTurnLines.push(`[user]: ${pair.userMessage}`);
199
435
  }
436
+ const lastTurnBlock = `<last_turn>\n${lastTurnLines.join("\n")}\n</last_turn>`;
200
437
 
201
- // Cache breakpoint 2 — `<now>` is stable across most turns (NOW.md only
202
- // changes when the model rewrites it), so the bulk of the user message
203
- // rides the cache. We use a 1h TTL to match the system-prompt breakpoint
204
- // and the provider's auto-applied breakpoints. The trailing block has no
205
- // `cache_control`; the Anthropic provider auto-applies a 1h breakpoint on
206
- // the last text block of a turn-starting user message, which covers it.
207
438
  const userMsg: Message = {
208
439
  role: "user",
209
440
  content: [
@@ -212,7 +443,7 @@ export async function runRouter(
212
443
  type: "text",
213
444
  text:
214
445
  `<already_injected_ids>\n${priorIds.join(", ")}\n</already_injected_ids>\n\n` +
215
- `<last_turn>\n[user]: ${userMessage}\n[assistant]: ${assistantMessage}\n</last_turn>`,
446
+ lastTurnBlock,
216
447
  },
217
448
  ],
218
449
  };
@@ -230,13 +461,14 @@ export async function runRouter(
230
461
  config: {
231
462
  callSite: "memoryRouter" as const,
232
463
  tool_choice: { type: "tool" as const, name: ROUTER_TOOL_NAME },
464
+ disableTurnStartCache: true,
233
465
  },
234
466
  ...(signal ? { signal } : {}),
235
467
  },
236
468
  );
237
469
  } catch (err) {
238
470
  log.warn({ err }, "Router provider call threw; treating as api_error");
239
- return emptyResult("api_error");
471
+ return emptyBatchResult("api_error");
240
472
  }
241
473
 
242
474
  const toolBlock = extractToolUse(response);
@@ -245,7 +477,7 @@ export async function runRouter(
245
477
  { stopReason: response.stopReason },
246
478
  "Router model returned no select_pages_to_inject tool_use block",
247
479
  );
248
- return emptyResult("tool_use_missing");
480
+ return emptyBatchResult("tool_use_missing");
249
481
  }
250
482
 
251
483
  const parsed = RouterResultSchema.safeParse(toolBlock.input);
@@ -254,11 +486,10 @@ export async function runRouter(
254
486
  { error: parsed.error.message },
255
487
  "Router tool input did not match schema",
256
488
  );
257
- return emptyResult("schema_mismatch");
489
+ return emptyBatchResult("schema_mismatch");
258
490
  }
259
491
 
260
- const N = pageIndex.entries.length;
261
-
492
+ const N = batchIndex.entries.length;
262
493
  const inRangeIds: number[] = [];
263
494
  const droppedIds: number[] = [];
264
495
  for (const id of parsed.data.page_ids) {
@@ -275,9 +506,8 @@ export async function runRouter(
275
506
  );
276
507
  }
277
508
 
278
- // De-duplicate BEFORE applying the cap — otherwise a duplicate-heavy
279
- // model output like `[1, 1, 2]` with `max=2` slices to `[1, 1]` and
280
- // dedupes to `[1]`, under-filling the cap.
509
+ // De-duplicate BEFORE applying the cap — `[1, 1, 2]` with max=2 must
510
+ // yield 2 distinct slugs, not collapse to 1 after slicing duplicates.
281
511
  const dedupedIds = Array.from(new Set(inRangeIds));
282
512
 
283
513
  const truncated = dedupedIds.length > maxPageIds;
@@ -291,7 +521,7 @@ export async function runRouter(
291
521
 
292
522
  const selectedSlugs: string[] = [];
293
523
  for (const id of finalIds) {
294
- const entry = pageIndex.byId.get(id);
524
+ const entry = batchIndex.byId.get(id);
295
525
  if (!entry) continue;
296
526
  selectedSlugs.push(entry.slug);
297
527
  }
@@ -299,6 +529,83 @@ export async function runRouter(
299
529
  return { selectedSlugs, failureReason: null };
300
530
  }
301
531
 
532
+ /** Truncation marker prepended to a front-truncated historical message. */
533
+ const HISTORICAL_TRUNCATION_MARKER = "…";
534
+
535
+ /**
536
+ * Apply the `<last_turn>` content character budget to a chronological
537
+ * pairs array. The just-arrived user message has first claim on the
538
+ * budget; older messages are added newest-first until exhausted. The
539
+ * oldest still-includable message is front-truncated with a leading
540
+ * `…` so it joins coherently with the next message in time. Older pairs
541
+ * whose content doesn't fit are dropped entirely.
542
+ *
543
+ * Counts message content only — framing characters (`[assistant]: `,
544
+ * `[user]: `, newlines) are not deducted from the budget. The cap is a
545
+ * conservative upper bound on the dialogue content surfaced to the
546
+ * router, not on the exact rendered block size.
547
+ *
548
+ * Exported for tests; production calls it via `runRouterBatch`.
549
+ */
550
+ export function applyHistoricalCharBudget(
551
+ pairs: readonly RouterTurnPair[],
552
+ maxChars: number | null,
553
+ ): RouterTurnPair[] {
554
+ if (maxChars === null || maxChars <= 0) return [...pairs];
555
+
556
+ type WalkedMsg = {
557
+ role: "user" | "assistant";
558
+ text: string;
559
+ pairIdx: number;
560
+ };
561
+ // Walk every message newest-first. Within a single pair the user
562
+ // message came AFTER the assistant message chronologically, so the
563
+ // user line gets first claim on the budget.
564
+ const walked: WalkedMsg[] = [];
565
+ for (let i = pairs.length - 1; i >= 0; i--) {
566
+ walked.push({ role: "user", text: pairs[i].userMessage, pairIdx: i });
567
+ walked.push({
568
+ role: "assistant",
569
+ text: pairs[i].assistantMessage,
570
+ pairIdx: i,
571
+ });
572
+ }
573
+
574
+ let used = 0;
575
+ const included = new Map<number, { assistant: string; user: string }>();
576
+ for (const msg of walked) {
577
+ const remaining = maxChars - used;
578
+ if (remaining <= 0) break;
579
+ let textToInclude: string;
580
+ let stop = false;
581
+ if (msg.text.length <= remaining) {
582
+ textToInclude = msg.text;
583
+ used += msg.text.length;
584
+ } else {
585
+ // Front-truncate so the surviving suffix of an older message
586
+ // connects to the next message (in chronological order) without
587
+ // a syntactic seam. The marker counts toward the budget so the
588
+ // emitted text never exceeds `maxChars` cumulatively.
589
+ if (remaining <= HISTORICAL_TRUNCATION_MARKER.length) break;
590
+ const keepChars = remaining - HISTORICAL_TRUNCATION_MARKER.length;
591
+ textToInclude = HISTORICAL_TRUNCATION_MARKER + msg.text.slice(-keepChars);
592
+ used = maxChars;
593
+ stop = true;
594
+ }
595
+ const slot = included.get(msg.pairIdx) ?? { assistant: "", user: "" };
596
+ if (msg.role === "user") slot.user = textToInclude;
597
+ else slot.assistant = textToInclude;
598
+ included.set(msg.pairIdx, slot);
599
+ if (stop) break;
600
+ }
601
+
602
+ const sortedIdxs = [...included.keys()].sort((a, b) => a - b);
603
+ return sortedIdxs.map((idx) => {
604
+ const slot = included.get(idx)!;
605
+ return { assistantMessage: slot.assistant, userMessage: slot.user };
606
+ });
607
+ }
608
+
302
609
  /**
303
610
  * Build a text content block carrying an ephemeral `cache_control`
304
611
  * breakpoint with a 1h TTL. The Anthropic SDK accepts the field as an extra