mixdog 1.2.2 → 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 (415) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/provider-pingpong-live.mjs +509 -0
  4. package/src/agents/advisor/AGENT.md +1 -1
  5. package/src/agents/advisor/agent.json +1 -1
  6. package/src/defaults/shipped-history.json +5 -0
  7. package/src/defaults/skills/setup/SKILL.md +6 -1
  8. package/src/defaults/skills/setup/references/actions.md +44 -22
  9. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  10. package/src/headless-exec.mjs +15 -8
  11. package/src/lib/keychain-cjs.cjs +7 -4
  12. package/src/output-styles/common.md +11 -10
  13. package/src/rules/agent/AGENT.md +5 -5
  14. package/src/rules/lead/LEAD.md +5 -5
  15. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  16. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  17. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  18. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  19. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  21. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  22. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  23. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
  28. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  30. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  31. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  32. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
  39. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  40. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
  41. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  42. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
  43. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
  45. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
  49. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  50. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
  51. package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
  52. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  53. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  54. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  55. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  56. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  57. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  59. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
  60. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
  61. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  62. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
  63. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
  64. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  65. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
  66. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
  67. package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
  68. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  71. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  72. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  73. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  74. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  75. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  76. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  77. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  78. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  80. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  81. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  82. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  83. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  84. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  85. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  86. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +121 -61
  89. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  90. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  91. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  92. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  93. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +42 -24
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +53 -5
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  108. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  109. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  110. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  111. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +25 -4
  112. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  114. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  115. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  117. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  119. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  121. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
  122. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  123. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  124. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  125. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  126. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  127. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  130. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +11 -3
  131. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  132. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  133. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  134. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +147 -8
  135. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  136. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
  137. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  138. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  139. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  140. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  141. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  142. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  147. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  148. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  150. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  151. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  154. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
  156. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  157. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  158. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  159. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  160. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  161. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  162. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  163. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  164. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  165. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  167. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  168. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  169. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  170. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  171. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  172. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +63 -20
  173. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
  174. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  175. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  179. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +4 -1
  180. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  181. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +16 -0
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  184. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  187. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  188. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
  189. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  190. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  192. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  193. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  195. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  196. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +13 -0
  197. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  198. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  199. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  200. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  201. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  203. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  204. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  205. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  206. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  207. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  208. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  209. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  210. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  211. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  212. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  213. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  216. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  217. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  218. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  221. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  223. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  224. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  225. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  226. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  227. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  228. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  229. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  230. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  231. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  232. package/src/runtime/github/tool.mjs +92 -2
  233. package/src/runtime/memory/index.mjs +1 -0
  234. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  235. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  236. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  237. package/src/runtime/memory/lib/pg/process.mjs +31 -26
  238. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
  240. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  241. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  242. package/src/runtime/office/README.md +1 -1
  243. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  244. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  245. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  246. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  247. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  248. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  249. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  250. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  251. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  252. package/src/runtime/office/core/office-sessions.mjs +5 -0
  253. package/src/runtime/office/core/office-transactions.mjs +3 -0
  254. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  255. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  256. package/src/runtime/office/index.mjs +30 -0
  257. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  258. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  259. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  260. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  261. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  262. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  263. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  264. package/src/runtime/shared/buffered-appender.mjs +18 -0
  265. package/src/runtime/shared/config.mjs +78 -18
  266. package/src/runtime/shared/err-text.mjs +6 -0
  267. package/src/runtime/shared/file-permissions.d.mts +6 -1
  268. package/src/runtime/shared/file-permissions.mjs +54 -6
  269. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  270. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  271. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  272. package/src/runtime/shared/loopback-listener.mjs +9 -0
  273. package/src/runtime/shared/provider-api-key.mjs +2 -0
  274. package/src/runtime/shared/review-diff.mjs +52 -0
  275. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  276. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  277. package/src/runtime/shared/slow-span.mjs +114 -0
  278. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  279. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  280. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  281. package/src/runtime/shared/tool-card-model.mjs +5 -2
  282. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  283. package/src/runtime/shared/tool-primitives.mjs +13 -0
  284. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  285. package/src/runtime/shared/tool-surface.mjs +18 -3
  286. package/src/runtime/shared/tool-work-units.mjs +40 -4
  287. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  288. package/src/runtime/shared/transcript-writer.mjs +10 -2
  289. package/src/runtime/shared/turn-changes.mjs +268 -100
  290. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  291. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  292. package/src/runtime/shared/turn-snapshot.mjs +857 -683
  293. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  294. package/src/runtime/shared/user-data-guard.mjs +262 -49
  295. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  296. package/src/runtime/shared/worktrees/contract.mjs +34 -0
  297. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  298. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  299. package/src/runtime/shared/worktrees/git.mjs +8 -3
  300. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  301. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  302. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  303. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  304. package/src/runtime/terminal-bridge/client.mjs +44 -11
  305. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  306. package/src/runtime/tidy/apply.mjs +47 -2
  307. package/src/runtime/tidy/run-engines.mjs +11 -5
  308. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  309. package/src/session-runtime/boot/apis.mjs +13 -5
  310. package/src/session-runtime/boot/facade.mjs +1 -0
  311. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  312. package/src/session-runtime/boot/session.mjs +0 -1
  313. package/src/session-runtime/boot/tools.mjs +4 -1
  314. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  315. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  316. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  317. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  318. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  319. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  320. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  321. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  322. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -3
  323. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  324. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  325. package/src/session-runtime/lifecycle/teardown.mjs +72 -7
  326. package/src/session-runtime/lifecycle-api.mjs +1 -0
  327. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  328. package/src/session-runtime/model-route/set-route.mjs +2 -2
  329. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  330. package/src/session-runtime/native-web-search.mjs +10 -1
  331. package/src/session-runtime/new-session-config.mjs +4 -2
  332. package/src/session-runtime/provider-auth/login.mjs +4 -0
  333. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  334. package/src/session-runtime/runtime-review-api.mjs +8 -2
  335. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  336. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  337. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  338. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  339. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  340. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  341. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  342. package/src/session-runtime/services/agent-tool.mjs +3 -0
  343. package/src/session-runtime/services/channel-admin.mjs +19 -3
  344. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  345. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  346. package/src/session-runtime/services/provider-admin.mjs +81 -15
  347. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  348. package/src/session-runtime/session-turn-api.mjs +14 -5
  349. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  350. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  351. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  352. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  353. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  354. package/src/session-runtime/skills-api.mjs +3 -5
  355. package/src/session-runtime/tool-surface.mjs +5 -1
  356. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  357. package/src/session-runtime/turn/session-ops.mjs +7 -5
  358. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  359. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  360. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  361. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  362. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  363. package/src/session-runtime/turn/turn-run.mjs +25 -9
  364. package/src/session-runtime/usage-stats-api.mjs +43 -11
  365. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  366. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  367. package/src/session-runtime/workspace/transitions.mjs +190 -15
  368. package/src/standalone/daemon-agent-control.mjs +9 -1
  369. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  370. package/src/standalone/daemon-owner.mjs +17 -4
  371. package/src/standalone/daemon-pg-stop.mjs +51 -0
  372. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  373. package/src/standalone/daemon-stop-budget.mjs +18 -0
  374. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  375. package/src/standalone/daemon-telemetry.mjs +19 -0
  376. package/src/standalone/daemon.mjs +61 -1
  377. package/src/standalone/desktop-service-registry.mjs +5 -0
  378. package/src/standalone/local-session-runtime.mjs +70 -19
  379. package/src/standalone/session-client.mjs +42 -0
  380. package/src/standalone/session-protocol.mjs +7 -0
  381. package/src/standalone/session-proxy/projection.mjs +41 -4
  382. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  383. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  384. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  385. package/src/standalone/session-service-api.mjs +6 -1
  386. package/src/standalone/session-state-patch.d.mts +2 -1
  387. package/src/standalone/session-state-patch.mjs +41 -1
  388. package/src/tui/App.jsx +25 -0
  389. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  390. package/src/tui/app/btw-controller.mjs +118 -0
  391. package/src/tui/app/create-app-pickers.mjs +2 -0
  392. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  393. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  394. package/src/tui/app/slash-commands.mjs +13 -3
  395. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  396. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  397. package/src/tui/app/use-global-key-input.mjs +5 -12
  398. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  399. package/src/tui/components/BtwPanel.jsx +53 -0
  400. package/src/tui/components/QuestionPanel.jsx +275 -0
  401. package/src/tui/components/question-panel-model.mjs +156 -0
  402. package/src/tui/dist/index.mjs +2413 -1465
  403. package/src/tui/session/context-state.mjs +4 -2
  404. package/src/tui/session/session-api/commands.mjs +10 -0
  405. package/src/tui/session/session-api/controls.mjs +2 -2
  406. package/src/tui/session/session-api/integrations.mjs +9 -2
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  408. package/src/tui/session/session-api/lifecycle.mjs +2 -1
  409. package/src/tui/session/session-api/settings.mjs +6 -0
  410. package/src/tui/session/session-api.mjs +1 -0
  411. package/src/tui/session/tool-approval.mjs +10 -7
  412. package/src/tui/session/transcript-spill.mjs +14 -7
  413. package/src/tui/session/turn-stream.mjs +174 -31
  414. package/src/tui/session/turn.mjs +12 -5
  415. package/src/workflows/default/WORKFLOW.md +3 -1
@@ -26,7 +26,11 @@ import { createSdkStreamReader } from './gemini-sdk-stream/reader.mjs';
26
26
  import { createRestStreamWatchdogs } from './gemini-rest-stream/watchdogs.mjs';
27
27
  import { drainSseDataLines, sseDataPayload } from './gemini-rest-stream/sse-lines.mjs';
28
28
  import { noteAbandonedUsage } from '../../../shared/llm/usage-context.mjs';
29
- import { applyGeminiErrorContract, assertNoGeminiInBandError } from './gemini-error-contract.mjs';
29
+ import {
30
+ applyGeminiErrorContract,
31
+ assertNoGeminiInBandError,
32
+ geminiFinishReasonKind,
33
+ } from './gemini-error-contract.mjs';
30
34
 
31
35
  export const GEMINI_FIRST_BYTE_TIMEOUT_MS = resolveTimeoutMs(
32
36
  'MIXDOG_GEMINI_FIRST_BYTE_TIMEOUT_MS',
@@ -183,8 +187,10 @@ function stampGeminiStreamFailure(
183
187
  const visible = visibleText.length > 0;
184
188
  // Native functionCall chunks are only dispatched after successful stream
185
189
  // completion in gemini.mjs. Until then a reconnect is safe. Text-leaked
186
- // calls are dispatched while parsing and remain a hard replay boundary.
187
- const pendingTool = leaked;
190
+ // calls are dispatched while parsing and remain a hard replay boundary,
191
+ // unless the guard holds them back (`deferToolCalls`): a held call never
192
+ // runs when the stream fails, so a reconnect cannot double-execute it.
193
+ const pendingTool = leaked && textLeakGuard?.defersToolCalls !== true;
188
194
  try {
189
195
  if (visible) {
190
196
  err.liveTextEmitted = true;
@@ -237,24 +243,31 @@ function aggregateGeminiStreamChunks(responses, label = 'Gemini stream') {
237
243
  // An error envelope anywhere in the stream — including after STOP — fails
238
244
  // the turn instead of aggregating into a success.
239
245
  for (const response of responses) assertNoGeminiInBandError(response, label);
240
- const lastResponse = responses[responses.length - 1];
241
- const aggregatedResponse = {
242
- promptFeedback: lastResponse?.promptFeedback,
243
- };
246
+ const aggregatedResponse = {};
247
+ // Candidates are keyed by their own `index`; chunks that omit it fall back
248
+ // to the position inside that chunk's candidate list.
249
+ const candidatesByIndex = new Map();
244
250
  for (const response of responses) {
251
+ // Early block info must survive later chunks that carry none.
252
+ if (response?.promptFeedback) {
253
+ aggregatedResponse.promptFeedback = { ...aggregatedResponse.promptFeedback, ...response.promptFeedback };
254
+ }
245
255
  if (response?.candidates) {
246
- let candidateIndex = 0;
247
- for (const candidate of response.candidates) {
248
- if (!aggregatedResponse.candidates) aggregatedResponse.candidates = [];
249
- if (!aggregatedResponse.candidates[candidateIndex]) {
250
- aggregatedResponse.candidates[candidateIndex] = { index: candidateIndex };
256
+ response.candidates.forEach((candidate, position) => {
257
+ const candidateIndex = Number.isInteger(candidate?.index) ? candidate.index : position;
258
+ if (!candidatesByIndex.has(candidateIndex)) candidatesByIndex.set(candidateIndex, { index: candidateIndex });
259
+ const aggCand = candidatesByIndex.get(candidateIndex);
260
+ // A later chunk that omits a field never erases an earlier value.
261
+ if (candidate.citationMetadata !== undefined) {
262
+ aggCand.citationMetadata = mergeStreamMetadata(aggCand.citationMetadata, candidate.citationMetadata);
251
263
  }
252
- const aggCand = aggregatedResponse.candidates[candidateIndex];
253
- aggCand.citationMetadata = candidate.citationMetadata;
254
- aggCand.groundingMetadata = candidate.groundingMetadata;
255
- aggCand.finishReason = candidate.finishReason;
256
- aggCand.finishMessage = candidate.finishMessage;
257
- aggCand.safetyRatings = candidate.safetyRatings;
264
+ if (candidate.groundingMetadata !== undefined) {
265
+ aggCand.groundingMetadata = mergeStreamMetadata(aggCand.groundingMetadata, candidate.groundingMetadata);
266
+ }
267
+ if (geminiFinishReasonKind(candidate.finishReason) !== 'none') aggCand.finishReason = candidate.finishReason;
268
+ if (candidate.finishMessage !== undefined) aggCand.finishMessage = candidate.finishMessage;
269
+ if (candidate.safetyRatings !== undefined) aggCand.safetyRatings = candidate.safetyRatings;
270
+ if (candidate.continuationToken !== undefined) aggCand.continuationToken = candidate.continuationToken;
258
271
  if (candidate.content?.parts) {
259
272
  if (!aggCand.content) {
260
273
  aggCand.content = {
@@ -273,36 +286,52 @@ function aggregateGeminiStreamChunks(responses, label = 'Gemini stream') {
273
286
  aggCand.content.parts.push(newPart);
274
287
  }
275
288
  }
276
- candidateIndex++;
277
- }
289
+ });
278
290
  }
279
291
  if (response?.usageMetadata) aggregatedResponse.usageMetadata = response.usageMetadata;
280
292
  }
293
+ if (candidatesByIndex.size) {
294
+ aggregatedResponse.candidates = [...candidatesByIndex.values()].sort((a, b) => a.index - b.index);
295
+ }
281
296
  return aggregatedResponse;
282
297
  }
283
298
 
284
- // A response with neither text nor a tool call (thoughts alone are not text).
285
- function hasNoAnswerContent(aggregated) {
286
- const parts = aggregated?.candidates?.[0]?.content?.parts;
287
- return !(Array.isArray(parts) ? parts : []).some(
288
- (part) => part?.functionCall || (part?.thought !== true && typeof part?.text === 'string' && part.text.trim())
289
- );
299
+ // GroundingMetadata / CitationMetadata arrive in pieces while streaming and
300
+ // are merged, not replaced: groundingChunks carry only the chunks not sent
301
+ // before (appended as-is, so groundingSupports indices stay valid); every
302
+ // other list is a de-duplicated union, nested objects merge, scalars take the
303
+ // latest value.
304
+ function mergeStreamMetadata(previous, next) {
305
+ if (!previous) return next;
306
+ if (!next || typeof next !== 'object') return previous;
307
+ const merged = { ...previous };
308
+ for (const [key, value] of Object.entries(next)) {
309
+ if (value === undefined || value === null) continue;
310
+ const before = previous[key];
311
+ if (Array.isArray(value)) {
312
+ if (key === 'groundingChunks') {
313
+ merged[key] = [...(before || []), ...value];
314
+ } else {
315
+ const seen = new Set((before || []).map((item) => JSON.stringify(item)));
316
+ merged[key] = [...(before || []), ...value.filter((item) => !seen.has(JSON.stringify(item)))];
317
+ }
318
+ } else if (typeof value === 'object' && before && typeof before === 'object') {
319
+ merged[key] = { ...before, ...value };
320
+ } else {
321
+ merged[key] = value;
322
+ }
323
+ }
324
+ return merged;
290
325
  }
291
326
 
292
- function assertGeminiStreamCompleted({
293
- sawStreamChunk,
294
- finishReason,
295
- promptBlockReason,
296
- label,
297
- acceptEmptyNoFinish = false,
298
- aggregated = null,
299
- }) {
327
+ // A stream that ends with no finishReason is unfinished, whatever it carried
328
+ // (thoughts only, an empty body, even right after a tool result); only a
329
+ // STOP that carries no text is a completed, empty answer.
330
+ function assertGeminiStreamCompleted({ sawStreamChunk, finishReason, promptBlockReason, label }) {
300
331
  if (!sawStreamChunk) {
301
332
  throw geminiTruncatedStreamError(`${label} truncated: empty stream`);
302
333
  }
303
- if (!finishReason && !promptBlockReason) {
304
- // Right after a tool result the model may end with nothing at all.
305
- if (acceptEmptyNoFinish && hasNoAnswerContent(aggregated)) return;
334
+ if (geminiFinishReasonKind(finishReason) === 'none' && geminiFinishReasonKind(promptBlockReason) === 'none') {
306
335
  throw geminiTruncatedStreamError(`${label} truncated: no finishReason`);
307
336
  }
308
337
  }
@@ -344,13 +373,23 @@ function relayGeminiStreamText(t, { onTextDelta, textLeakGuard }) {
344
373
  * `part.text` streams. Mirrors the Anthropic OAuth guard: suppress tags from
345
374
  * visible text, synthesize known-tool calls, dispatch via onToolCall.
346
375
  */
347
- export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolCall, onStreamDelta }) {
376
+ export function createGeminiTextLeakGuard({
377
+ knownToolNames,
378
+ onTextDelta,
379
+ onToolCall,
380
+ onStreamDelta,
381
+ deferToolCalls = false,
382
+ }) {
348
383
  const _knownTools = knownToolNameSet(knownToolNames);
349
384
  const _enabled = _knownTools.size > 0;
350
385
  const _isKnownTool = (name) => _knownTools.has(name);
351
386
  let leakBuffer = '';
352
387
  let relayedText = '';
353
388
  const leakedCalls = [];
389
+ // With `deferToolCalls`, recovered calls wait here until the caller has seen
390
+ // the response finish cleanly (releaseDeferredToolCalls); a failed response
391
+ // never runs them.
392
+ const deferredCalls = [];
354
393
  const dispatchedFingerprints = new Set();
355
394
 
356
395
  const dispatchLeakedCall = (recovered) => {
@@ -372,9 +411,12 @@ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolC
372
411
  arguments: args,
373
412
  };
374
413
  leakedCalls.push(call);
375
- try {
376
- onToolCall?.(call);
377
- } catch {}
414
+ if (deferToolCalls) deferredCalls.push(call);
415
+ else {
416
+ try {
417
+ onToolCall?.(call);
418
+ } catch {}
419
+ }
378
420
  try {
379
421
  onStreamDelta?.('tool');
380
422
  } catch {}
@@ -401,6 +443,9 @@ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolC
401
443
  get enabled() {
402
444
  return _enabled;
403
445
  },
446
+ get defersToolCalls() {
447
+ return deferToolCalls === true;
448
+ },
404
449
  feedText(text) {
405
450
  if (!text) return;
406
451
  if (!_enabled) {
@@ -439,6 +484,13 @@ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolC
439
484
  getLeakedToolCalls() {
440
485
  return [...leakedCalls];
441
486
  },
487
+ releaseDeferredToolCalls() {
488
+ for (const call of deferredCalls.splice(0)) {
489
+ try {
490
+ onToolCall?.(call);
491
+ } catch {}
492
+ }
493
+ },
442
494
  getRelayedText() {
443
495
  return relayedText;
444
496
  },
@@ -473,7 +525,6 @@ export async function consumeGeminiRestStreamResponse(
473
525
  unwrapChunk = null,
474
526
  onChunk = null,
475
527
  failureUsage = null,
476
- acceptEmptyNoFinish = false,
477
528
  }
478
529
  ) {
479
530
  const unwrap =
@@ -613,8 +664,6 @@ export async function consumeGeminiRestStreamResponse(
613
664
  finishReason,
614
665
  promptBlockReason,
615
666
  label,
616
- acceptEmptyNoFinish,
617
- aggregated,
618
667
  });
619
668
  } catch (err) {
620
669
  throw stampGeminiStreamFailure(err, { relayedText, textLeakGuard, chunks: allChunks, failureUsage });
@@ -634,7 +683,6 @@ export async function consumeGeminiSdkStream(
634
683
  firstByteTimeoutMs = GEMINI_FIRST_BYTE_TIMEOUT_MS,
635
684
  cancellationGraceMs = 250,
636
685
  failureUsage = null,
637
- acceptEmptyNoFinish = false,
638
686
  }
639
687
  ) {
640
688
  let relayedText = '';
@@ -721,8 +769,6 @@ export async function consumeGeminiSdkStream(
721
769
  finishReason,
722
770
  promptBlockReason,
723
771
  label,
724
- acceptEmptyNoFinish,
725
- aggregated: raw,
726
772
  });
727
773
  return raw;
728
774
  } catch (err) {
@@ -15,14 +15,53 @@ function catalogThinkingLevels(model, provider) {
15
15
  return declared.length ? [...new Set(declared)] : null;
16
16
  }
17
17
 
18
- // Only translate the public option names, not arbitrary effort-to-token ratios.
19
- // Omitting settings preserves the provider's model default. A level is checked
20
- // against the catalog's ladder when one is declared; otherwise the value is sent
21
- // as given (within the wire vocabulary) and the server decides, and an explicit
22
- // thinkingBudget is likewise passed through unvalidated beyond its wire type.
18
+ // Gemini 2.5 models take thinkingBudget only (thinkingLevel is unsupported).
19
+ // Documented ranges: 2.5 Pro 128–32768 (cannot disable), 2.5 Flash 0–24576,
20
+ // 2.5 Flash-Lite 0 or 512–24576; -1 is dynamic thinking for all of them.
21
+ function budgetSpec(model) {
22
+ const bare = String(model || '').replace(/^models\//i, '').toLowerCase();
23
+ if (!/^gemini-2\.5(?:-|$)/.test(bare)) return null;
24
+ if (/^gemini-2\.5-pro/.test(bare)) {
25
+ return { name: 'Gemini 2.5 Pro', min: 128, max: 32768, canDisable: false, efforts: { minimal: 128, low: 1024, medium: 8192, high: 32768 } };
26
+ }
27
+ if (/^gemini-2\.5-flash-lite/.test(bare)) {
28
+ return { name: 'Gemini 2.5 Flash-Lite', min: 512, max: 24576, canDisable: true, efforts: { minimal: 512, low: 1024, medium: 8192, high: 24576 } };
29
+ }
30
+ return { name: 'Gemini 2.5 Flash', min: 0, max: 24576, canDisable: true, efforts: { minimal: 0, low: 1024, medium: 8192, high: 24576 } };
31
+ }
32
+
33
+ // Levels documented for models whose ladder differs from the generic wire
34
+ // vocabulary (a catalog ladder, when declared, still takes precedence).
35
+ function documentedThinkingLevels(model) {
36
+ const bare = String(model || '').replace(/^models\//i, '').toLowerCase();
37
+ if (bare === 'gemini-4-argon' || bare === 'gemini-3.8-flash') return ['low', 'medium', 'high'];
38
+ return null;
39
+ }
40
+
41
+ function checkBudget(model, spec, budget) {
42
+ if (!Number.isInteger(budget) || budget < -1) {
43
+ throw new TypeError('thinkingBudget must be -1 (dynamic), 0, or a positive integer.');
44
+ }
45
+ if (!spec || budget === -1) return;
46
+ if (budget === 0 && !spec.canDisable) {
47
+ throw new TypeError(`${model} (${spec.name}) cannot disable thinking; thinkingBudget 0 is not allowed.`);
48
+ }
49
+ if (budget !== 0 && (budget < spec.min || budget > spec.max)) {
50
+ throw new TypeError(`${model} (${spec.name}) thinkingBudget must be -1, ${spec.canDisable ? '0, or ' : ''}${spec.min}–${spec.max}; received ${budget}.`);
51
+ }
52
+ }
53
+
54
+ // Only translate the public option names. Omitting settings preserves the
55
+ // provider's model default. Gemini 2.5 models use thinkingBudget (a generic
56
+ // effort maps to a budget; an explicit thinkingLevel is rejected locally and
57
+ // budgets are range-checked). Other models use thinkingLevel, checked against
58
+ // the catalog/documented ladder; unknown models pass values within the wire
59
+ // vocabulary and the server decides.
23
60
  export function geminiThinkingConfig(model, opts = {}, { includeThoughts, provider = 'gemini' } = {}) {
24
61
  const rawBudget = opts.thinkingBudget ?? opts.thinkingBudgetTokens;
25
62
  const hasBudget = rawBudget !== undefined && rawBudget !== null && rawBudget !== '';
63
+ const spec = budgetSpec(model);
64
+ const explicitLevel = opts.thinkingLevel == null ? '' : String(opts.thinkingLevel).trim().toLowerCase();
26
65
  const rawLevel = opts.thinkingLevel ?? (hasBudget ? undefined : opts.effort);
27
66
  const level = rawLevel == null ? '' : String(rawLevel).trim().toLowerCase();
28
67
  const config = {};
@@ -31,8 +70,16 @@ export function geminiThinkingConfig(model, opts = {}, { includeThoughts, provid
31
70
  if (level && hasBudget) {
32
71
  throw new TypeError('Choose thinkingLevel/effort or thinkingBudget, not both.');
33
72
  }
34
- if (level) {
35
- const supported = catalogThinkingLevels(model, provider) ?? LEVELS;
73
+ if (spec && explicitLevel) {
74
+ throw new TypeError(`${model} (${spec.name}) does not support thinkingLevel; use thinkingBudget.`);
75
+ }
76
+ if (spec && level) {
77
+ if (!Object.hasOwn(spec.efforts, level)) {
78
+ throw new TypeError(`${model} supports thinking levels ${Object.keys(spec.efforts).join(', ')}; received ${level}.`);
79
+ }
80
+ config.thinkingBudget = spec.efforts[level];
81
+ } else if (level) {
82
+ const supported = catalogThinkingLevels(model, provider) ?? documentedThinkingLevels(model) ?? LEVELS;
36
83
  if (!supported.includes(level)) {
37
84
  throw new TypeError(`${model} supports thinking levels ${supported.join(', ')}; received ${level}.`);
38
85
  }
@@ -40,9 +87,7 @@ export function geminiThinkingConfig(model, opts = {}, { includeThoughts, provid
40
87
  }
41
88
  if (hasBudget) {
42
89
  const budget = Number(rawBudget);
43
- if (!Number.isInteger(budget) || budget < -1) {
44
- throw new TypeError('thinkingBudget must be -1 (dynamic), 0, or a positive integer.');
45
- }
90
+ checkBudget(model, spec, budget);
46
91
  config.thinkingBudget = budget;
47
92
  }
48
93
  return Object.keys(config).length ? config : undefined;
@@ -17,7 +17,12 @@ import {
17
17
  } from '../stall-policy.mjs';
18
18
  import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
19
19
  import { GEMINI_FIRST_BYTE_TIMEOUT_MS, consumeGeminiRestStreamResponse } from './gemini-stream.mjs';
20
- import { applyGeminiErrorContract } from './gemini-error-contract.mjs';
20
+ import {
21
+ applyGeminiErrorContract,
22
+ geminiContinuationUnsupportedError,
23
+ geminiFinishErrorFields,
24
+ geminiFinishReasonKind,
25
+ } from './gemini-error-contract.mjs';
21
26
  import {
22
27
  GEMINI_MIDSTREAM_MAX_ATTEMPTS,
23
28
  geminiEndsWithFunctionResponse,
@@ -50,6 +55,7 @@ import {
50
55
  import {
51
56
  awaitSharedCreate,
52
57
  dropRejectedGeminiCache,
58
+ geminiBareModelId,
53
59
  geminiCacheCreateBody,
54
60
  geminiCacheEntry,
55
61
  geminiCachePrefixIdentity,
@@ -275,6 +281,10 @@ export class GeminiProvider {
275
281
  if (decision.canReuseState) {
276
282
  return state.cacheName;
277
283
  }
284
+ // A request forked from a shared prefix (/btw: opts.sharedCachePrefixCount)
285
+ // only reads the session's live cache. Creating or refreshing one would
286
+ // store the fork's own suffix (the appended reply and question).
287
+ if (opts.sharedCachePrefixCount) return decision.canAttachState ? state.cacheName : null;
278
288
  if (!apiKey || geminiExplicitCacheRefused(model)) return null;
279
289
  const { canAttachState } = decision;
280
290
  if (geminiPrefixBelowMinimum({ model, systemInstruction, geminiTools, contents, opts, currentIter })) {
@@ -584,10 +594,15 @@ export class GeminiProvider {
584
594
  cachedContent,
585
595
  });
586
596
  const parsed = parseGeminiCandidate(response, textLeakGuard);
587
- emitGeminiToolCalls(parsed.nativeToolCalls, callbacks.onToolCall);
588
597
  const usage = resolveGeminiUsage(response, opts, cachedContent, useModel);
598
+ // Terminal status first: a failed candidate's calls are never dispatched.
589
599
  const incomplete = geminiIncompleteError(response, parsed, useModel, usage);
590
600
  if (incomplete) {
601
+ Object.assign(incomplete, geminiFinishErrorFields(response));
602
+ if (geminiFinishReasonKind(incomplete.finishReason) === 'continuation') {
603
+ // Direct Gemini only: surface the typed result with its token.
604
+ throw geminiContinuationUnsupportedError(incomplete, response);
605
+ }
591
606
  // A malformed / unexpected tool call that survived the stream ladder
592
607
  // (4 attempts) is spent; the loop must not multiply that budget.
593
608
  if (
@@ -599,6 +614,8 @@ export class GeminiProvider {
599
614
  }
600
615
  throw incomplete;
601
616
  }
617
+ textLeakGuard?.releaseDeferredToolCalls?.();
618
+ emitGeminiToolCalls(parsed.nativeToolCalls, callbacks.onToolCall);
602
619
  return geminiSendResult(parsed, useModel, opts, usage);
603
620
  }
604
621
 
@@ -626,7 +643,7 @@ export class GeminiProvider {
626
643
  }
627
644
 
628
645
  async _restGenerateContent(useModel, apiKey, body, fallbackSignal) {
629
- const nonStreamUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(useModel)}:generateContent?key=${encodeURIComponent(apiKey)}`;
646
+ const nonStreamUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(geminiBareModelId(useModel))}:generateContent?key=${encodeURIComponent(apiKey)}`;
630
647
  const res = await this._fetch(nonStreamUrl, {
631
648
  method: 'POST',
632
649
  headers: { 'Content-Type': 'application/json' },
@@ -650,10 +667,10 @@ export class GeminiProvider {
650
667
  // { retryUncached: true } when the cache itself was rejected and the send
651
668
  // must be replayed without it.
652
669
  async _streamCachedViaRest(stream, internal) {
653
- const { opts, signal, useModel, contents, generationConfig, cachedContent, callbacks } = stream;
670
+ const { opts, signal, useModel, contents, generationConfig, safetySettings, cachedContent, callbacks } = stream;
654
671
  const apiKey = this._getApiKey();
655
- const genUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(useModel)}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`;
656
- const body = geminiCachedRestBody({ opts, contents, cachedContent, generationConfig });
672
+ const genUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(geminiBareModelId(useModel))}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`;
673
+ const body = geminiCachedRestBody({ opts, contents, cachedContent, generationConfig, safetySettings });
657
674
  // cachedContent owns tools + toolConfig. The API rejects a
658
675
  // generateContent request that repeats either field.
659
676
  // Option A (mirror anthropic-oauth): no absolute wall-clock cap on a
@@ -679,7 +696,6 @@ export class GeminiProvider {
679
696
  connected();
680
697
  const textLeakGuard = geminiTextLeakGuardFor(stream);
681
698
  const response = await consumeGeminiRestStreamResponse(res, {
682
- acceptEmptyNoFinish: afterToolResult,
683
699
  signal: attemptSignal,
684
700
  onStreamDelta: callbacks.onStreamDelta,
685
701
  onTextDelta: callbacks.onTextDelta,
@@ -715,13 +731,15 @@ export class GeminiProvider {
715
731
  }
716
732
 
717
733
  async _streamViaSdk(stream) {
718
- const { opts, signal, useModel, systemInstruction, geminiTools, toolConfig, generationConfig, contents } = stream;
734
+ const { opts, signal, useModel, systemInstruction, geminiTools, toolConfig, generationConfig, safetySettings, contents } =
735
+ stream;
719
736
  const genModel = this._currentGenAI().getGenerativeModel({
720
737
  model: useModel,
721
738
  systemInstruction,
722
739
  tools: geminiTools,
723
740
  ...(toolConfig ? { toolConfig } : {}),
724
741
  ...(generationConfig ? { generationConfig } : {}),
742
+ ...(safetySettings ? { safetySettings } : {}),
725
743
  });
726
744
  // Option A (mirror anthropic-oauth): pure pass-through of the external
727
745
  // signal, no absolute streaming total cap. See the REST path.
@@ -3,7 +3,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
3
3
  // Grok CLI client version for the cli-chat-proxy version gate (HTTP 426).
4
4
  // Effective = env override, else max(floor, learned-from-426, live npm latest
5
5
  // of the official @xai-official/grok CLI).
6
- export const GROK_CLI_VERSION_FLOOR = '1.0.52';
6
+ export const GROK_CLI_VERSION_FLOOR = '1.0.60';
7
7
  export const GROK_CLI_NPM_PACKAGE = '@xai-official/grok';
8
8
 
9
9
  const live = createNpmVersionSource(GROK_CLI_NPM_PACKAGE, { persistKey: 'grok-cli' });
@@ -412,6 +412,7 @@ export class GrokOAuthProvider {
412
412
  apiKey: token,
413
413
  baseURL: PROXY_BASE_URL,
414
414
  responsesTransport: resolveGrokOAuthResponsesTransport(),
415
+ transportPinned: true,
415
416
  extraHeaders: requestHeaders,
416
417
  });
417
418
  this._innerKey = key;
@@ -1,3 +1,5 @@
1
+ import { mergeFlatSchemaProperty } from './flat-schema-merge.mjs';
2
+
1
3
  // Preserve action-specific input rules when a provider needs a flat schema.
2
4
  // Field definitions remain shared; only the per-action field names and differing
3
5
  // enums/bounds are repeated, rather than copying every full schema branch.
@@ -34,3 +36,61 @@ export function actionInputContract(schema) {
34
36
  });
35
37
  return `Allowed input by action (* required): ${rows.join('; ')}.`;
36
38
  }
39
+
40
+ // A per-action input union: the root's `action` enum and an `input` whose
41
+ // anyOf alternatives are object schemas, each titled with the one action it
42
+ // belongs to. Returns those alternatives as action/input branches, or null.
43
+ function actionInputBranches(schema) {
44
+ const actions = schema?.properties?.action?.enum;
45
+ const alternatives = schema?.properties?.input?.anyOf;
46
+ if (!Array.isArray(actions) || !Array.isArray(alternatives) || !alternatives.length) return null;
47
+ const branches = alternatives.map((alternative) =>
48
+ alternative?.properties && actions.includes(alternative.title)
49
+ ? { properties: { action: { enum: [alternative.title] }, input: alternative } }
50
+ : null
51
+ );
52
+ return branches.every(Boolean) ? branches : null;
53
+ }
54
+
55
+ /** The flat projection of a per-action input union: `input` becomes the
56
+ * merged field set of every alternative, its description listing the fields
57
+ * per action. Any other schema is returned as is; the input is never mutated. */
58
+ export function flattenActionInputUnion(schema) {
59
+ const branches = actionInputBranches(schema);
60
+ if (!branches) return schema;
61
+ const { anyOf: _anyOf, description, ...base } = schema.properties.input;
62
+ const merged = branches
63
+ .map(({ properties }) => {
64
+ const { title: _title, description: _description, ...shape } = properties.input;
65
+ return shape;
66
+ })
67
+ .reduce((current, shape) => mergeFlatSchemaProperty(current, shape));
68
+ const contract = actionInputContract({ oneOf: branches });
69
+ return {
70
+ ...schema,
71
+ properties: {
72
+ ...schema.properties,
73
+ input: { ...base, ...merged, description: [description, contract].filter(Boolean).join(' ') },
74
+ },
75
+ };
76
+ }
77
+
78
+ // Nested per-action input unions keyed by their flat projection's JSON. A tool
79
+ // advertises the flat projection on every path; only provider paths verified
80
+ // to accept nested alternatives opt in through actionInputUnionFor. Keyed by
81
+ // content, so a request snapshot's clone still resolves.
82
+ const nestedByFlat = new Map();
83
+
84
+ /** Register `nested` (a per-action input union) and return the flat
85
+ * projection the tool advertises. */
86
+ export function advertiseActionInputUnion(nested) {
87
+ const flat = flattenActionInputUnion(nested);
88
+ nestedByFlat.set(JSON.stringify(flat), nested);
89
+ return flat;
90
+ }
91
+
92
+ /** The registered nested union for an advertised flat schema, else `schema`. */
93
+ export function actionInputUnionFor(schema) {
94
+ if (!schema?.properties?.action || !schema.properties.input) return schema;
95
+ return nestedByFlat.get(JSON.stringify(schema)) ?? schema;
96
+ }
@@ -19,6 +19,7 @@ export const NATIVE_SERVER_TOOL_RESULT_BLOCK_TYPES = new Set([
19
19
  'bash_code_execution_tool_result',
20
20
  'text_editor_code_execution_tool_result',
21
21
  'mcp_tool_result',
22
+ 'tool_search_tool_result',
22
23
  ]);
23
24
 
24
25
  export function isNativeServerToolBlockType(type) {