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
@@ -5,8 +5,21 @@
5
5
  */
6
6
  import { SchemaType } from '@google/generative-ai';
7
7
  import { traceHash, stableTraceStringify } from './trace-utils.mjs';
8
- import { normalizeContentForGeminiParts, splitToolContentForGemini } from './media-normalization.mjs';
8
+ import {
9
+ normalizeContentForGeminiParts,
10
+ splitToolContentForGemini,
11
+ geminiPartMetadata,
12
+ } from './media-normalization.mjs';
9
13
  import { providerReplayItems } from './lib/provider-replay.mjs';
14
+ import {
15
+ claudeBridgeInputSchema,
16
+ escapePointer,
17
+ geminiJsonSchemaProblem,
18
+ repairedToolInputSchema,
19
+ reportInvalidTool,
20
+ } from './lib/claude-bridge-schema.mjs';
21
+ import { actionInputUnionFor } from './lib/action-input-contract.mjs';
22
+ import { isGeminiFamilyModel } from './gemini-family.mjs';
10
23
  import { ensureGeminiToolCallSignatures } from './gemini-history-signatures.mjs';
11
24
 
12
25
  // Bounds on persisted provider metadata replayed back into the prompt.
@@ -20,14 +33,22 @@ function explicitGeminiMediaPart(part) {
20
33
  if (typeof inline?.data === 'string' && inline.data) {
21
34
  const mimeType = inline.mimeType || inline.mime_type || inline.mediaType || inline.media_type;
22
35
  if (typeof mimeType === 'string' && mimeType) {
23
- return { inlineData: { mimeType, data: inline.data } };
36
+ return { inlineData: { mimeType, data: inline.data }, ...geminiPartMetadata(part) };
24
37
  }
25
38
  }
39
+ // An explicit fileData part keeps exactly the MIME type it declared; with
40
+ // none, the shared normalizer resolves it from the URI or omits it.
26
41
  const file = part.fileData || part.file_data;
27
42
  const fileUri = file?.fileUri || file?.file_uri;
28
43
  const mimeType = file?.mimeType || file?.mime_type || file?.mediaType || file?.media_type;
29
- if (typeof fileUri === 'string' && fileUri && typeof mimeType === 'string' && mimeType) {
30
- return { fileData: { mimeType, fileUri } };
44
+ if (typeof fileUri === 'string' && fileUri) {
45
+ const info = { fileUri };
46
+ if (typeof mimeType === 'string' && mimeType) info.mimeType = mimeType;
47
+ else {
48
+ const resolved = normalizeContentForGeminiParts([part])[0]?.fileData?.mimeType;
49
+ if (resolved) info.mimeType = resolved;
50
+ }
51
+ return { fileData: info, ...geminiPartMetadata(part) };
31
52
  }
32
53
  return null;
33
54
  }
@@ -66,49 +87,6 @@ function splitGeminiToolContent(content) {
66
87
  };
67
88
  }
68
89
 
69
- const GEMINI_FUNCTION_RESPONSE_MIME = /^(?:image\/(?:png|jpeg|webp)|application\/pdf|text\/plain)$/i;
70
-
71
- function geminiFunctionCapabilities(model) {
72
- const match = String(model || '')
73
- .toLowerCase()
74
- .match(/(?:^|\/)gemini(?:-live)?-(\d+)/);
75
- const major = match ? Number.parseInt(match[1], 10) : null;
76
- const modern = major == null || major >= 3;
77
- return {
78
- functionPartIds: modern,
79
- multimodalFunctionResponse: modern,
80
- };
81
- }
82
-
83
- function toGeminiFunctionResponseMedia(mediaParts) {
84
- const parts = [];
85
- const refs = [];
86
- const external = [];
87
- const omitted = [];
88
- for (const media of mediaParts || []) {
89
- const payload = media?.inlineData || media?.fileData;
90
- const mimeType = String(payload?.mimeType || '').trim();
91
- if (!GEMINI_FUNCTION_RESPONSE_MIME.test(mimeType)) {
92
- if (mimeType) omitted.push(mimeType);
93
- continue;
94
- }
95
- const displayName = `tool_media_${parts.length + 1}`;
96
- if (media.inlineData) {
97
- parts.push({ inlineData: { ...media.inlineData, mimeType, displayName } });
98
- refs.push({ $ref: displayName });
99
- } else {
100
- // FunctionResponse.parts currently documents inlineData only.
101
- // fileData is valid in ordinary Content parts but can 400 when
102
- // nested here, so retain file-backed media as plain JSON metadata.
103
- external.push({
104
- mimeType,
105
- fileUri: String(media.fileData?.fileUri || ''),
106
- });
107
- }
108
- }
109
- return { parts, refs, external, omitted };
110
- }
111
-
112
90
  /**
113
91
  * Convert JSON Schema type string to Gemini SchemaType.
114
92
  * Gemini SDK uses its own enum instead of plain strings.
@@ -549,34 +527,256 @@ function pruneTypeSpecificKeywords(result, rawType) {
549
527
  function needsJsonParameters(schema) {
550
528
  if (typeof schema === 'boolean') return true;
551
529
  if (!schema || typeof schema !== 'object') return false;
552
- // The legacy dialect has no reference vocabulary; preserve both pointers
553
- // and their definitions together, including recursive MCP contracts.
554
- if (['$ref', '$defs', 'definitions'].some((key) => Object.hasOwn(schema, key))) return true;
555
- const constraints = Object.keys(schema).filter(
556
- (key) => !['description', 'title', 'default', 'examples', '$comment'].includes(key)
557
- );
558
- if (!constraints.length || (schema.type === 'array' && !schema.items)) return true;
530
+ return !legacyRepresentable(schema, true);
531
+ }
532
+
533
+ const LEGACY_JSON_TYPES = new Set(['string', 'number', 'integer', 'boolean', 'array', 'object']);
534
+ // Annotation-only keywords: dropping them never widens the accepted arguments.
535
+ const ANNOTATION_KEYS = new Set(['$schema', '$id', '$comment', 'examples']);
536
+ const NON_CONSTRAINT_KEYS = new Set([...ANNOTATION_KEYS, 'description', 'title', 'default', 'example']);
537
+
538
+ /** True when the legacy OpenAPI Schema subset expresses `input` exactly:
539
+ * convertSchema would neither drop a constraint nor invent a replacement. */
540
+ function legacyRepresentable(input, root = false) {
541
+ if (!input || typeof input !== 'object' || Array.isArray(input)) return false;
542
+ const flat = flattenAllOf(input);
543
+ if (flat.conflict) return false;
544
+ const schema = flat.schema;
545
+ const keys = Object.keys(schema);
546
+ if (!keys.some((key) => !NON_CONSTRAINT_KEYS.has(key))) return false;
547
+ for (const key of keys) {
548
+ if (GEMINI_SCHEMA_FIELDS.has(key) || ANNOTATION_KEYS.has(key)) continue;
549
+ // additionalProperties:true is the default; anything else is a constraint.
550
+ if (key === 'additionalProperties' && schema[key] === true) continue;
551
+ return false;
552
+ }
553
+ if (schema.oneOf !== undefined || schema.not !== undefined) return false;
554
+
555
+ const declared = [].concat(schema.type ?? []);
556
+ const nonNull = declared.filter((type) => type !== 'null');
557
+ if (declared.length && !nonNull.length) return false;
558
+ if (nonNull.length > 1 || nonNull.some((type) => !LEGACY_JSON_TYPES.has(type))) return false;
559
+ let type = nonNull[0];
560
+ if (!type && (schema.properties || schema.required)) type = 'object';
561
+ if (!type && schema.items) type = 'array';
562
+
563
+ if (schema.enum !== undefined && (!Array.isArray(schema.enum) || schema.enum.some((v) => typeof v !== 'string'))) {
564
+ return false;
565
+ }
566
+ if (schema.const !== undefined && typeof schema.const !== 'string') return false;
567
+ if (['integer', 'number', 'boolean'].includes(type) && (schema.enum !== undefined || schema.const !== undefined)) {
568
+ return false;
569
+ }
570
+ if (!type && [...ALL_TYPE_SPECIFIC_KEYWORDS].some((key) => schema[key] !== undefined)) return false;
571
+
572
+ const lower = rawBound(schema, 'lower');
573
+ const upper = rawBound(schema, 'upper');
574
+ if ((lower?.exclusive || upper?.exclusive) && type !== 'integer') return false;
575
+ if (lower && upper && lower.value > upper.value) return false;
576
+ for (const [minKey, maxKey] of [
577
+ ['minLength', 'maxLength'],
578
+ ['minItems', 'maxItems'],
579
+ ['minProperties', 'maxProperties'],
580
+ ]) {
581
+ if (Number.isFinite(schema[minKey]) && Number.isFinite(schema[maxKey]) && schema[minKey] > schema[maxKey]) {
582
+ return false;
583
+ }
584
+ }
585
+
586
+ if (type === 'array') {
587
+ if (!schema.items || typeof schema.items !== 'object' || Array.isArray(schema.items)) return false;
588
+ if (!legacyRepresentable(schema.items)) return false;
589
+ }
590
+ if (type === 'object') {
591
+ const props = schema.properties;
592
+ if (props !== undefined && (!props || typeof props !== 'object' || Array.isArray(props))) return false;
593
+ const names = Object.keys(props || {});
594
+ // A free-form object has no legacy form (empty `properties` is rejected);
595
+ // only the root of a no-argument tool may be empty.
596
+ if (!names.length && !root && !Array.isArray(schema.anyOf)) return false;
597
+ if (schema.required !== undefined) {
598
+ if (!Array.isArray(schema.required)) return false;
599
+ if (schema.required.some((name) => typeof name !== 'string' || !names.includes(name))) return false;
600
+ }
601
+ if (!names.every((name) => legacyRepresentable(props[name]))) return false;
602
+ }
603
+ if (schema.anyOf !== undefined) {
604
+ if (!Array.isArray(schema.anyOf) || !schema.anyOf.every((branch) => legacyRepresentable(branch))) return false;
605
+ }
606
+ return true;
607
+ }
608
+
609
+ // Keywords the Gemini endpoints reject or ignore on parametersJsonSchema:
610
+ // vendor extensions (`x-*`) and annotation-only keywords. None of them
611
+ // constrains the accepted arguments, so dropping them keeps the semantics.
612
+ const NON_STANDARD_SCHEMA_KEYS = new Set(['$schema', '$comment', 'deprecated', 'examples']);
613
+ const isNonStandardSchemaKey = (key) => NON_STANDARD_SCHEMA_KEYS.has(key) || key.startsWith('x-');
614
+ // Keys whose value maps names to subschemas (names are data, never stripped),
615
+ // a single subschema, or a list of subschemas.
616
+ const JSON_SCHEMA_MAP_KEYS = ['properties', 'patternProperties', '$defs', 'definitions', 'dependentSchemas'];
617
+ const JSON_SCHEMA_NODE_KEYS = [
618
+ 'items',
619
+ 'additionalItems',
620
+ 'additionalProperties',
621
+ 'unevaluatedItems',
622
+ 'unevaluatedProperties',
623
+ 'contains',
624
+ 'propertyNames',
625
+ 'not',
626
+ 'if',
627
+ 'then',
628
+ 'else',
629
+ ];
630
+ const JSON_SCHEMA_LIST_KEYS = ['prefixItems', 'allOf', 'anyOf', 'oneOf'];
631
+
632
+ function stripNonStandardSchemaKeys(schema) {
633
+ if (Array.isArray(schema)) return schema.map(stripNonStandardSchemaKeys);
634
+ if (!schema || typeof schema !== 'object') return schema;
635
+ const out = {};
636
+ for (const [key, value] of Object.entries(schema)) {
637
+ if (isNonStandardSchemaKey(key)) continue;
638
+ if (JSON_SCHEMA_MAP_KEYS.includes(key) && value && typeof value === 'object' && !Array.isArray(value)) {
639
+ const children = {};
640
+ for (const [name, child] of Object.entries(value)) {
641
+ defineSchemaProperty(children, name, stripNonStandardSchemaKeys(child));
642
+ }
643
+ out[key] = children;
644
+ } else if (JSON_SCHEMA_NODE_KEYS.includes(key) || JSON_SCHEMA_LIST_KEYS.includes(key)) {
645
+ out[key] = stripNonStandardSchemaKeys(value);
646
+ } else {
647
+ out[key] = value;
648
+ }
649
+ }
650
+ return out;
651
+ }
652
+
653
+ const LEGACY_SCHEMA_TYPES = new Set(Object.values(SchemaType));
654
+
655
+ /** Why a legacy `parameters` Schema (the OpenAPI subset convertSchema targets)
656
+ * is rejected by Gemini, as `{ pointer, reason }`, or null when it is valid:
657
+ * an OBJECT root (or none), known types, an `items` schema on every ARRAY,
658
+ * string enums, and `required` names that exist in `properties`. */
659
+ function legacyParametersProblem(node, pointer = '', root = true) {
660
+ const bad = (reason, at = pointer) => ({ pointer: at, reason });
661
+ if (!node || typeof node !== 'object' || Array.isArray(node)) return bad('a Gemini Schema must be an object');
662
+ const { type, properties, required, items, anyOf } = node;
663
+ if (type !== undefined && !LEGACY_SCHEMA_TYPES.has(type))
664
+ return bad(`unsupported type ${JSON.stringify(type)}`, `${pointer}/type`);
665
+ if (root && type !== undefined && type !== SchemaType.OBJECT)
666
+ return bad('the input schema root must have type "object"', `${pointer}/type`);
667
+ if (node.enum !== undefined && (!Array.isArray(node.enum) || node.enum.some((value) => typeof value !== 'string'))) {
668
+ return bad('enum must be an array of strings', `${pointer}/enum`);
669
+ }
670
+ if (type === SchemaType.ARRAY && (!items || typeof items !== 'object' || Array.isArray(items))) {
671
+ return bad('an array schema needs an "items" schema', `${pointer}/items`);
672
+ }
673
+ // A node without its own `properties` (an anyOf branch narrowing the
674
+ // parent's required keys) has nothing to check `required` against.
675
+ if (required !== undefined) {
676
+ const names = properties && typeof properties === 'object' ? Object.keys(properties) : null;
677
+ if (!Array.isArray(required) || (names && required.some((name) => !names.includes(name)))) {
678
+ return bad('required must list properties declared in "properties"', `${pointer}/required`);
679
+ }
680
+ }
559
681
  const children = [
560
- ...Object.values(schema.properties || {}),
561
- ...(schema.items ? [schema.items] : []),
562
- ...(typeof schema.additionalProperties === 'object' ? [schema.additionalProperties] : []),
563
- ...(schema.anyOf || []),
564
- ...(schema.oneOf || []),
565
- ...(schema.allOf || []),
682
+ ...Object.entries(properties || {}).map(([name, child]) => [child, `${pointer}/properties/${escapePointer(name)}`]),
683
+ ...(items ? [[items, `${pointer}/items`]] : []),
684
+ ...(Array.isArray(anyOf) ? anyOf.map((child, i) => [child, `${pointer}/anyOf/${i}`]) : []),
566
685
  ];
567
- return children.some(needsJsonParameters);
686
+ for (const [child, at] of children) {
687
+ const problem = legacyParametersProblem(child, at, false);
688
+ if (problem) return problem;
689
+ }
690
+ return null;
568
691
  }
569
692
 
570
- export function toGeminiTools(tools) {
571
- return {
572
- functionDeclarations: tools.map((t) => ({
573
- name: t.name,
574
- description: t.description,
575
- ...(needsJsonParameters(t.inputSchema)
576
- ? { parametersJsonSchema: structuredClone(t.inputSchema) }
577
- : { parameters: convertSchema(t.inputSchema) }),
578
- })),
579
- };
693
+ /** Why the declaration's schema (`parameters` or `parametersJsonSchema`) is
694
+ * rejected by Gemini, or null. A tool without a schema is sent as written. */
695
+ function geminiDeclarationProblem(declaration) {
696
+ if (declaration.parametersJsonSchema !== undefined) return geminiJsonSchemaProblem(declaration.parametersJsonSchema);
697
+ return declaration.parameters === undefined ? null : legacyParametersProblem(declaration.parameters);
698
+ }
699
+
700
+ // `claudeBridge: true` (Claude models behind Antigravity) always encodes the
701
+ // schema as `parametersJsonSchema`: the bridge hands it to Anthropic as a
702
+ // draft 2020-12 input_schema, and the legacy `parameters` projection
703
+ // (convertSchema) rewrites type arrays, numeric enums and nullable unions.
704
+ // A tool whose schema is invalid for Anthropic is left out and reported
705
+ // (`onToolExcluded`, default console.warn); the other tools are unaffected.
706
+ // Gemini routes validate each final declaration the same way; `validate:
707
+ // false` (an Antigravity model outside the Gemini family) converts without it.
708
+ export function toGeminiTools(tools, { claudeBridge = false, onToolExcluded, validate = true } = {}) {
709
+ const functionDeclarations = [];
710
+ tools.forEach((t, index) => {
711
+ const declaration = { name: t.name, description: t.description };
712
+ if (claudeBridge) {
713
+ // The bridge accepts nested per-action input alternatives.
714
+ const result = claudeBridgeInputSchema(actionInputUnionFor(t.inputSchema));
715
+ if (!result.schema) {
716
+ reportInvalidTool(t.name, index, result, onToolExcluded);
717
+ return;
718
+ }
719
+ declaration.parametersJsonSchema = result.schema;
720
+ } else if (validate) {
721
+ const accepted = acceptedGeminiTool(t, index, onToolExcluded);
722
+ if (!accepted) return;
723
+ Object.assign(declaration, accepted.fields);
724
+ } else {
725
+ Object.assign(declaration, geminiSchemaFields(t.inputSchema));
726
+ }
727
+ functionDeclarations.push(declaration);
728
+ });
729
+ return { functionDeclarations };
730
+ }
731
+
732
+ function geminiSchemaFields(inputSchema) {
733
+ if (needsJsonParameters(inputSchema)) {
734
+ return { parametersJsonSchema: stripNonStandardSchemaKeys(structuredClone(inputSchema)) };
735
+ }
736
+ return { parameters: convertSchema(inputSchema) };
737
+ }
738
+
739
+ // A Gemini endpoint rejects the whole request for one bad declaration. A
740
+ // declaration it would reject is first rebuilt from the lowered schema
741
+ // (draft-07/04 constructs); one still rejected is reported and left out.
742
+ // Returns { tool, fields } (the tool to send, its schema fields) or null.
743
+ function acceptedGeminiTool(tool, index, onToolExcluded) {
744
+ const fields = geminiSchemaFields(tool.inputSchema);
745
+ let problem = geminiDeclarationProblem(fields);
746
+ if (!problem) return { tool, fields };
747
+ const repaired = repairedToolInputSchema(tool.inputSchema, 'gemini');
748
+ if (repaired) {
749
+ const repairedFields = geminiSchemaFields(repaired);
750
+ problem = geminiDeclarationProblem(repairedFields);
751
+ if (!problem) return { tool: { ...tool, inputSchema: repaired }, fields: repairedFields };
752
+ }
753
+ reportInvalidTool(tool.name, index, problem, onToolExcluded, '[gemini] tool');
754
+ return null;
755
+ }
756
+
757
+ /** The tools whose schema a Gemini-family model behind an OpenAI-compatible
758
+ * route (OpenRouter, a gateway) accepts, in order: unchanged, or carrying
759
+ * the lowered schema when only that is accepted. The others are reported
760
+ * through `onToolExcluded`. */
761
+ export function geminiAcceptedTools(tools, onToolExcluded) {
762
+ let changed = false;
763
+ const out = [];
764
+ tools.forEach((tool, index) => {
765
+ const accepted = acceptedGeminiTool(tool, index, onToolExcluded);
766
+ if (accepted?.tool !== tool) changed = true;
767
+ if (accepted) out.push(accepted.tool);
768
+ });
769
+ return changed ? out : tools;
770
+ }
771
+
772
+ /** The `{ name, pointer, reason }` for which a Gemini route leaves `tool`
773
+ * out of its requests, or null when the tool is sent. Reports nothing. */
774
+ export function geminiToolExclusion(tool) {
775
+ let exclusion = null;
776
+ geminiAcceptedTools([tool], (found) => {
777
+ exclusion = found;
778
+ });
779
+ return exclusion;
580
780
  }
581
781
 
582
782
  export function toGeminiNativeTools(nativeTools) {
@@ -595,8 +795,10 @@ export function toGeminiNativeTools(nativeTools) {
595
795
 
596
796
  // The request `tools` array: hosted tools first, then one function-declaration
597
797
  // entry when function tools are present. Empty when neither is present.
598
- export function toGeminiRequestTools(tools, nativeTools) {
599
- const functionTools = tools?.length ? [toGeminiTools(tools)] : [];
798
+ export function toGeminiRequestTools(tools, nativeTools, options) {
799
+ const declarations = tools?.length ? toGeminiTools(tools, options) : null;
800
+ // Every function tool may have been left out as invalid for the provider.
801
+ const functionTools = declarations?.functionDeclarations.length ? [declarations] : [];
600
802
  return [...toGeminiNativeTools(nativeTools), ...functionTools];
601
803
  }
602
804
 
@@ -647,30 +849,65 @@ export function toGeminiToolConfig(toolChoice) {
647
849
  return undefined;
648
850
  }
649
851
 
650
- function toGeminiToolContent(message, toolNameByCallId, capabilities) {
852
+ // One tool result: its functionResponse part, plus any media it carried as
853
+ // ordinary content parts. The ids pair a call with its response (the Claude
854
+ // models behind Antigravity require them) and are harmless for Gemini.
855
+ // Multimodal function responses (FunctionResponse.parts) exist on Gemini 3+.
856
+ // Older Gemini ids and other families (Claude behind Antigravity) keep media
857
+ // as sibling parts of the response turn.
858
+ function supportsFunctionResponseParts(model) {
859
+ if (!isGeminiFamilyModel(model)) return false;
860
+ const major = /gemini-(\d+)/i.exec(String(model))?.[1];
861
+ return major === undefined || Number(major) >= 3;
862
+ }
863
+
864
+ // FunctionResponsePart carries only inlineData{mimeType,data}; anything else
865
+ // (fileData URIs, parts with mediaResolution/videoMetadata) stays a sibling.
866
+ const isNestableMedia = (part) =>
867
+ part?.inlineData && Object.keys(part).length === 1 && Object.keys(part.inlineData).length === 2;
868
+
869
+ // A failed result travels under `error`, the key Gemini's function-calling
870
+ // contract reserves for failures; a successful one keeps `result`.
871
+ const isFailedToolResult = (message) => message.toolKind === 'error' || message.isError === true;
872
+
873
+ // `callsByFinalId` maps a tool result's id to the functionCall the request
874
+ // replays for it. The response must name exactly the id that call carries:
875
+ // the id the transcript settled on (possibly renamed `-2`) can differ from the
876
+ // recorded part, and a recorded Gemini part may carry no id at all, in which
877
+ // case the response carries none either. An unmatched result keeps its own id.
878
+ function toGeminiToolResult(message, toolNameByCallId, nestMedia, callsByFinalId) {
651
879
  const functionName = toolNameByCallId?.get(message.toolCallId) || message.toolCallId || '';
652
- const { response, mediaParts } = splitGeminiToolContent(message.content);
653
- const media = toGeminiFunctionResponseMedia(mediaParts);
654
- if (media.refs.length) response.media = media.refs;
655
- if (media.external.length) response.externalMedia = media.external;
656
- if (media.omitted.length) response.omittedMediaTypes = media.omitted;
880
+ const { response: rawResponse, mediaParts } = splitGeminiToolContent(message.content);
881
+ const response = isFailedToolResult(message) && 'result' in rawResponse ? { error: rawResponse.result } : rawResponse;
657
882
  const functionResponse = { name: functionName, response };
658
- if (capabilities.functionPartIds && typeof message.toolCallId === 'string' && message.toolCallId) {
659
- functionResponse.id = message.toolCallId;
660
- }
661
- if (capabilities.multimodalFunctionResponse && media.parts.length) {
662
- functionResponse.parts = media.parts;
663
- }
883
+ const replayedCall = callsByFinalId?.get(message.toolCallId);
884
+ const responseId = replayedCall ? replayedCall.id : message.toolCallId;
885
+ if (typeof responseId === 'string' && responseId) functionResponse.id = responseId;
886
+ if (!nestMedia) return { functionResponsePart: { functionResponse }, mediaParts };
887
+ const nested = mediaParts.filter(isNestableMedia);
888
+ if (nested.length) functionResponse.parts = nested;
664
889
  return {
665
- content: { role: 'user', parts: [{ functionResponse }] },
666
- trailingMediaParts: capabilities.multimodalFunctionResponse ? [] : media.parts,
890
+ functionResponsePart: { functionResponse },
891
+ mediaParts: mediaParts.filter((part) => !isNestableMedia(part)),
667
892
  };
668
893
  }
669
894
 
670
- function toGeminiContent(message, capabilities) {
895
+ // A replay recorded by a non-Gemini model (Claude behind Antigravity) carries
896
+ // signatures Gemini rejects: its replay envelope and the signed metadata
897
+ // derived from the same response must not reach a Gemini request.
898
+ function hasForeignReplay(message) {
899
+ const replay = message?.providerReplay;
900
+ if (replay?.provider !== 'gemini' && replay?.provider !== 'antigravity') return false;
901
+ const recorded = replay.requestContext?.model;
902
+ return typeof recorded === 'string' && recorded !== '' && !isGeminiFamilyModel(recorded);
903
+ }
904
+
905
+ function toGeminiContent(message) {
671
906
  if (!message || message.role === 'system') return null;
907
+ const foreign = message.role === 'assistant' && hasForeignReplay(message);
908
+ if (foreign) message = { ...message, providerMetadata: undefined };
672
909
  const orderedReplay =
673
- message.role === 'assistant' ? providerReplayItems(message, ['gemini', 'antigravity']) : undefined;
910
+ message.role === 'assistant' && !foreign ? providerReplayItems(message, ['gemini', 'antigravity']) : undefined;
674
911
  if (orderedReplay?.length) {
675
912
  return { role: 'model', parts: orderedReplay };
676
913
  }
@@ -689,10 +926,11 @@ function toGeminiContent(message, capabilities) {
689
926
  functionCall: {
690
927
  name: tc.name,
691
928
  args: tc.arguments,
692
- ...(capabilities.functionPartIds && typeof tc.id === 'string' && tc.id ? { id: tc.id } : {}),
929
+ ...(typeof tc.id === 'string' && tc.id ? { id: tc.id } : {}),
693
930
  },
694
931
  };
695
932
  if (
933
+ !foreign &&
696
934
  typeof tc.thoughtSignature === 'string' &&
697
935
  tc.thoughtSignature &&
698
936
  tc.thoughtSignature.length <= MAX_THOUGHT_SIGNATURE_CHARS
@@ -765,45 +1003,64 @@ function geminiThoughtPartsFromMetadata(message) {
765
1003
 
766
1004
  export function toGeminiContents(messages, model = '', { repairToolSignatures = true } = {}) {
767
1005
  const contents = [];
768
- const capabilities = geminiFunctionCapabilities(model);
769
1006
  // Map synthetic toolCallId -> function name from prior assistant
770
1007
  // tool_calls so each functionResponse part carries the real function name.
771
1008
  const toolNameByCallId = new Map();
1009
+ // Final call id -> the functionCall the request replays for it. Replayed
1010
+ // assistant turns are the raw recorded parts, so a generated or renamed id
1011
+ // never appears on them. Claude/GPT-OSS routes need the pair to share the
1012
+ // final id, so it is stamped on the part; a Gemini part keeps exactly what
1013
+ // the server sent (possibly no id) and the response follows it.
1014
+ const callsByFinalId = new Map();
1015
+ const assistantContent = new Map();
1016
+ const stampFinalIds = !!model && !isGeminiFamilyModel(model);
772
1017
  for (const m of messages) {
773
1018
  if (m?.role === 'assistant' && Array.isArray(m.toolCalls)) {
774
1019
  for (const tc of m.toolCalls) {
775
1020
  if (tc?.id && tc?.name) toolNameByCallId.set(tc.id, tc.name);
776
1021
  }
1022
+ const content = toGeminiContent(m);
1023
+ assistantContent.set(m, content);
1024
+ const replayed = (content?.parts || []).filter((part) => part?.functionCall);
1025
+ m.toolCalls.forEach((tc, index) => {
1026
+ if (!tc?.id) return;
1027
+ // Positional when the turn replays one call per tool call (the id may
1028
+ // be renamed, and a bridged call_tool keeps its wire name and id);
1029
+ // otherwise only a part already carrying the id can be matched.
1030
+ const part =
1031
+ replayed.length === m.toolCalls.length ? replayed[index] : replayed.find((p) => p.functionCall.id === tc.id);
1032
+ if (!part) return;
1033
+ if (stampFinalIds) part.functionCall.id = tc.id;
1034
+ callsByFinalId.set(tc.id, part.functionCall);
1035
+ });
777
1036
  }
778
1037
  }
779
- let pendingToolMediaParts = [];
780
- const flushToolMedia = () => {
781
- if (!pendingToolMediaParts.length) return;
782
- contents.push({ role: 'user', parts: pendingToolMediaParts });
783
- pendingToolMediaParts = [];
784
- };
1038
+ // Consecutive tool results share one user turn: every functionResponse part
1039
+ // first (one per call, in call order), then the media the results carried as
1040
+ // sibling inlineData/fileData parts.
1041
+ let toolTurn = null;
1042
+ const nestMedia = supportsFunctionResponseParts(model);
785
1043
  for (const message of messages) {
786
1044
  if (message?.role === 'tool') {
787
- const { content, trailingMediaParts } = toGeminiToolContent(message, toolNameByCallId, capabilities);
788
- const last = contents[contents.length - 1];
789
- if (
790
- last?.role === 'user' &&
791
- Array.isArray(last.parts) &&
792
- last.parts.length &&
793
- last.parts.every((part) => part?.functionResponse)
794
- ) {
795
- last.parts.push(...content.parts);
796
- } else {
797
- contents.push(content);
1045
+ const { functionResponsePart, mediaParts } = toGeminiToolResult(
1046
+ message,
1047
+ toolNameByCallId,
1048
+ nestMedia,
1049
+ callsByFinalId
1050
+ );
1051
+ if (!toolTurn) {
1052
+ toolTurn = { content: { role: 'user', parts: [] }, responseCount: 0 };
1053
+ contents.push(toolTurn.content);
798
1054
  }
799
- pendingToolMediaParts.push(...trailingMediaParts);
1055
+ toolTurn.content.parts.splice(toolTurn.responseCount, 0, functionResponsePart);
1056
+ toolTurn.responseCount += 1;
1057
+ toolTurn.content.parts.push(...mediaParts);
800
1058
  continue;
801
1059
  }
802
- flushToolMedia();
803
- const content = toGeminiContent(message, capabilities);
1060
+ toolTurn = null;
1061
+ const content = assistantContent.has(message) ? assistantContent.get(message) : toGeminiContent(message);
804
1062
  if (content) contents.push(content);
805
1063
  }
806
- flushToolMedia();
807
1064
  return repairToolSignatures ? ensureGeminiToolCallSignatures(contents, model) : contents;
808
1065
  }
809
1066
 
@@ -20,6 +20,7 @@ export function geminiTextLeakGuardFor({ tools, callbacks }) {
20
20
  onTextDelta: callbacks.onTextDelta,
21
21
  onToolCall: callbacks.onToolCall,
22
22
  onStreamDelta: callbacks.onStreamDelta,
23
+ deferToolCalls: true,
23
24
  });
24
25
  }
25
26
 
@@ -71,7 +72,7 @@ function linkSdkRequestController(attemptSignal) {
71
72
  return { controller, detachParent, clearConnectTimer };
72
73
  }
73
74
 
74
- export async function streamGeminiSdkAttempt(genModel, stream, attemptSignal) {
75
+ export async function streamGeminiSdkAttempt(genModel, stream, attemptSignal, onConnected = null) {
75
76
  const { contents, callbacks } = stream;
76
77
  const link = linkSdkRequestController(attemptSignal);
77
78
  const { controller } = link;
@@ -89,6 +90,7 @@ export async function streamGeminiSdkAttempt(genModel, stream, attemptSignal) {
89
90
  // the parent link attached so a later abort during streaming still
90
91
  // reaches the request.
91
92
  link.clearConnectTimer();
93
+ onConnected?.();
92
94
  const textLeakGuard = geminiTextLeakGuardFor(stream);
93
95
  const response = await consumeGeminiSdkStream(streamResult, {
94
96
  signal: attemptSignal,