@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
@@ -1,6 +1,5 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
 
3
- import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/system-prompt.js";
4
3
  import { isAbortReason } from "../../util/abort-reasons.js";
5
4
  import { ProviderError } from "../../util/errors.js";
6
5
  import { getLogger } from "../../util/logger.js";
@@ -537,6 +536,55 @@ function formatOrphanedWebSearchResultAsText(block: {
537
536
  *
538
537
  * Builds a fresh result array without mutating the input.
539
538
  */
539
+ /**
540
+ * Find the start index of the active tool-use continuation span at the tail
541
+ * of the formatted message array. Messages from this index onward may contain
542
+ * thinking blocks that must be preserved for Anthropic's tool-use protocol.
543
+ *
544
+ * The active span is the trailing sequence of alternating
545
+ * assistant(tool_use) → user(tool_result) messages. Everything before it is
546
+ * a completed historical turn whose thinking blocks can be safely stripped.
547
+ *
548
+ * Returns `messages.length` when there is no active tool-use continuation
549
+ * (i.e. all messages are historical — strip thinking from everything).
550
+ */
551
+ function findActiveToolUseContinuationStart(
552
+ messages: Anthropic.MessageParam[],
553
+ ): number {
554
+ // Walk backwards from the end. The tail pattern we're looking for is:
555
+ // ... assistant(tool_use) user(tool_result) [assistant(tool_use) user(tool_result)]* ...
556
+ // The last message is typically a user message (the new prompt), so if it
557
+ // doesn't contain tool_result blocks, there's no active continuation.
558
+ let i = messages.length - 1;
559
+
560
+ while (i >= 0) {
561
+ const msg = messages[i];
562
+ if (msg.role === "user") {
563
+ const content = Array.isArray(msg.content) ? msg.content : [];
564
+ const hasToolResult = content.some(
565
+ (b) => typeof b !== "string" && isToolResultBlock(b),
566
+ );
567
+ if (!hasToolResult) break;
568
+ // This user message has tool_result — the preceding assistant message
569
+ // should have the matching tool_use and its thinking blocks preserved.
570
+ i--;
571
+ } else if (msg.role === "assistant") {
572
+ const content = Array.isArray(msg.content) ? msg.content : [];
573
+ const hasToolUse = content.some(
574
+ (b) => typeof b !== "string" && isToolUseBlock(b),
575
+ );
576
+ if (!hasToolUse) break;
577
+ // This assistant message has tool_use — it's part of the active span.
578
+ // Check if the preceding user message continues the chain.
579
+ i--;
580
+ } else {
581
+ break;
582
+ }
583
+ }
584
+
585
+ return i + 1;
586
+ }
587
+
540
588
  function ensureToolPairing(
541
589
  messages: Anthropic.MessageParam[],
542
590
  ): Anthropic.MessageParam[] {
@@ -770,6 +818,15 @@ export class AnthropicProvider implements Provider {
770
818
  ((config as Record<string, unknown> | undefined)?.cacheTtl as
771
819
  | "5m"
772
820
  | "1h") ?? "1h";
821
+ // Opt-out for callers (e.g. the memory router) that send a single
822
+ // user message per call with content that changes every time. The
823
+ // turn-start cache breakpoint below is only useful when the same
824
+ // prefix is re-sent on a subsequent call (typical for the main agent
825
+ // loop's tool-use iterations); one-shot callers pay cache_creation
826
+ // cost without a future hit.
827
+ const disableTurnStartCache =
828
+ (config as Record<string, unknown> | undefined)?.disableTurnStartCache ===
829
+ true;
773
830
  let sentMessages: Anthropic.MessageParam[] | undefined;
774
831
  const startedAt = Date.now();
775
832
  // Hoisted so the catch block can distinguish our inner stream timeout
@@ -925,10 +982,29 @@ export class AnthropicProvider implements Provider {
925
982
  }
926
983
  }
927
984
 
928
- // Thinking blocks are stripped at rest by DB migration 209 so
929
- // historical messages are clean when loaded. Within a turn,
930
- // assistant messages have original thinking with valid signatures
931
- // the API accepts them. No provider-side stripping needed.
985
+ // Strip thinking/redacted_thinking blocks from completed historical
986
+ // assistant turns. Anthropic only requires these blocks for active
987
+ // tool-use continuation (the tail span where assistant tool_use is
988
+ // followed by user tool_result). Replaying stale thinking blocks from
989
+ // earlier turns causes 400 errors when the signature is no longer
990
+ // valid (e.g. after a provider/model/profile switch).
991
+ const activeToolUseStart = findActiveToolUseContinuationStart(formatted);
992
+ for (let i = 0; i < activeToolUseStart; i++) {
993
+ const msg = formatted[i];
994
+ if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
995
+ const stripped = (msg.content as Anthropic.ContentBlockParam[]).filter(
996
+ (b) =>
997
+ typeof b === "string" ||
998
+ (b.type !== "thinking" && b.type !== "redacted_thinking"),
999
+ );
1000
+ if (stripped.length === 0) {
1001
+ stripped.push({
1002
+ type: "text" as const,
1003
+ text: PLACEHOLDER_BLOCKS_OMITTED,
1004
+ });
1005
+ }
1006
+ formatted[i] = { ...msg, content: stripped };
1007
+ }
932
1008
 
933
1009
  sentMessages = ensureToolPairing(
934
1010
  repairOrphanedServerToolBlocks(formatted),
@@ -938,6 +1014,7 @@ export class AnthropicProvider implements Provider {
938
1014
  speed,
939
1015
  output_config,
940
1016
  cacheTtl: _cacheTtl,
1017
+ disableTurnStartCache: _disableTurnStartCache,
941
1018
  max_tokens: callerMaxTokens,
942
1019
  usageAttributionHeaders,
943
1020
  ...restConfig
@@ -994,38 +1071,17 @@ export class AnthropicProvider implements Provider {
994
1071
  };
995
1072
 
996
1073
  if (systemPrompt) {
997
- const boundaryIdx = systemPrompt.indexOf(SYSTEM_PROMPT_CACHE_BOUNDARY);
998
- if (boundaryIdx >= 0) {
999
- // Split into two cache blocks: static instructions (stable across
1000
- // turns) and dynamic workspace content (changes when files are
1001
- // edited). The static prefix stays cached even when workspace
1002
- // files change, saving ~8-10K tokens of cache creation per turn.
1003
- // Both blocks use 1-hour cache TTL to avoid repeated cache misses
1004
- // for conversations with turn gaps exceeding the default 5-minute
1005
- // window.
1006
- const staticBlock = systemPrompt.slice(0, boundaryIdx);
1007
- const dynamicBlock = systemPrompt.slice(
1008
- boundaryIdx + SYSTEM_PROMPT_CACHE_BOUNDARY.length,
1009
- );
1010
- const systemBlocks = [staticBlock, dynamicBlock]
1011
- .filter((text) => text.length > 0)
1012
- .map((text) => ({
1013
- type: "text" as const,
1014
- text,
1015
- cache_control: cacheControl,
1016
- }));
1017
- if (systemBlocks.length > 0) {
1018
- params.system = systemBlocks;
1019
- }
1020
- } else {
1021
- params.system = [
1022
- {
1023
- type: "text" as const,
1024
- text: systemPrompt,
1025
- cache_control: cacheControl,
1026
- },
1027
- ];
1028
- }
1074
+ // The whole system prompt is rendered as a single cached
1075
+ // block. A 1-hour cache TTL is used (when supported by the
1076
+ // model) so the breakpoint survives turn gaps that exceed the
1077
+ // default 5-minute window.
1078
+ params.system = [
1079
+ {
1080
+ type: "text" as const,
1081
+ text: systemPrompt,
1082
+ cache_control: cacheControl,
1083
+ },
1084
+ ];
1029
1085
  }
1030
1086
 
1031
1087
  if (tools && tools.length > 0) {
@@ -1089,7 +1145,9 @@ export class AnthropicProvider implements Provider {
1089
1145
  }
1090
1146
  };
1091
1147
  const turnStartIdx = findUserTextMsgIdx(msgs.length - 1);
1092
- if (turnStartIdx >= 0) applyCacheControlToLastBlock(turnStartIdx);
1148
+ if (turnStartIdx >= 0 && !disableTurnStartCache) {
1149
+ applyCacheControlToLastBlock(turnStartIdx);
1150
+ }
1093
1151
 
1094
1152
  // Previous-turn anchor: when this request is the first of a new turn
1095
1153
  // (turn-start is the very last message — no tool-use loop yet), also
@@ -1101,9 +1159,8 @@ export class AnthropicProvider implements Provider {
1101
1159
  // cache_creation tokens per new turn). Skipped during tool-use loops
1102
1160
  // where the current turn-start already covers the same prefix and a
1103
1161
  // second anchor would blow the 4-breakpoint budget.
1104
- let prevTurnAnchorIdx = -1;
1105
1162
  if (turnStartIdx === msgs.length - 1 && turnStartIdx > 0) {
1106
- prevTurnAnchorIdx = findUserTextMsgIdx(turnStartIdx - 1);
1163
+ const prevTurnAnchorIdx = findUserTextMsgIdx(turnStartIdx - 1);
1107
1164
  if (prevTurnAnchorIdx >= 0)
1108
1165
  applyCacheControlToLastBlock(prevTurnAnchorIdx);
1109
1166
  }
@@ -1114,7 +1171,6 @@ export class AnthropicProvider implements Provider {
1114
1171
  // cheaply without conflicting with the 1h breakpoints above.
1115
1172
  // Skip thinking/redacted_thinking blocks — Anthropic doesn't allow
1116
1173
  // cache_control on those types.
1117
- let tailBreakpointApplied = false;
1118
1174
  if (turnStartIdx >= 0 && turnStartIdx < sentMessages.length - 1) {
1119
1175
  const lastMsg = sentMessages[sentMessages.length - 1];
1120
1176
  if (Array.isArray(lastMsg.content) && lastMsg.content.length > 0) {
@@ -1136,34 +1192,15 @@ export class AnthropicProvider implements Provider {
1136
1192
  if (tailBlock && typeof tailBlock !== "string") {
1137
1193
  (tailBlock as unknown as Record<string, unknown>).cache_control =
1138
1194
  tailCacheControl;
1139
- tailBreakpointApplied = true;
1140
1195
  }
1141
1196
  }
1142
1197
  }
1143
1198
 
1144
- // Enforce Anthropic API maximum of 4 cache_control blocks.
1145
- // With the system prompt boundary split into 2 cached blocks AND
1146
- // tools + turn-start + (tail OR prev-turn-anchor), we'd have 5.
1147
- // Drop the static system block's breakpoint it's small (<1K
1148
- // tokens) so the re-read cost is negligible, while the dynamic
1149
- // block (workspace context) rarely changes mid-session and
1150
- // benefits more from caching. Tail and prev-turn-anchor are
1151
- // mutually exclusive (prev-turn-anchor only fires when turn-start
1152
- // is the last message, which is the exact condition that suppresses
1153
- // the tail), so we never exceed 5.
1154
- const hasToolCacheBreakpoint =
1155
- params.tools?.some(
1156
- (t) => "cache_control" in t && t.cache_control != null,
1157
- ) ?? false;
1158
- if (
1159
- (tailBreakpointApplied || prevTurnAnchorIdx >= 0) &&
1160
- Array.isArray(params.system) &&
1161
- params.system.length === 2 &&
1162
- hasToolCacheBreakpoint
1163
- ) {
1164
- delete (params.system[0] as unknown as Record<string, unknown>)
1165
- .cache_control;
1166
- }
1199
+ // Cache-breakpoint accounting: system(1) + tools(1) + turn-start(1) +
1200
+ // (tail OR prev-turn-anchor)(1) = 4 exactly Anthropic's per-request
1201
+ // cap. Tail and prev-turn-anchor are mutually exclusive (the latter
1202
+ // only fires when turn-start is the last message, which suppresses
1203
+ // the tail), so the total can't drift past 4.
1167
1204
 
1168
1205
  // Strip orphaned UTF-16 surrogates so the Anthropic JSON parser never
1169
1206
  // sees invalid strings produced by upstream surrogate-splitting `.slice()` calls.
@@ -1274,6 +1311,19 @@ export class AnthropicProvider implements Provider {
1274
1311
  let lastInputJsonEmitMs = 0;
1275
1312
  let pendingInputJsonFlush: ReturnType<typeof setTimeout> | undefined;
1276
1313
 
1314
+ // Anthropic streams `server_tool_use` block input via `input_json_delta`
1315
+ // events (the block's own `input` field is `{}` at content_block_start).
1316
+ // We accumulate the JSON separately from regular `tool_use` blocks so
1317
+ // the daemon can read the resolved query when the paired
1318
+ // `web_search_tool_result` arrives — without this, downstream activity
1319
+ // metadata sees an empty query.
1320
+ let currentServerToolUseId: string | undefined;
1321
+ let accumulatedServerToolInputJson = "";
1322
+ const resolvedServerToolInputs = new Map<
1323
+ string,
1324
+ Record<string, unknown>
1325
+ >();
1326
+
1277
1327
  stream.on("streamEvent", (event) => {
1278
1328
  // Reset the text sentinel buffer at each content-block boundary.
1279
1329
  // A new block starts fresh; at the end of a block, flush any
@@ -1300,6 +1350,8 @@ export class AnthropicProvider implements Provider {
1300
1350
  event.type === "content_block_start" &&
1301
1351
  event.content_block.type === "server_tool_use"
1302
1352
  ) {
1353
+ currentServerToolUseId = event.content_block.id;
1354
+ accumulatedServerToolInputJson = "";
1303
1355
  onEvent?.({
1304
1356
  type: "server_tool_start",
1305
1357
  name: event.content_block.name,
@@ -1315,11 +1367,21 @@ export class AnthropicProvider implements Provider {
1315
1367
  ) {
1316
1368
  const block = event.content_block as {
1317
1369
  tool_use_id: string;
1318
- content?: { type: "web_search_tool_result_error" } | unknown[];
1370
+ content?:
1371
+ | { type: "web_search_tool_result_error"; error_code?: string }
1372
+ | unknown[];
1319
1373
  };
1320
1374
  const isError =
1321
1375
  !Array.isArray(block.content) &&
1322
1376
  block.content?.type === "web_search_tool_result_error";
1377
+ const errorCode =
1378
+ isError && !Array.isArray(block.content)
1379
+ ? block.content?.error_code
1380
+ : undefined;
1381
+ const resolvedInput = resolvedServerToolInputs.get(
1382
+ block.tool_use_id,
1383
+ );
1384
+ resolvedServerToolInputs.delete(block.tool_use_id);
1323
1385
  onEvent?.({
1324
1386
  type: "server_tool_complete",
1325
1387
  toolUseId: block.tool_use_id,
@@ -1327,6 +1389,8 @@ export class AnthropicProvider implements Provider {
1327
1389
  ...(Array.isArray(block.content)
1328
1390
  ? { content: block.content }
1329
1391
  : {}),
1392
+ ...(resolvedInput ? { resolvedInput } : {}),
1393
+ ...(errorCode ? { errorCode } : {}),
1330
1394
  });
1331
1395
  }
1332
1396
  if (event.type === "content_block_stop") {
@@ -1345,6 +1409,25 @@ export class AnthropicProvider implements Provider {
1345
1409
  currentStreamingToolName = undefined;
1346
1410
  currentStreamingToolUseId = undefined;
1347
1411
  accumulatedInputJson = "";
1412
+ // Finalize the resolved input for a `server_tool_use` block (e.g.
1413
+ // the actual web-search query) so the paired `web_search_tool_result`
1414
+ // emits `server_tool_complete` with `resolvedInput` populated.
1415
+ if (currentServerToolUseId && accumulatedServerToolInputJson) {
1416
+ try {
1417
+ const parsed = JSON.parse(accumulatedServerToolInputJson);
1418
+ if (parsed && typeof parsed === "object") {
1419
+ resolvedServerToolInputs.set(
1420
+ currentServerToolUseId,
1421
+ parsed as Record<string, unknown>,
1422
+ );
1423
+ }
1424
+ } catch {
1425
+ // Malformed partial JSON — drop silently; downstream falls
1426
+ // back to whatever was captured at server_tool_start.
1427
+ }
1428
+ }
1429
+ currentServerToolUseId = undefined;
1430
+ accumulatedServerToolInputJson = "";
1348
1431
  // Flush residual text buffer unless it's exactly a sentinel.
1349
1432
  if (textBuffer.length > 0 && !isCompleteSentinel(textBuffer)) {
1350
1433
  onEvent?.({ type: "text_delta", text: textBuffer });
@@ -1354,6 +1437,13 @@ export class AnthropicProvider implements Provider {
1354
1437
  });
1355
1438
 
1356
1439
  stream.on("inputJson", (partialJson) => {
1440
+ if (currentServerToolUseId) {
1441
+ // Server-tool input (e.g. `web_search` query) — accumulate without
1442
+ // emitting `input_json_delta`; the daemon only consumes the
1443
+ // finalized value from `server_tool_complete.resolvedInput`.
1444
+ accumulatedServerToolInputJson += partialJson;
1445
+ return;
1446
+ }
1357
1447
  if (!currentStreamingToolName) return;
1358
1448
  accumulatedInputJson += partialJson;
1359
1449
  const now = Date.now();
@@ -1544,6 +1634,9 @@ export class AnthropicProvider implements Provider {
1544
1634
  case "text":
1545
1635
  return { type: "text", text: block.text };
1546
1636
  case "thinking":
1637
+ if (!block.signature) {
1638
+ return null;
1639
+ }
1547
1640
  return {
1548
1641
  type: "thinking",
1549
1642
  thinking: block.thinking,
@@ -24,6 +24,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
24
24
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
25
25
  import { getConfig } from "../config/loader.js";
26
26
  import { getDb } from "../memory/db-connection.js";
27
+ import { isConnectionCompatibleWithModel } from "./connection-model-compat.js";
27
28
  import {
28
29
  ConnectionResolutionError,
29
30
  tryResolveProviderForConnectionName,
@@ -73,10 +74,15 @@ export class CallSiteRoutingProvider implements Provider {
73
74
  * `expectedProvider` is the provider name the resolved profile
74
75
  * declared. The hook verifies the connection's provider matches
75
76
  * and throws on mismatch.
77
+ *
78
+ * `model` is the resolved call-site model, threaded through so the
79
+ * connection lookup can gate `oauth_subscription` (Codex) connections
80
+ * by model compatibility.
76
81
  */
77
82
  private readonly resolveByConnection: (
78
83
  connectionName: string,
79
84
  expectedProvider: string,
85
+ model: string | undefined,
80
86
  ) => Promise<Provider | null>,
81
87
  ) {
82
88
  this.tokenEstimationProvider = defaultProvider.tokenEstimationProvider;
@@ -155,7 +161,11 @@ export class CallSiteRoutingProvider implements Provider {
155
161
  const candidates = listConnections(getDb(), {
156
162
  provider: resolved.provider,
157
163
  });
158
- const active = candidates.find((c) => c.status === "active");
164
+ const active = candidates.find(
165
+ (c) =>
166
+ c.status === "active" &&
167
+ isConnectionCompatibleWithModel(c, resolved.model),
168
+ );
159
169
  if (active) {
160
170
  connectionName = active.name;
161
171
  }
@@ -168,6 +178,7 @@ export class CallSiteRoutingProvider implements Provider {
168
178
  const connectionProvider = await this.resolveByConnection(
169
179
  connectionName,
170
180
  resolved.provider,
181
+ resolved.model,
171
182
  );
172
183
  if (connectionProvider) return connectionProvider;
173
184
  return this.defaultProvider;
@@ -200,11 +211,12 @@ export function wrapWithCallSiteRouting(
200
211
  ): Provider {
201
212
  return new CallSiteRoutingProvider(
202
213
  base,
203
- (connectionName, expectedProvider) =>
214
+ (connectionName, expectedProvider, model) =>
204
215
  tryResolveProviderForConnectionName(
205
216
  connectionName,
206
217
  config,
207
218
  expectedProvider,
219
+ model,
208
220
  ),
209
221
  );
210
222
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Model-compatibility gate for auto-resolved provider connections.
3
+ *
4
+ * When a profile uses "Any active <provider> connection" (no
5
+ * `provider_connection` pinned), the daemon auto-picks an active connection
6
+ * for the provider. `oauth_subscription` connections (ChatGPT Codex) hard-
7
+ * route every request to the Codex endpoint, which rejects non-Codex models
8
+ * with HTTP 400. This helper lets the auto-resolution sites skip such a
9
+ * connection when the requested model is not Codex-compatible.
10
+ */
11
+
12
+ import type { ProviderConnection } from "./inference/auth.js";
13
+ import { isCodexSubscriptionModel } from "./openai/codex-models.js";
14
+
15
+ /**
16
+ * Whether `connection` can serve a request for `model` during
17
+ * auto-resolution.
18
+ *
19
+ * `oauth_subscription` connections route through the ChatGPT Codex endpoint,
20
+ * so they are only compatible with Codex models. Every other auth type
21
+ * imposes no model restriction and is always compatible.
22
+ *
23
+ * `model` may be undefined when the call site has no resolved model; in that
24
+ * case no model gating is applied (returns true) so resolution behaviour is
25
+ * unchanged.
26
+ *
27
+ * This gate applies to auto-resolution only — an explicitly pinned
28
+ * `provider_connection` bypasses connection selection entirely and is used
29
+ * regardless of model.
30
+ */
31
+ export function isConnectionCompatibleWithModel(
32
+ connection: Pick<ProviderConnection, "auth">,
33
+ model: string | undefined,
34
+ ): boolean {
35
+ if (connection.auth.type !== "oauth_subscription") return true;
36
+ if (!model) return true;
37
+ return isCodexSubscriptionModel(model);
38
+ }
@@ -30,6 +30,7 @@
30
30
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
31
31
  import { getDb } from "../memory/db-connection.js";
32
32
  import { getLogger } from "../util/logger.js";
33
+ import { isConnectionCompatibleWithModel } from "./connection-model-compat.js";
33
34
  import { getConnection, listConnections } from "./inference/connections.js";
34
35
  import type { ProvidersConfig } from "./registry.js";
35
36
  import { resolveProviderFromConnection } from "./registry.js";
@@ -79,11 +80,16 @@ export class ConnectionResolutionError extends Error {
79
80
  * `expectedProvider` is the provider name the resolving profile declared.
80
81
  * Pass `undefined` to skip the mismatch check (callers that don't yet
81
82
  * know the expected provider).
83
+ *
84
+ * `model` is the resolved call-site model. It gates the `provider_mismatch`
85
+ * auto-recovery below so a non-Codex model is never rerouted onto an
86
+ * `oauth_subscription` (ChatGPT Codex) connection.
82
87
  */
83
88
  export async function tryResolveProviderForConnectionName(
84
89
  connectionName: string,
85
90
  config: ProvidersConfig,
86
91
  expectedProvider?: string,
92
+ model?: string,
87
93
  ): Promise<Provider | null> {
88
94
  let connection;
89
95
  try {
@@ -113,7 +119,10 @@ export async function tryResolveProviderForConnectionName(
113
119
  try {
114
120
  const db = getDb();
115
121
  const candidates = listConnections(db, { provider: expectedProvider });
116
- const active = candidates.find((c) => c.status === "active");
122
+ const active = candidates.find(
123
+ (c) =>
124
+ c.status === "active" && isConnectionCompatibleWithModel(c, model),
125
+ );
117
126
  if (active) {
118
127
  log.info(
119
128
  {
@@ -192,7 +201,11 @@ export async function resolveDefaultProvider(
192
201
  const candidates = listConnections(getDb(), {
193
202
  provider: resolved.provider,
194
203
  });
195
- const active = candidates.find((c) => c.status === "active");
204
+ const active = candidates.find(
205
+ (c) =>
206
+ c.status === "active" &&
207
+ isConnectionCompatibleWithModel(c, resolved.model),
208
+ );
196
209
  if (active) {
197
210
  log.info(
198
211
  { provider: resolved.provider, resolvedConnection: active.name },
@@ -216,5 +229,6 @@ export async function resolveDefaultProvider(
216
229
  connectionName,
217
230
  config,
218
231
  resolved.provider,
232
+ resolved.model,
219
233
  );
220
234
  }
@@ -1,3 +1,4 @@
1
+ import { PROVIDER_CATALOG } from "../model-catalog.js";
1
2
  import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provider.js";
2
3
 
3
4
  export interface FireworksProviderOptions {
@@ -8,6 +9,15 @@ export interface FireworksProviderOptions {
8
9
 
9
10
  const DEFAULT_FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference/v1";
10
11
 
12
+ const FIREWORKS_MODEL_EFFORT_CEILINGS: ReadonlyMap<
13
+ string,
14
+ "high" | "xhigh" | "max"
15
+ > = new Map(
16
+ PROVIDER_CATALOG.find((p) => p.id === "fireworks")?.models.flatMap((m) =>
17
+ m.maxEffort ? ([[m.id, m.maxEffort]] as const) : [],
18
+ ) ?? [],
19
+ );
20
+
11
21
  export class FireworksProvider extends OpenAIChatCompletionsProvider {
12
22
  constructor(
13
23
  apiKey: string,
@@ -19,9 +29,17 @@ export class FireworksProvider extends OpenAIChatCompletionsProvider {
19
29
  providerName: "fireworks",
20
30
  providerLabel: "Fireworks",
21
31
  streamTimeoutMs: options.streamTimeoutMs,
22
- // Fireworks' OpenAI-compatible chat-completions API documents only
23
- // low|medium|high for reasoning_effort; sending "xhigh" 4xxs upstream.
32
+ // Fallback for models not declared in the catalog. Most Fireworks
33
+ // chat-completions models only document `low|medium|high`; per-model
34
+ // overrides (e.g. DeepSeek V4 → "max") come from
35
+ // {@link resolveMaxReasoningEffort}.
24
36
  maxReasoningEffort: "high",
25
37
  });
26
38
  }
39
+
40
+ protected override resolveMaxReasoningEffort(
41
+ model: string,
42
+ ): "high" | "xhigh" | "max" {
43
+ return FIREWORKS_MODEL_EFFORT_CEILINGS.get(model) ?? "high";
44
+ }
27
45
  }
@@ -1,7 +1,6 @@
1
1
  import type * as genai from "@google/genai";
2
- import { ApiError, GoogleGenAI } from "@google/genai";
2
+ import { ApiError, GoogleGenAI, ThinkingLevel } from "@google/genai";
3
3
 
4
- import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/cache-boundary.js";
5
4
  import { isAbortReason } from "../../util/abort-reasons.js";
6
5
  import { ProviderError } from "../../util/errors.js";
7
6
  import { getLogger } from "../../util/logger.js";
@@ -34,6 +33,47 @@ function isGemini3Model(model: string): boolean {
34
33
  return model.startsWith("gemini-3") || model.startsWith("models/gemini-3");
35
34
  }
36
35
 
36
+ const THINKING_LEVEL_BY_NAME: Record<string, ThinkingLevel> = {
37
+ minimal: ThinkingLevel.MINIMAL,
38
+ low: ThinkingLevel.LOW,
39
+ medium: ThinkingLevel.MEDIUM,
40
+ high: ThinkingLevel.HIGH,
41
+ };
42
+
43
+ /**
44
+ * Translate the resolved wire-shape `thinking` config into Gemini's
45
+ * `thinkingConfig`. Returns `undefined` when no thinking config was supplied,
46
+ * which lets Google's per-model default apply (e.g. `gemini-3.5-flash`
47
+ * defaults to dynamic medium-level thinking).
48
+ *
49
+ * `enabled: false` maps to `thinkingLevel: MINIMAL` because Gemini 3.x cannot
50
+ * fully disable thinking — `"minimal"` is the floor. `includeThoughts` is
51
+ * gated on `streamThinking` so callers that opted out of streaming thoughts
52
+ * don't pay for thought tokens in the response.
53
+ */
54
+ function buildThinkingConfig(
55
+ thinking: Record<string, unknown> | undefined,
56
+ ): genai.ThinkingConfig | undefined {
57
+ if (!thinking) return undefined;
58
+ if (thinking.type === "disabled") {
59
+ return {
60
+ thinkingLevel: ThinkingLevel.MINIMAL,
61
+ includeThoughts: false,
62
+ };
63
+ }
64
+ if (thinking.type !== "adaptive") return undefined;
65
+
66
+ const result: genai.ThinkingConfig = {};
67
+ if (typeof thinking.level === "string") {
68
+ const mapped = THINKING_LEVEL_BY_NAME[thinking.level];
69
+ if (mapped) result.thinkingLevel = mapped;
70
+ }
71
+ if (typeof thinking.streamThinking === "boolean") {
72
+ result.includeThoughts = thinking.streamThinking;
73
+ }
74
+ return Object.keys(result).length > 0 ? result : undefined;
75
+ }
76
+
37
77
  function stripGeminiHttpOptions(
38
78
  config: genai.GenerateContentConfig,
39
79
  ): genai.GenerateContentConfig {
@@ -175,6 +215,9 @@ export class GeminiProvider implements Provider {
175
215
  const usageAttributionHeaders = configObj?.usageAttributionHeaders as
176
216
  | Record<string, string>
177
217
  | undefined;
218
+ const thinkingConfig = buildThinkingConfig(
219
+ configObj?.thinking as Record<string, unknown> | undefined,
220
+ );
178
221
  const activeModel = modelOverride ?? this.model;
179
222
 
180
223
  try {
@@ -183,14 +226,14 @@ export class GeminiProvider implements Provider {
183
226
  const geminiConfig: genai.GenerateContentConfig = {};
184
227
 
185
228
  if (systemPrompt) {
186
- geminiConfig.systemInstruction = systemPrompt.replaceAll(
187
- SYSTEM_PROMPT_CACHE_BOUNDARY,
188
- "\n",
189
- );
229
+ geminiConfig.systemInstruction = systemPrompt;
190
230
  }
191
231
  if (maxTokens) {
192
232
  geminiConfig.maxOutputTokens = maxTokens;
193
233
  }
234
+ if (thinkingConfig) {
235
+ geminiConfig.thinkingConfig = thinkingConfig;
236
+ }
194
237
  if (tools && tools.length > 0) {
195
238
  geminiConfig.tools = [
196
239
  {