mixdog 1.2.1 → 1.2.3

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 (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -4,6 +4,8 @@
4
4
  // effort to a supported level and serializes it for the provider protocol.
5
5
  // First-party providers never route through here.
6
6
 
7
+ import { isTogetherBaseURL } from './openai-compat-reasoning-field.mjs';
8
+
7
9
  export const CUSTOM_EFFORT_LEVELS = Object.freeze(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
8
10
  const RANK = new Map(CUSTOM_EFFORT_LEVELS.map((level, index) => [level, index]));
9
11
 
@@ -63,16 +65,30 @@ export function snapCustomEffort(levels, effort) {
63
65
  }
64
66
 
65
67
  const EMPTY = Object.freeze({ level: null, fields: {}, thinking: null, replay: false });
68
+ // Chat-only extensions on top of the standard `reasoning_effort`.
69
+ const CHAT_ONLY_WIRE_FORMATS = new Set(['deepseek', 'together', 'vllm']);
70
+
71
+ /**
72
+ * The effective wire format of a row: its declared format, else `together`
73
+ * when the provider's own base URL is Together AI (whose hybrid models toggle
74
+ * reasoning with a `reasoning.enabled` flag), else `standard`.
75
+ */
76
+ export function customWireFormat(model, baseURL) {
77
+ const declared = model?.customReasoning?.wireFormat;
78
+ if (CHAT_ONLY_WIRE_FORMATS.has(declared)) return declared;
79
+ return isTogetherBaseURL(baseURL) ? 'together' : 'standard';
80
+ }
66
81
 
67
82
  /**
68
- * @param {{ protocol: 'openai-chat'|'openai-responses'|'anthropic', model: object|null, effort: string|null|undefined }} input
83
+ * @param {{ protocol: 'openai-chat'|'openai-responses'|'anthropic', model: object|null, effort: string|null|undefined, baseURL?: string }} input
69
84
  * @returns {{ level: string|null, fields: object, thinking: 'on'|'off'|null, replay: boolean }}
70
85
  */
71
- export function resolveCustomReasoning({ protocol, model, effort } = {}) {
86
+ export function resolveCustomReasoning({ protocol, model, effort, baseURL } = {}) {
72
87
  const custom = model?.customReasoning || {};
73
- const wireFormat = custom.wireFormat === 'deepseek' ? 'deepseek' : 'standard';
74
- // DeepSeek's `thinking` extension exists only on the Chat wire.
75
- if (wireFormat === 'deepseek' && protocol !== 'openai-chat') return { ...EMPTY, fields: {} };
88
+ const wireFormat = protocol === 'openai-chat' ? customWireFormat(model, baseURL) : 'standard';
89
+ // The `thinking` / `reasoning.enabled` / chat_template_kwargs extensions
90
+ // exist only on the Chat wire.
91
+ if (CHAT_ONLY_WIRE_FORMATS.has(custom.wireFormat) && protocol !== 'openai-chat') return { ...EMPTY, fields: {} };
76
92
  const level = snapCustomEffort(customEffortLevels(model), effort);
77
93
  let thinking = null;
78
94
  if (level !== null) thinking = level === 'none' ? 'off' : 'on';
@@ -86,6 +102,18 @@ export function resolveCustomReasoning({ protocol, model, effort } = {}) {
86
102
  level === 'none'
87
103
  ? { thinking: { type: 'disabled' } }
88
104
  : { thinking: { type: 'enabled' }, reasoning_effort: value };
105
+ } else if (wireFormat === 'together') {
106
+ // Together: `reasoning.enabled` toggles hybrid models (those that can
107
+ // be turned off); `reasoning_effort` sets the depth of the others.
108
+ if (level === 'none') fields = { reasoning: { enabled: false } };
109
+ else {
110
+ fields = { reasoning_effort: value };
111
+ if (customEffortLevels(model)?.includes('none')) fields.reasoning = { enabled: true };
112
+ }
113
+ } else if (wireFormat === 'vllm') {
114
+ // vLLM switches thinking through the chat template.
115
+ fields = { chat_template_kwargs: { enable_thinking: level !== 'none' } };
116
+ if (level !== 'none') fields.reasoning_effort = value;
89
117
  } else {
90
118
  fields = { reasoning_effort: value };
91
119
  }
@@ -101,7 +129,6 @@ export function resolveCustomReasoning({ protocol, model, effort } = {}) {
101
129
  // An explicit replay flag wins over the catalog's reasoning_content field.
102
130
  const replayFlag =
103
131
  typeof custom.replay === 'boolean' ? custom.replay : model?.reasoningContentField === 'reasoning_content';
104
- const replay =
105
- protocol === 'openai-chat' && replayFlag && thinking !== 'off' && !/reasoner/i.test(String(model?.id || ''));
132
+ const replay = protocol === 'openai-chat' && replayFlag && thinking !== 'off';
106
133
  return { level, fields, thinking, replay };
107
134
  }
@@ -42,17 +42,43 @@ function customToolArgumentsFromInput(name, input) {
42
42
  return { input: text };
43
43
  }
44
44
 
45
+ // Responses calls of a tool loaded from a declared namespace carry
46
+ // `namespace` beside `name`. Mixdog declares no namespaces today, so this is
47
+ // parse-side preservation only: a call that carries one keeps it on its
48
+ // record (and in replay), and its dispatch dedupe identity is qualified, so it
49
+ // is never conflated with a same-named top-level tool.
50
+ export function toolCallNamespace(item) {
51
+ return typeof item?.namespace === 'string' && item.namespace ? item.namespace : '';
52
+ }
53
+
54
+ /** Copy the source item's namespace onto a call record (mutates; returns it). */
55
+ export function withToolCallNamespace(call, source) {
56
+ const namespace = toolCallNamespace(source);
57
+ if (call && namespace && !call.namespace) call.namespace = namespace;
58
+ return call;
59
+ }
60
+
61
+ /** Dispatch dedupe identity: the namespace-qualified tool name. */
62
+ export function qualifiedToolCallName(call) {
63
+ const namespace = toolCallNamespace(call);
64
+ const name = call?.name || '';
65
+ return namespace ? `${namespace}.${name}` : name;
66
+ }
67
+
45
68
  export function customToolCallFromResponseItem(item) {
46
69
  if (item?.type !== 'custom_tool_call') return null;
47
70
  const id = item.call_id || item.id || '';
48
71
  const name = item.name || '';
49
72
  if (!id || !name) return null;
50
- return {
51
- id,
52
- name,
53
- arguments: customToolArgumentsFromInput(name, item.input ?? ''),
54
- nativeType: 'custom_tool_call',
55
- };
73
+ return withToolCallNamespace(
74
+ {
75
+ id,
76
+ name,
77
+ arguments: customToolArgumentsFromInput(name, item.input ?? ''),
78
+ nativeType: 'custom_tool_call',
79
+ },
80
+ item
81
+ );
56
82
  }
57
83
 
58
84
  export function isCustomToolCallRecord(call) {
@@ -0,0 +1,67 @@
1
+ /**
2
+ * DeepSeek: Chat Completions at https://api.deepseek.com plus the Anthropic
3
+ * Messages endpoint at https://api.deepseek.com/anthropic (the SDK appends
4
+ * /v1/messages). Per DeepSeek's Anthropic API docs that endpoint carries
5
+ * thinking and tool_use/tool_result blocks and ignores cache_control and
6
+ * anthropic-beta; agent/tool sessions use it, tool-less one-shot requests stay
7
+ * on Chat (wire-route.mjs). DeepSeek has no Responses endpoint.
8
+ */
9
+ import { WireGatewayProvider, messagesBaseFromOpenAIBase } from './wire-gateway.mjs';
10
+ import { OPENAI_COMPAT_PRESETS } from './openai-compat-presets.mjs';
11
+
12
+ export function deepSeekMessagesBaseURL(configuredBaseURL) {
13
+ return `${messagesBaseFromOpenAIBase(configuredBaseURL || OPENAI_COMPAT_PRESETS.deepseek.baseURL)}/anthropic`;
14
+ }
15
+
16
+ // Requested effort → output_config.effort (thinking_mode docs: minimal/low →
17
+ // low, medium/high/xhigh → high, max/ultra → max).
18
+ const DEEPSEEK_EFFORT = Object.freeze({
19
+ minimal: 'low',
20
+ low: 'low',
21
+ medium: 'high',
22
+ high: 'high',
23
+ xhigh: 'high',
24
+ max: 'max',
25
+ ultra: 'max',
26
+ });
27
+ const DEEPSEEK_OFF = new Set(['none', 'off', 'disabled']);
28
+
29
+ /**
30
+ * DeepSeek's own effort contract on its Messages endpoint: thinking is on by
31
+ * default and `budget_tokens` is ignored, so an effort goes in
32
+ * `output_config.effort`; off is `thinking:{type:'disabled'}` together with the
33
+ * documented Anthropic-format toggle `reasoning:{effort:'none'}`. No effort
34
+ * leaves the default (thinking on, effort high). Always handles the request.
35
+ */
36
+ export function deepSeekEffortProjection(body, { effort } = {}) {
37
+ const level = String(effort ?? '')
38
+ .trim()
39
+ .toLowerCase();
40
+ if (DEEPSEEK_OFF.has(level)) {
41
+ body.thinking = { type: 'disabled' };
42
+ body.reasoning = { effort: 'none' };
43
+ return true;
44
+ }
45
+ const mapped = DEEPSEEK_EFFORT[level];
46
+ if (mapped) {
47
+ const existing = body.output_config && typeof body.output_config === 'object' ? body.output_config : {};
48
+ body.output_config = { ...existing, effort: mapped };
49
+ }
50
+ return true;
51
+ }
52
+
53
+ export class DeepSeekProvider extends WireGatewayProvider {
54
+ constructor(config = {}) {
55
+ super('deepseek', config, {
56
+ baseURL: deepSeekMessagesBaseURL(config.baseURL),
57
+ // The endpoint has no document block of any kind (PDFs included).
58
+ nativePdf: false,
59
+ nativeDocuments: false,
60
+ // disable_parallel_tool_use is ignored on every tool_choice.
61
+ supportsDisableParallelToolUse: false,
62
+ // Image `source.type: file` needs the Files API beta, on those requests only.
63
+ fileIdImageBeta: 'files-api-2025-04-14',
64
+ messagesEffortProjection: deepSeekEffortProjection,
65
+ });
66
+ }
67
+ }
@@ -7,6 +7,9 @@ export const EFFORT_CONFIGURATION_BETA = 'mid-conversation-output-config-2026-07
7
7
  // first version checked on the wire (update accepted, prompt cache kept), and
8
8
  // every later version of that family. A model that turns out to reject the
9
9
  // update is switched off at runtime (markEffortConfigurationUnsupported).
10
+ // The Anthropic catalogs publish no per-model flag for it, so a measured
11
+ // floor is kept for the families already checked: below it the rejection is
12
+ // certain, and every request would pay a failed attempt first.
10
13
  const ANTHROPIC_MIN_VERSION = Object.freeze({
11
14
  opus: [5, 0],
12
15
  sonnet: [5, 5],
@@ -14,6 +17,10 @@ const ANTHROPIC_MIN_VERSION = Object.freeze({
14
17
  fable: [5, 1],
15
18
  mythos: [5, 1],
16
19
  });
20
+ // A family not measured yet starts at the earliest checked major, on the
21
+ // routes that replay a rejected update (the rest cannot recover from one).
22
+ const ANTHROPIC_FIRST_MAJOR = Math.min(...Object.values(ANTHROPIC_MIN_VERSION).map(([major]) => major));
23
+ const ANTHROPIC_REPLAYING_PROVIDERS = new Set(['anthropic-oauth']);
17
24
  // https://developers.openai.com/api/docs/guides/reasoning#change-reasoning-mid-conversation
18
25
  // — GPT-6 and later, standard single-agent mode. The public API publishes no
19
26
  // per-model flag, so the version is its whole answer; the OAuth backend's
@@ -25,14 +32,19 @@ function versionAtLeast([major, minor], [minMajor, minMinor]) {
25
32
  return major > minMajor || (major === minMajor && minor >= minMinor);
26
33
  }
27
34
 
28
- function anthropicVersionSupported(id) {
35
+ function anthropicVersionSupported(provider, id) {
29
36
  const m = id.match(/^claude-([a-z]+)-(\d+)(?:-(\d{1,2}))?$/);
30
- const floor = m && ANTHROPIC_MIN_VERSION[m[1]];
31
- return Boolean(floor) && versionAtLeast([Number(m[2]), Number(m[3] || 0)], floor);
37
+ if (!m) return false;
38
+ const version = [Number(m[2]), Number(m[3] || 0)];
39
+ const floor = ANTHROPIC_MIN_VERSION[m[1]];
40
+ if (floor) return versionAtLeast(version, floor);
41
+ return ANTHROPIC_REPLAYING_PROVIDERS.has(provider) && version[0] >= ANTHROPIC_FIRST_MAJOR;
32
42
  }
33
43
 
44
+ // Any `gpt-<major>` id, whatever follows the major (tier names, minors,
45
+ // snapshots), so a later naming scheme needs no edit.
34
46
  function openAiVersionSupported(id) {
35
- const m = id.match(/^gpt-(\d+)(?:-\d+)?(?:-[a-z]+)?$/);
47
+ const m = id.match(/^gpt-(\d+)(?:-|$)/);
36
48
  return Boolean(m) && Number(m[1]) >= OPENAI_MIN_MAJOR;
37
49
  }
38
50
 
@@ -110,11 +122,25 @@ function openAiSupportsEffortUpdates(provider, model, id) {
110
122
  return declared ?? openAiVersionSupported(id);
111
123
  }
112
124
 
125
+ // A custom route on the Responses wire (`opts.protocol`) serving GPT-6 or
126
+ // later takes the same update as the official routes. The version is read
127
+ // from the id's last `/` segment, so gateway ids like `openai/gpt-6.1-sol` count.
128
+ function customResponsesSupportsEffortUpdates(provider, opts, id) {
129
+ return (
130
+ isCustomProviderName(provider) &&
131
+ opts.protocol === 'openai-responses' &&
132
+ openAiVersionSupported(id.slice(id.lastIndexOf('/') + 1))
133
+ );
134
+ }
135
+
113
136
  export function effortConfigurationMode(provider, model, opts = {}) {
114
137
  const id = modelKey(model);
115
138
  if (opts.effortConfigurationEnabled === false || Number(opts.thinkingBudgetTokens) > 0) return null;
116
139
  if (unsupportedModels.has(`${provider}:${id}`)) return null;
117
- if (OPENAI_PROVIDERS.has(provider) && openAiSupportsEffortUpdates(provider, model, id)) {
140
+ if (
141
+ (OPENAI_PROVIDERS.has(provider) && openAiSupportsEffortUpdates(provider, model, id)) ||
142
+ customResponsesSupportsEffortUpdates(provider, opts, id)
143
+ ) {
118
144
  const parameters = opts.modelParameters || {};
119
145
  const mode = opts.reasoning?.mode ?? parameters.reasoning_mode ?? parameters.mode ?? 'standard';
120
146
  if (mode !== 'standard' || opts.multiAgent === true || parameters.multi_agent === true) return null;
@@ -122,7 +148,7 @@ export function effortConfigurationMode(provider, model, opts = {}) {
122
148
  }
123
149
  if (
124
150
  ANTHROPIC_PROVIDERS.has(provider) &&
125
- anthropicVersionSupported(id) &&
151
+ anthropicVersionSupported(provider, id) &&
126
152
  opts.disableBetaHeaders !== true &&
127
153
  (!opts.baseURL || /^https:\/\/api\.anthropic\.com(?:\/|$)/.test(opts.baseURL))
128
154
  )
@@ -132,7 +158,8 @@ export function effortConfigurationMode(provider, model, opts = {}) {
132
158
 
133
159
  // Custom providers on the Chat and Responses wires take a fresh effort with
134
160
  // every request, so auto effort sends a turn's or step's effort as that
135
- // request's own effort: no mid-conversation update, no beta header. A custom
161
+ // request's own effort: no mid-conversation update, no beta header (except a
162
+ // Responses-wire GPT-6+ model, which takes the 'responses' update). A custom
136
163
  // Anthropic-wire provider keeps auto effort off.
137
164
  const CUSTOM_AUTO_EFFORT_PROTOCOLS = new Set(['openai-chat', 'openai-responses']);
138
165
 
@@ -156,22 +183,31 @@ export function autoEffortModel(providerName, providerImpl, model) {
156
183
  // list from falling back to a family ladder.
157
184
  return { id: model, reasoningLevels: anthropicEffortLevelsFor(model), customReasoning: true };
158
185
  }
159
- if (!isCustomProviderName(providerName)) return { id: model };
186
+ // Every other route reads the provider's own cached model row, the source
187
+ // route resolution (lookupModelMeta) uses; a bare id has no levels and
188
+ // skips the judge.
160
189
  return { ...(providerImpl?.getCachedModelInfo?.(model) || {}), id: model };
161
190
  }
162
191
 
163
192
  /** The effort-change mode of a session's route: 'responses' / 'anthropic'
164
- * (mid-conversation update), 'custom' (per-request effort), or null. */
193
+ * (mid-conversation update), 'custom' (per-request effort), or null. A
194
+ * custom route takes an update mode only when its model declares levels. */
165
195
  export function turnEffortConfigurationMode(session, provider) {
166
- const opts = { ...(provider?.config || {}), modelParameters: session.modelParameters || {} };
196
+ const protocol = provider?.customConfig?.protocol;
197
+ const opts = { ...(provider?.config || {}), modelParameters: session.modelParameters || {}, protocol };
198
+ const custom = customAutoEffortCapable(
199
+ session.provider,
200
+ protocol,
201
+ autoEffortModel(session.provider, provider, session.model)
202
+ );
167
203
  const mode = effortConfigurationMode(session.provider, session.model, opts);
168
- if (mode) return mode;
169
- const model = autoEffortModel(session.provider, provider, session.model);
170
- return customAutoEffortCapable(session.provider, provider?.customConfig?.protocol, model) ? 'custom' : null;
204
+ if (mode && (custom || !isCustomProviderName(session.provider))) return mode;
205
+ return custom ? 'custom' : null;
171
206
  }
172
207
 
173
208
  const CUSTOM_EFFORTS = new Set(CUSTOM_EFFORT_LEVELS);
174
- const effortsFor = (mode) => (mode === 'custom' ? CUSTOM_EFFORTS : EFFORTS);
209
+ // A custom route keeps its own levels (including `none`) in either mode.
210
+ const effortsFor = (mode, provider) => (mode === 'custom' || isCustomProviderName(provider) ? CUSTOM_EFFORTS : EFFORTS);
175
211
 
176
212
  function normalizedEffort(provider, model, effort) {
177
213
  if (ANTHROPIC_PROVIDERS.has(provider)) return normalizeAnthropicEffortInput(effort, model) || null;
@@ -187,8 +223,8 @@ function validSnapshot(value, provider, model, mode) {
187
223
  value.provider === provider &&
188
224
  value.model === modelKey(model) &&
189
225
  value.mode === mode &&
190
- effortsFor(mode).has(value.initialEffort) &&
191
- effortsFor(mode).has(value.effort)
226
+ effortsFor(mode, provider).has(value.initialEffort) &&
227
+ effortsFor(mode, provider).has(value.effort)
192
228
  );
193
229
  }
194
230
 
@@ -199,7 +235,7 @@ function validSnapshot(value, provider, model, mode) {
199
235
  export function prepareTurnEffortConfiguration(session, provider, turnEffort) {
200
236
  const mode = turnEffortConfigurationMode(session, provider);
201
237
  const effort = normalizedEffort(session.provider, session.model, turnEffort ?? session.effort);
202
- if (!mode || !effortsFor(mode).has(effort)) return null;
238
+ if (!mode || !effortsFor(mode, session.provider).has(effort)) return null;
203
239
  const first = (session.messages || []).find((message) =>
204
240
  validSnapshot(message?.meta?.[META_KEY], session.provider, session.model, mode)
205
241
  )?.meta?.[META_KEY];
@@ -221,7 +257,7 @@ export function prepareTurnEffortConfiguration(session, provider, turnEffort) {
221
257
  // step), or null when that effort is not valid for the model.
222
258
  export function stepEffortConfiguration(snapshot, provider, model, effort) {
223
259
  const value = normalizedEffort(provider, model, effort);
224
- if (!snapshot || !EFFORTS.has(value)) return null;
260
+ if (!snapshot || !effortsFor(snapshot.mode, provider).has(value)) return null;
225
261
  return { ...snapshot, effort: value };
226
262
  }
227
263
 
@@ -256,6 +292,32 @@ export function projectEffortConfiguration(messages, provider, model, opts = {})
256
292
  return { mode, initialEffort: seed.initialEffort, effort: current, updates };
257
293
  }
258
294
 
295
+ /**
296
+ * Responses-wire placement of a projection's updates while a history is
297
+ * lowered in order: `before(message)` gives the items to emit ahead of a
298
+ * message, `end()` those after the last one. An update on a tool result
299
+ * applies after its whole batch; one on a user message before it. Adjacent
300
+ * updates are rejected, so a batch update that a user message directly
301
+ * follows yields to that message's own.
302
+ */
303
+ export function responsesEffortUpdates(projection) {
304
+ let afterBatch = null;
305
+ const items = (effort) => (effort ? [{ type: 'configuration_update', reasoning: { effort } }] : []);
306
+ return {
307
+ before(message) {
308
+ const effort = projection?.updates.get(message);
309
+ if (message.role === 'tool') {
310
+ if (effort) afterBatch = effort;
311
+ return [];
312
+ }
313
+ const value = effort || afterBatch;
314
+ afterBatch = null;
315
+ return items(value);
316
+ },
317
+ end: () => items(afterBatch),
318
+ };
319
+ }
320
+
259
321
  // Split only before a user message or after a whole tool-result batch.
260
322
  // Sanitizing each segment before inserting the trusted empty system control
261
323
  // avoids losing it as empty text, and never separates a tool call from its
@@ -14,7 +14,7 @@
14
14
  import { appendAgentTrace } from '../agent-trace.mjs';
15
15
  import {
16
16
  _estimateGeminiCacheTokens,
17
- _geminiCacheMinTokens,
17
+ geminiExplicitCacheMinTokens,
18
18
  _geminiCachePrefixCount,
19
19
  _geminiCachePrefixContents,
20
20
  _geminiCachePrefixHash,
@@ -146,6 +146,12 @@ export function awaitSharedCreate(task, signal) {
146
146
  // role='user' or 'model'; generateContent uses role='function' for
147
147
  // tool_result turns, so that is collapsed to 'user' (functionResponse parts
148
148
  // remain inside).
149
+ // The model id without its `models/` resource prefix; every URL and body that
150
+ // adds the prefix itself starts from this.
151
+ export function geminiBareModelId(model) {
152
+ return String(model || '').replace(/^models\//i, '');
153
+ }
154
+
149
155
  export function geminiCacheCreateBody({
150
156
  model,
151
157
  ttlSeconds,
@@ -157,7 +163,7 @@ export function geminiCacheCreateBody({
157
163
  }) {
158
164
  const cachePrefixContents = _geminiCachePrefixContents(contents, cachePrefixContentCount);
159
165
  const body = {
160
- model: `models/${model}`,
166
+ model: `models/${geminiBareModelId(model)}`,
161
167
  ttl: `${ttlSeconds}s`,
162
168
  };
163
169
  if (systemInstruction) {
@@ -252,9 +258,10 @@ export function dropRejectedGeminiCache(cachedContent, opts) {
252
258
  // the model-specific minimum. Skip the POST entirely when the estimate
253
259
  // is under threshold so we don't spam 400 responses turn-after-turn.
254
260
  export function geminiPrefixBelowMinimum({ model, systemInstruction, geminiTools, contents, opts, currentIter }) {
255
- const minTokens = _geminiCacheMinTokens(model);
261
+ // null: the model is excluded from explicit caching, so never create one.
262
+ const minTokens = geminiExplicitCacheMinTokens(model);
256
263
  const estimatedTokens = _estimateGeminiCacheTokens(systemInstruction, geminiTools, contents);
257
- if (estimatedTokens >= minTokens) return false;
264
+ if (minTokens !== null && estimatedTokens >= minTokens) return false;
258
265
  traceGeminiCache(opts, currentIter, 'gemini_cache_skip', {
259
266
  reason: 'prefix_below_min',
260
267
  estimatedTokens,
@@ -43,12 +43,11 @@ function summarizeTraceContents(contents) {
43
43
  return [...summaries.slice(0, 8), { omittedTurns: summaries.length - 12 }, ...summaries.slice(-4)];
44
44
  }
45
45
 
46
- // Gemini cachedContents API rejects prefixes below the model-specific minimum
47
- // (Gemini 2.0/2.5 = 2048 tokens, Gemini 3.x = 4096 tokens) with HTTP 400
48
- // "Cached content is too small". Estimating chars/4 ≈ tokens lets us skip the
49
- // roundtrip when the prefix cannot satisfy the invariant. Estimate undercount
50
- // is harmless (we attempt and get the same 400 we would have skipped); overcount
51
- // is harmless (we skip, fall back to implicit cache).
46
+ // Gemini cachedContents API rejects prefixes below a model-specific minimum
47
+ // with HTTP 400 "Cached content is too small". Estimating chars/4 ≈ tokens
48
+ // lets us skip the roundtrip when the prefix cannot satisfy the invariant.
49
+ // Estimate undercount is harmless (we attempt and get the same 400 we would
50
+ // have skipped); overcount is harmless (we skip, fall back to implicit cache).
52
51
  export function _estimateGeminiCacheTokens(systemInstruction, geminiTools, contents) {
53
52
  let chars = 0;
54
53
  if (typeof systemInstruction === 'string') chars += systemInstruction.length;
@@ -67,8 +66,26 @@ export function _estimateGeminiCacheTokens(systemInstruction, geminiTools, conte
67
66
  return Math.ceil(chars / 4);
68
67
  }
69
68
 
69
+ // Explicit-cache eligibility and minimum prefix size per model, from the
70
+ // caching docs: explicit caching works on Gemini 3 and 2.5 and is not supported
71
+ // from Gemini 4 onward; documented minimums are 4096 for Gemini 3.x and 2048
72
+ // for 2.5 Flash/Pro. Other ids keep the conservative 4096 floor (skipping a
73
+ // small prefix only falls back to the implicit cache, whereas a floor that is
74
+ // too low would POST a create the server rejects every turn).
75
+ const GEMINI_CACHE_MIN_TOKENS = 4096;
76
+
77
+ // Minimum prefix tokens for an explicit cache, or null when the docs exclude
78
+ // the model from explicit caching.
79
+ export function geminiExplicitCacheMinTokens(model) {
80
+ const bare = String(model || '').replace(/^models\//i, '').toLowerCase();
81
+ const major = /^gemini-(\d+)/.exec(bare);
82
+ if (major && Number(major[1]) >= 4) return null;
83
+ if (/^gemini-2\.5-(?:pro|flash)(?!-lite)(?:-|$)/.test(bare)) return 2048;
84
+ return GEMINI_CACHE_MIN_TOKENS;
85
+ }
86
+
70
87
  export function _geminiCacheMinTokens(model) {
71
- return /^gemini-3/i.test(String(model || '')) ? 4096 : 2048;
88
+ return geminiExplicitCacheMinTokens(model) ?? GEMINI_CACHE_MIN_TOKENS;
72
89
  }
73
90
 
74
91
  export function _geminiCachePrefixCount(contents) {
@@ -110,6 +127,23 @@ const GEMINI_GLOBAL_CACHE_MAX_ENTRIES = 128;
110
127
  export const GEMINI_GLOBAL_CACHE_DELETE_GRACE_MS = 2 * 60 * 1000;
111
128
  const geminiGlobalCaches = new Map();
112
129
  export const geminiGlobalCacheCreates = new Map();
130
+ // Models whose cachedContents.create the server refused as unsupported (not
131
+ // a prefix or quota failure). No catalog publishes explicit-cache support, so
132
+ // the server's own answer decides, once per process.
133
+ const geminiExplicitCacheRefusedModels = new Set();
134
+
135
+ export function markGeminiExplicitCacheRefused(model, err) {
136
+ if (err?.status !== 400) return false;
137
+ if (!/explicit caching is not supported/i.test(String(err?.message || ''))) return false;
138
+ geminiExplicitCacheRefusedModels.add(String(model || ''));
139
+ return true;
140
+ }
141
+
142
+ // True when explicit cache creates must not be attempted: the docs exclude the
143
+ // model, or the server already refused it.
144
+ export function geminiExplicitCacheRefused(model) {
145
+ return geminiExplicitCacheMinTokens(model) === null || geminiExplicitCacheRefusedModels.has(String(model || ''));
146
+ }
113
147
 
114
148
  export function _geminiCredentialFingerprint(apiKey) {
115
149
  return traceHash(String(apiKey || ''));
@@ -224,7 +258,11 @@ export function _resolveGeminiCacheUsage({ usageMetadata, cachedContent, provide
224
258
  firstFinite(usageMetadata?.thoughtsTokenCount, usageMetadata?.thoughts_token_count);
225
259
  const hasExplicitPromptTokens =
226
260
  Object.hasOwn(usageMetadata || {}, 'promptTokenCount') || Object.hasOwn(usageMetadata || {}, 'prompt_token_count');
227
- const inputTokens = hasExplicitPromptTokens ? promptTokens : Math.max(0, totalTokens - outputTokens);
261
+ // toolUsePromptTokenCount (tool-result prompt tokens) is billed as input and
262
+ // reported separately from promptTokenCount; cached tokens stay a subset of
263
+ // the prompt portion.
264
+ const toolUseTokens = firstFinite(usageMetadata?.toolUsePromptTokenCount, usageMetadata?.tool_use_prompt_token_count);
265
+ const inputTokens = hasExplicitPromptTokens ? promptTokens + toolUseTokens : Math.max(0, totalTokens - outputTokens);
228
266
  const reportedCachedTokens = firstFinite(
229
267
  // generateContent UsageMetadata field.
230
268
  usageMetadata?.cachedContentTokenCount,