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
@@ -0,0 +1,172 @@
1
+ // Shared by openai-compat-responses-native.test.mjs and the one-off generator
2
+ // that produced openai-compat-responses-head-parity.json by running these same
3
+ // captures against the pre-change (HEAD) converters.
4
+ import { sendCompatResponses } from './openai-compat-responses.mjs';
5
+ import { OpenAICompatProvider } from './openai-compat.mjs';
6
+ import { buildRequestBody } from './openai-responses-payload.mjs';
7
+ import { createProviderReplay } from './lib/provider-replay.mjs';
8
+
9
+ export const SERVER_CALL = {
10
+ type: 'tool_search_call',
11
+ id: 'ts_srv',
12
+ call_id: null,
13
+ execution: 'server',
14
+ arguments: { query: 'q' },
15
+ };
16
+ export const SERVER_OUTPUT = { type: 'tool_search_output', id: 'tso_srv', call_id: null, execution: 'server', tools: [] };
17
+ export const REPLY = { type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'ok' }] };
18
+
19
+ export const ROUTES = [
20
+ ['opencode-go', 'gpt-5.5'],
21
+ ['muse-code', 'muse-spark'],
22
+ ['command-code', 'gpt-5.5'],
23
+ ['custom-cmd', 'openai/gpt-5.6-sol'],
24
+ ['openrouter', 'openai/gpt-5.5'],
25
+ ['xai', 'grok-4'],
26
+ ['opencode-go', 'grok-4'],
27
+ ];
28
+ export const FIRST_PARTY = [
29
+ ['openai', 'gpt-5.5'],
30
+ ['openai-oauth', 'gpt-5.5'],
31
+ ];
32
+
33
+ export const replayOwner = (name) => `compat-responses:${name}`;
34
+
35
+ const search = (name) => ({
36
+ provider: name,
37
+ openaiTools: [{ type: 'function', name: 'x', description: 'd', parameters: { type: 'object', properties: {} } }],
38
+ });
39
+
40
+ export function nativeHistory() {
41
+ return [
42
+ { role: 'user', content: 'go' },
43
+ {
44
+ role: 'assistant',
45
+ content: '',
46
+ toolCalls: [
47
+ { id: 'ts1', name: 'load_tool', arguments: { names: ['x'] }, nativeType: 'tool_search_call' },
48
+ { id: 'cu1', name: 'apply_patch', arguments: { patch: 'P' }, nativeType: 'custom_tool_call' },
49
+ { id: 'fn1', name: 'Read', arguments: { path: 'a' } },
50
+ ],
51
+ },
52
+ { role: 'tool', toolCallId: 'ts1', content: 'loaded' },
53
+ { role: 'tool', toolCallId: 'cu1', content: 'patched' },
54
+ { role: 'tool', toolCallId: 'fn1', content: 'file' },
55
+ { role: 'user', content: 'next' },
56
+ ];
57
+ }
58
+
59
+ // Left by a previous openai-oauth route: native search/custom calls, native
60
+ // search results carrying loaded tools, phase-tagged assistant turns, a Skill
61
+ // result with loadable tools, and a foreign openai-responses replay.
62
+ export function oauthHistory() {
63
+ return [
64
+ { role: 'system', content: 'sys' },
65
+ { role: 'user', content: 'go' },
66
+ { role: 'assistant', content: 'working', phase: 'commentary', toolCalls: [] },
67
+ {
68
+ role: 'assistant',
69
+ content: 'looking',
70
+ phase: 'commentary',
71
+ reasoningItems: [{ id: 'rs', encrypted_content: 'ENC', summary: [] }],
72
+ toolCalls: [
73
+ { id: 'ts1', name: 'load_tool', arguments: { names: ['x'] }, nativeType: 'tool_search_call' },
74
+ { id: 'cu1', name: 'apply_patch', arguments: { patch: 'P' }, nativeType: 'custom_tool_call' },
75
+ { id: 'sk1', name: 'Skill', arguments: { name: 's' } },
76
+ ],
77
+ },
78
+ { role: 'tool', toolCallId: 'ts1', content: 'loaded', nativeToolSearch: search('openai-oauth') },
79
+ { role: 'tool', toolCallId: 'cu1', content: 'patched' },
80
+ { role: 'tool', toolCallId: 'sk1', content: 'skill', nativeToolSearch: search('openai-oauth') },
81
+ {
82
+ role: 'assistant',
83
+ content: '',
84
+ toolCalls: [{ id: 'f2', name: 'Read', arguments: { path: 'a' } }],
85
+ providerReplay: createProviderReplay('openai-responses', [
86
+ { type: 'tool_search_call', call_id: 'ts9', execution: 'client', arguments: {} },
87
+ ]),
88
+ },
89
+ { role: 'tool', toolCallId: 'f2', content: 'file' },
90
+ { role: 'user', content: 'next' },
91
+ ];
92
+ }
93
+
94
+ // Same-owner replay envelope holding a server-executed search pair.
95
+ export function serverSearchReplayHistory(owner) {
96
+ return [
97
+ { role: 'user', content: 'find tools' },
98
+ {
99
+ role: 'assistant',
100
+ content: 'done',
101
+ providerReplay: createProviderReplay(owner, [
102
+ { type: 'reasoning', id: 'rs_1', encrypted_content: 'ENC', summary: [] },
103
+ SERVER_CALL,
104
+ SERVER_OUTPUT,
105
+ { type: 'function_call', call_id: 'c1', name: 'Read', arguments: '{}' },
106
+ ]),
107
+ toolCalls: [{ id: 'c1', name: 'Read', arguments: {} }],
108
+ },
109
+ { role: 'tool', toolCallId: 'c1', content: 'ok' },
110
+ { role: 'user', content: 'next' },
111
+ ];
112
+ }
113
+
114
+ // Pre-change flag-off cases: [label, history(name), providerState?]
115
+ export const COMPAT_CASES = [
116
+ ['native', () => nativeHistory()],
117
+ ['oauth', () => oauthHistory()],
118
+ ['own-search-output', (name) => {
119
+ const h = nativeHistory();
120
+ h[2] = { ...h[2], nativeToolSearch: search(name) };
121
+ return h;
122
+ }],
123
+ ['server-replay', (name, owner = replayOwner(name)) => serverSearchReplayHistory(owner)],
124
+ ];
125
+
126
+ export function compatProvider(name, config = {}) {
127
+ const requests = [];
128
+ const provider = Object.assign(Object.create(OpenAICompatProvider.prototype), {
129
+ name,
130
+ config: { preconnect: false, ...config },
131
+ nativePdf: true,
132
+ client: {
133
+ responses: {
134
+ create: async (params) => {
135
+ requests.push(structuredClone(params));
136
+ return (async function* () {
137
+ yield {
138
+ type: 'response.completed',
139
+ response: { id: 'resp-1', model: params.model, status: 'completed', output: [REPLY] },
140
+ };
141
+ })();
142
+ },
143
+ },
144
+ },
145
+ });
146
+ return { provider, requests };
147
+ }
148
+
149
+ export async function captureCompat(name, model, history, opts = {}, config = {}) {
150
+ const { provider, requests } = compatProvider(name, config);
151
+ await sendCompatResponses(provider, history, model, [], { sessionId: 'sess-1', ...opts });
152
+ return requests[0];
153
+ }
154
+
155
+ export function captureFirstParty(name, model, history) {
156
+ return JSON.parse(JSON.stringify(buildRequestBody(history, model, [], { promptCacheProvider: name, sessionId: 'sess-1' })));
157
+ }
158
+
159
+ export async function captureAll() {
160
+ const out = {};
161
+ for (const [name, model] of ROUTES) {
162
+ for (const [label, build] of COMPAT_CASES) {
163
+ out[`compat/${name}/${model}/${label}`] = await captureCompat(name, model, build(name));
164
+ }
165
+ }
166
+ for (const [name, model] of FIRST_PARTY) {
167
+ for (const [label, build] of COMPAT_CASES) {
168
+ out[`first-party/${name}/${label}`] = captureFirstParty(name, model, build(name, 'openai-responses'));
169
+ }
170
+ }
171
+ return out;
172
+ }
@@ -22,6 +22,7 @@ import {
22
22
  toXaiResponsesInput,
23
23
  xaiSystemInstructions,
24
24
  } from './openai-compat-wire.mjs';
25
+ import { nativeDeferredFamilyForRoute } from './wire-route.mjs';
25
26
  import { preparePdfTextForProvider } from './media-normalization.mjs';
26
27
  import { normalizeOpencodeGoReasoningEffort } from './openai-compat-xai.mjs';
27
28
  import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
@@ -87,15 +88,38 @@ function customEffortProjection(provider, useModel, messages, opts) {
87
88
  return { ...projection, initialEffort, effort: current, updates };
88
89
  }
89
90
 
91
+ // Whether the endpoint takes `prompt_cache_key`. An explicit
92
+ // `opts.responsesPromptCacheKey` / `config.responsesPromptCacheKey` boolean
93
+ // decides; otherwise only custom routes (which always had it) send it.
94
+ function supportsPromptCacheKey(provider, opts) {
95
+ const declared = opts.responsesPromptCacheKey ?? provider.config?.responsesPromptCacheKey;
96
+ return typeof declared === 'boolean' ? declared : isCustomProviderName(provider.name);
97
+ }
98
+
99
+ // Native Responses items (tool_search_call/output, custom_tool_call/output) in
100
+ // replayed history are strictly opt-in: only a route that declares
101
+ // `responsesNativeItems: true` (opts or config) gets the first-party lowering.
102
+ // Every other route keeps the function-only lowering byte for byte.
103
+ function supportsNativeResponsesItems(provider, opts) {
104
+ return (opts.responsesNativeItems ?? provider.config?.responsesNativeItems) === true || hasNativeDeferredTools(provider, opts);
105
+ }
106
+
107
+ // A session whose pinned route verified native deferred tools on the Responses
108
+ // wire (flag off in every PROFILES entry today): tool_search is declared
109
+ // natively and loaded tools replay as tool_search_output.
110
+ function hasNativeDeferredTools(provider, opts) {
111
+ return nativeDeferredFamilyForRoute(provider.name, opts.wireRoute ?? opts.session?.wireRoute) === 'openai';
112
+ }
113
+
90
114
  /**
91
- * A custom route's session identity: its prompt_cache_key and session
115
+ * A route's session identity: its prompt_cache_key and (custom routes) session
92
116
  * headers, '' without a session. The session wins over the provider-scoped
93
117
  * cache key, so parallel sessions never evict each other; a one-shot role
94
118
  * ('shared' scope, a fresh session per call) keys on the provider key instead.
95
119
  * Never the effort, so an effort change keeps the cache routing.
96
120
  */
97
121
  function customSessionCacheKey(provider, opts) {
98
- if (!isCustomProviderName(provider.name)) return '';
122
+ if (!supportsPromptCacheKey(provider, opts)) return '';
99
123
  const explicit = opts.promptCacheKey || opts.providerCacheKey || opts.session?.promptCacheKey;
100
124
  return normalizeCacheKey(
101
125
  opts.promptCacheScope === 'shared' ? explicit || opts.sessionId : opts.sessionId || explicit
@@ -126,7 +150,11 @@ function buildCompatResponsesParams({
126
150
  const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
127
151
  if (maxOutputTokens) params.max_output_tokens = maxOutputTokens;
128
152
  if (tools?.length) {
129
- params.tools = toResponsesTools(tools, { provider: provider.name });
153
+ params.tools = toResponsesTools(tools, {
154
+ provider: provider.name,
155
+ onToolExcluded: opts.onToolExcluded,
156
+ ...(hasNativeDeferredTools(provider, opts) ? { nativeDeferredTools: true } : {}),
157
+ });
130
158
  params.parallel_tool_calls = true;
131
159
  }
132
160
  applyCompatToolChoice(params, opts);
@@ -207,6 +235,22 @@ async function streamCompatResponses({ provider, params, label, signal, opts, he
207
235
  }
208
236
  }
209
237
 
238
+ // OpenRouter's Responses endpoint is stateless: it does not store responses or
239
+ // resolve `previous_response_id`. Imported server-side continuation state (a
240
+ // previous id, or a stored response) is rejected up front rather than sent.
241
+ function assertOpenRouterStateless(provider, opts) {
242
+ if (provider.name !== 'openrouter') return;
243
+ const imported = opts.providerState?.[COMPAT_RESPONSES_STATE_KEY];
244
+ const previous = typeof imported?.previousResponseId === 'string' && imported.previousResponseId !== '';
245
+ if (!previous && imported?.store !== true) return;
246
+ throw Object.assign(
247
+ new Error(
248
+ 'openrouter Responses is stateless: imported previous_response_id / store:true continuation state is not supported'
249
+ ),
250
+ { code: 'OPENROUTER_RESPONSES_STATELESS_ONLY', provider: provider.name }
251
+ );
252
+ }
253
+
210
254
  /**
211
255
  * Send one turn over `POST {baseURL}/responses` (streaming) using the
212
256
  * provider's existing OpenAI SDK client. Returns the same result shape as
@@ -229,6 +273,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
229
273
  }
230
274
  const label = `${provider.name}:responses`;
231
275
  messages = await preparePdfTextForProvider(messages, provider);
276
+ assertOpenRouterStateless(provider, opts);
232
277
  const effortProjection = customEffortProjection(provider, useModel, messages, opts);
233
278
  const sessionCacheKey = customSessionCacheKey(provider, opts);
234
279
  const { input, previousResponseId, continuationResetReason } = toXaiResponsesInput(messages, opts.providerState, {
@@ -237,6 +282,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
237
282
  stateKey: COMPAT_RESPONSES_STATE_KEY,
238
283
  replayProvider,
239
284
  providerName: provider.name,
285
+ nativeLowering: supportsNativeResponsesItems(provider, opts),
240
286
  nativePdf: provider.nativePdf,
241
287
  // Opt-in: system prompts travel as top-level `instructions`, not input items.
242
288
  includeSystem: provider.config?.responsesSystemAsInstructions !== true,
@@ -254,7 +300,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
254
300
  sessionCacheKey,
255
301
  });
256
302
  // The session identity also travels as headers; caller headers win.
257
- const headers = sessionCacheKey
303
+ const headers = sessionCacheKey && isCustomProviderName(provider.name)
258
304
  ? { 'session-id': sessionCacheKey, 'x-client-request-id': sessionCacheKey, ...opts.requestHeaders }
259
305
  : opts.requestHeaders;
260
306
 
@@ -287,7 +333,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
287
333
  const messageIndex = Array.isArray(messages) ? messages.length : 0;
288
334
  const encryptedReasoningHistory = [
289
335
  ...(Array.isArray(priorState?.encryptedReasoningHistory) ? priorState.encryptedReasoningHistory : []),
290
- ...(reasoningItems.length ? [{ messageIndex, items: reasoningItems }] : []),
336
+ ...(reasoningItems.length ? [{ messageIndex, items: reasoningItems, owner: replayProvider }] : []),
291
337
  ];
292
338
  const searchSources = collectCompatResponseSearchSources(response);
293
339
  const usageSummary = usage ? responsesUsage(usage) : undefined;
@@ -296,6 +342,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
296
342
  model: response?.model || useModel,
297
343
  toolCalls: streamed.toolCalls,
298
344
  stopReason: streamed.stopReason || null,
345
+ ...(streamed.refusal ? { refusal: streamed.refusal } : {}),
299
346
  ...(streamed.stopReason === 'length' && (streamed.content || '').length > 0 ? { truncated: true } : {}),
300
347
  citations: searchSources.citations.length ? searchSources.citations : undefined,
301
348
  webSearchCalls: searchSources.webSearchCalls.length ? searchSources.webSearchCalls : undefined,
@@ -306,6 +353,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
306
353
  previousResponseId: null,
307
354
  responseId: response?.id || null,
308
355
  store: false,
356
+ owner: replayProvider,
309
357
  encryptedReasoningItems: reasoningItems,
310
358
  encryptedReasoningHistory,
311
359
  seenMessageCount: messageIndex,
@@ -31,6 +31,7 @@ import {
31
31
  finalizeResponsesStream,
32
32
  unresolvedSalvageError,
33
33
  } from './openai-compat-responses-state.mjs';
34
+ import { createRefusals, refusalResultFields } from './openai-ws-response-state/refusals.mjs';
34
35
  import { responsesUsage } from './openai-compat-response-normalization.mjs';
35
36
  import { noteAbandonedUsage } from '../../../shared/llm/usage-context.mjs';
36
37
 
@@ -151,7 +152,12 @@ export async function consumeCompatResponsesStream(
151
152
  throw stampOutcome(unresolved);
152
153
  }
153
154
  try {
154
- return finalizeResponsesStream(state, { leakedCalls, parseResponsesToolCalls, responseOutputText, label });
155
+ const result = finalizeResponsesStream(state, { leakedCalls, parseResponsesToolCalls, responseOutputText, label });
156
+ // The terminal output bundle's refusal parts join the streamed ones (keyed
157
+ // by item id + content index, so copies of one part fold into one text).
158
+ state.refusals ||= createRefusals();
159
+ for (const item of result.response?.output || []) state.refusals.absorbMessage(item);
160
+ return { ...result, ...refusalResultFields(state.refusals, result.content) };
155
161
  } catch (err) {
156
162
  attachPartialState(err, state, leakedCalls);
157
163
  throw stampOutcome(err);
@@ -37,6 +37,8 @@ export function extractCompatCachedTokens(usage) {
37
37
  usage?.input_tokens_details?.cached_tokens,
38
38
  usage?.prompt_cache_hit_tokens,
39
39
  usage?.cached_prompt_text_tokens,
40
+ // Together reports it top-level; first-positive wins, so it never stacks on a nested count.
41
+ usage?.cached_tokens,
40
42
  ];
41
43
  for (const v of candidates) {
42
44
  const n = Number(v);
@@ -17,8 +17,11 @@ import {
17
17
  } from './media-normalization.mjs';
18
18
  import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from './custom-tool-wire.mjs';
19
19
  import { providerReplayItems } from './lib/provider-replay.mjs';
20
+ import { acceptedWireTools } from './lib/claude-bridge-schema.mjs';
20
21
  import { ensureResponsesCallOutputs } from './lib/wire-pairing.mjs';
21
22
  import { responsesEffortUpdates } from './effort-configuration.mjs';
23
+ import { convertMessagesToResponsesInput } from './openai-responses-input.mjs';
24
+ import { COMPAT_REASONING_METADATA_KEY, contentWithThinkingChunk } from './openai-compat-reasoning-field.mjs';
22
25
 
23
26
  function positiveTokenInt(value) {
24
27
  const n = Number(value);
@@ -39,19 +42,23 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
39
42
  // strict providers (xai) reject unknown roles/types and would 400 the
40
43
  // request. Documented in v0.1.160 (GPT reasoning replay).
41
44
  //
42
- // DeepSeek splits by model: thinking-mode models with tools REQUIRE the
43
- // prior turn's `reasoning_content` echoed back (400 without it), while
44
- // `deepseek-reasoner` REJECTS it with a 400. The caller decides per model
45
- // through options.replaysReasoningContent — see
46
- // deepseekReplaysReasoningContent below. xAI reasoning models preserve
47
- // their official multi-turn shape and cache prefix stability when prior
48
- // assistant reasoning_content is replayed; reasoning_effort itself remains
49
- // caller/user-selected.
45
+ // DeepSeek thinking-mode models with tools REQUIRE the prior turn's
46
+ // `reasoning_content` echoed back (400 without it); without tools it is
47
+ // ignored, so the caller (options.replaysReasoningContent) always replays it.
48
+ // xAI reasoning models preserve their official multi-turn shape and cache
49
+ // prefix stability when prior assistant reasoning_content is replayed;
50
+ // reasoning_effort itself remains caller/user-selected.
50
51
  //
51
52
  // Custom providers pass options.customReplay (custom-reasoning.mjs replay
52
53
  // eligibility). When it is a boolean it alone decides; a replaying custom
53
54
  // endpoint also needs a non-empty reasoning_content on every assistant
54
55
  // tool-call turn, so missing/empty reasoning there is padded with " ".
56
+ //
57
+ // options.reasoningShape (openai-compat-reasoning-field.mjs) names the
58
+ // endpoint families with their own reasoning fields; they decide the resend
59
+ // key and win over the flags above. options.developerRole keeps the
60
+ // `developer` role for endpoints that document it; every other chat endpoint
61
+ // only knows `system`, so developer instructions go out as system messages.
55
62
  const customReplay = typeof options.customReplay === 'boolean' ? options.customReplay : null;
56
63
  const replaysReasoningContent = customReplay ?? (options.replaysReasoningContent === true || providerName === 'xai');
57
64
  const out = [];
@@ -62,8 +69,25 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
62
69
  const details = metadata?.reasoning_details ?? metadata?.reasoningDetails;
63
70
  return Array.isArray(details) && details.length ? details : null;
64
71
  };
72
+ const shape = options.reasoningShape || null;
73
+ // Receive and resend fields differ per endpoint family: the key a reply's
74
+ // reasoning arrived on is recorded in providerMetadata at receive time.
75
+ const receivedField = (message) => message?.providerMetadata?.[COMPAT_REASONING_METADATA_KEY]?.reasoningField;
76
+ const attachShapeReasoning = (msg, message, stored) => {
77
+ if (!stored) return;
78
+ if (shape.resend === 'same_key') {
79
+ msg[receivedField(message) === 'reasoning' ? 'reasoning' : 'reasoning_content'] = stored;
80
+ } else if (shape.resend === 'reasoning') {
81
+ // OpenRouter: reasoning_details replace the text when present.
82
+ if (!openRouterReasoningDetails(message)) msg.reasoning = stored;
83
+ } else if (shape.resend === 'content_chunks' && receivedField(message) === 'content_chunks') {
84
+ msg.content = contentWithThinkingChunk(msg.content, stored);
85
+ }
86
+ };
65
87
  const attachAssistantReasoning = (msg, message) => {
66
- if (customReplay) {
88
+ if (shape) {
89
+ attachShapeReasoning(msg, message, typeof message.reasoningContent === 'string' ? message.reasoningContent : '');
90
+ } else if (customReplay) {
67
91
  const stored = typeof message.reasoningContent === 'string' ? message.reasoningContent : '';
68
92
  if (stored) msg.reasoning_content = stored;
69
93
  else if (Array.isArray(msg.tool_calls) && msg.tool_calls.length) msg.reasoning_content = ' ';
@@ -104,8 +128,12 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
104
128
  continue;
105
129
  }
106
130
  const msg = {
107
- role: m.role,
108
- content: normalizeContentForOpenAIChat(m.content, { role: m.role, nativePdf: options.nativePdf }),
131
+ role: m.role === 'developer' && options.developerRole !== true ? 'system' : m.role,
132
+ content: normalizeContentForOpenAIChat(m.content, {
133
+ role: m.role,
134
+ nativePdf: options.nativePdf,
135
+ cacheControl: options.cacheControl === true,
136
+ }),
109
137
  };
110
138
  out.push(m.role === 'assistant' ? attachAssistantReasoning(msg, m) : msg);
111
139
  }
@@ -113,18 +141,6 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
113
141
  return out;
114
142
  }
115
143
 
116
- // deepseek-reasoner returns 400 when `reasoning_content` appears in the input
117
- // messages; every other DeepSeek thinking model needs it back once tools are in
118
- // play. Unknown DeepSeek ids default to replaying: a missing echo breaks the
119
- // tool loop, while a stray field on a non-thinking model is ignored.
120
- export function deepseekReplaysReasoningContent(model) {
121
- return !/reasoner/.test(
122
- String(model || '')
123
- .trim()
124
- .toLowerCase()
125
- );
126
- }
127
-
128
144
  export function toOpenAITools(tools) {
129
145
  return tools.map((t) => ({
130
146
  type: 'function',
@@ -146,9 +162,42 @@ function functionToolFromSessionTool(t, name = t?.name) {
146
162
  };
147
163
  }
148
164
 
149
- export function toResponsesTools(tools, options = {}) {
165
+ // xAI hosts tool search itself (docs.x.ai progressive tool disclosure): a
166
+ // `{type:'tool_search'}` server tool loads the definitions of function tools
167
+ // marked `defer_loading: true`, and the server returns the search as
168
+ // tool_search_call / tool_search_output items. The client loader (`load_tool`)
169
+ // is therefore replaced by that one server tool; with deferred tools but no
170
+ // loader the server tool is still added, or the deferred tools could never load.
171
+ function toServerToolSearchTools(tools) {
172
+ let hasSearch = false;
173
+ let hasDeferred = false;
174
+ const out = tools.map((t) => {
175
+ if (t?.name === 'load_tool' || t?.name === 'tool_search') {
176
+ if (hasSearch) return null;
177
+ hasSearch = true;
178
+ return { type: 'tool_search' };
179
+ }
180
+ if (t?.deferLoading === true || t?.defer_loading === true) {
181
+ hasDeferred = true;
182
+ return { ...functionToolFromSessionTool(t), defer_loading: true };
183
+ }
184
+ return functionToolFromSessionTool(t);
185
+ });
186
+ if (hasDeferred && !hasSearch) out.push({ type: 'tool_search' });
187
+ return out.filter(Boolean);
188
+ }
189
+
190
+ export function toResponsesTools(allTools, options = {}) {
150
191
  const provider = String(options?.provider || '').toLowerCase();
192
+ // A Responses endpoint rejects the whole request for one invalid
193
+ // `parameters`; a tool broken even after lowering is left out and reported.
194
+ const tools = acceptedWireTools(allTools, 'openai', options?.onToolExcluded, `[${provider || 'responses'}] tool`);
195
+ if (options?.serverToolSearch === true) return toServerToolSearchTools(tools);
196
+ // A route pinned with verified native deferred tools declares the native
197
+ // client tool_search tool and marks deferred definitions `defer_loading`.
198
+ const nativeDeferred = options?.nativeDeferredTools === true;
151
199
  const allowNativeToolSearch =
200
+ nativeDeferred ||
152
201
  options?.nativeToolSearch === true ||
153
202
  (options?.nativeToolSearch !== false && (provider === 'openai' || provider === 'openai-oauth'));
154
203
  return tools.map((t) => {
@@ -170,6 +219,9 @@ export function toResponsesTools(tools, options = {}) {
170
219
  // tools (e.g. apply_patch) as ordinary function tools instead. Grammar
171
220
  // tools may carry no usable inputSchema, so fall back to a permissive
172
221
  // object schema so grok still registers a valid function tool.
222
+ if (nativeDeferred && (t?.deferLoading === true || t?.defer_loading === true)) {
223
+ return { ...functionToolFromSessionTool(t), defer_loading: true };
224
+ }
173
225
  return functionToolFromSessionTool(t);
174
226
  });
175
227
  }
@@ -237,7 +289,7 @@ export function parseResponsesToolCalls(response, label) {
237
289
  } else if (item?.type === 'custom_tool_call') {
238
290
  const call = customToolCallFromResponseItem(item);
239
291
  if (call) out.push(call);
240
- } else if (item?.type === 'tool_search_call') {
292
+ } else if (item?.type === 'tool_search_call' && item.execution !== 'server') {
241
293
  const searchArgs =
242
294
  item.arguments && typeof item.arguments === 'object' && !Array.isArray(item.arguments)
243
295
  ? item.arguments
@@ -409,16 +461,41 @@ export function toXaiResponsesInput(messages, providerState, options = {}) {
409
461
  let history = [];
410
462
  if (Array.isArray(state?.encryptedReasoningHistory)) history = state.encryptedReasoningHistory;
411
463
  else if (Array.isArray(state?.encryptedReasoningItems)) {
412
- history = [{ messageIndex: seen, items: state.encryptedReasoningItems }];
464
+ history = [{ messageIndex: seen, items: state.encryptedReasoningItems, owner: state.owner }];
413
465
  }
414
466
  for (const entry of history) {
415
467
  const index = Number(entry?.messageIndex);
416
468
  if (!Number.isInteger(index) || index < 0 || !Array.isArray(entry?.items)) continue;
469
+ // Owner-tagged reasoning (compat routes) never replays under another
470
+ // owner, even when a caller passes provider state across providers.
471
+ if (entry.owner !== undefined && entry.owner !== replayProvider) continue;
417
472
  const bucket = reasoningByMessageIndex.get(index) || [];
418
473
  bucket.push(...entry.items.map((item) => ({ ...item })));
419
474
  reasoningByMessageIndex.set(index, bucket);
420
475
  }
421
476
  }
477
+ if (options.nativeLowering === true) {
478
+ // Native-item-capable Responses routes share the first-party lowering:
479
+ // native tool_search / custom calls keep their own output type, and only
480
+ // this route's own replay tag and reasoning state are replayed.
481
+ return {
482
+ input: convertMessagesToResponsesInput(messages, {
483
+ startIndex,
484
+ includeSystem,
485
+ nativePdf: options.nativePdf,
486
+ replayProvider,
487
+ // Compat-owned tool_search payloads are tagged with the route name.
488
+ nativeToolSearchProvider: options.providerName,
489
+ replayOwnedReasoning: true,
490
+ reasoningByMessageIndex,
491
+ effortProjection: options.effortProjection,
492
+ splitToolContent: (content) => splitToolContentForXaiResponses(content, { nativePdf: options.nativePdf }),
493
+ }),
494
+ previousResponseId,
495
+ startIndex,
496
+ continuationResetReason: resetReason,
497
+ };
498
+ }
422
499
  const pendingToolMedia = [];
423
500
  const flushToolMedia = () => {
424
501
  if (!pendingToolMedia.length) return;
@@ -5,6 +5,7 @@ import { consumeCompatResponsesStream } from './openai-compat-stream.mjs';
5
5
  import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createPassthroughSignal } from '../stall-policy.mjs';
6
6
  import {
7
7
  nativeResponsesTools,
8
+ resolveCompatMaxOutputTokens,
8
9
  toOpenAIMessages,
9
10
  toResponsesTools,
10
11
  toXaiResponsesInput,
@@ -26,17 +27,34 @@ import { applyCompatToolChoice, compatStreamRetryReporter } from './compat-reque
26
27
  import { envFlag as _envFlag } from '../../../shared/env.mjs';
27
28
  import { resolveResponsesTransportPolicy, RESPONSES_TRANSPORT_CAPABILITIES } from './openai-transport-policy.mjs';
28
29
 
30
+ // Server-side tool search is strictly opt-in, from the provider's own config
31
+ // (`xaiServerToolSearch`, shared by grok-oauth's inner xai provider) or the
32
+ // request opts. Unset, every xAI request body is unchanged: deferred tools go
33
+ // out as plain function tools and the client `load_tool` stays a function.
34
+ // Server-executed search items replay through the owner-tagged providerReplay
35
+ // envelope in either mode and are never dispatched locally.
36
+ function xaiServerToolSearchEnabled(provider, opts) {
37
+ return (opts.xaiServerToolSearch ?? provider.config?.xaiServerToolSearch) === true;
38
+ }
39
+
29
40
  // Tool list, parallel tool calls, tool choice and reasoning effort shared by
30
41
  // the HTTP/SSE and WebSocket Responses bodies.
31
42
  function applyXaiResponsesToolsAndEffort(params, { provider, tools, opts, useModel }) {
32
43
  const nativeTools = nativeResponsesTools(opts);
33
44
  if (tools?.length || nativeTools.length) {
34
- params.tools = [...nativeTools, ...toResponsesTools(tools || [], { provider: 'xai' })];
45
+ const toolOptions = xaiServerToolSearchEnabled(provider, opts)
46
+ ? { provider: 'xai', serverToolSearch: true, onToolExcluded: opts.onToolExcluded }
47
+ : { provider: 'xai', onToolExcluded: opts.onToolExcluded };
48
+ params.tools = [...nativeTools, ...toResponsesTools(tools || [], toolOptions)];
35
49
  }
36
50
  // Explicit parallel tool calls, matching the OpenAI Responses
37
51
  // reference shape. Probe-verified accepted by api.x.ai (HTTP 200,
38
- // 2026-08-16); absent, the service default decides per turn.
39
- if (params.tools?.length) params.parallel_tool_calls = true;
52
+ // 2026-08-16); absent, the service default decides per turn. An explicit
53
+ // caller `parallelToolCalls:false` is honored (docs.x.ai function-calling).
54
+ if (params.tools?.length) params.parallel_tool_calls = opts.parallelToolCalls !== false;
55
+ // Caller output cap (docs.x.ai text best-practices): max_output_tokens.
56
+ const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
57
+ if (maxOutputTokens) params.max_output_tokens = maxOutputTokens;
40
58
  applyCompatToolChoice(params, opts);
41
59
  const reasoningEffort = normalizeXaiReasoningEffort(
42
60
  opts.xaiReasoningEffort ??
@@ -201,7 +219,8 @@ export async function sendXaiResponsesWebSocket(provider, messages, useModel, to
201
219
  onTextDelta: typeof opts.onTextDelta === 'function' ? opts.onTextDelta : null,
202
220
  onStageChange: typeof opts.onStageChange === 'function' ? opts.onStageChange : null,
203
221
  externalSignal: signal,
204
- poolKey: opts.sessionId || opts.session?.id || null,
222
+ // A forked request runs in its own transport scope (transport-scope.mjs).
223
+ poolKey: opts.transportScope || opts.sessionId || opts.session?.id || null,
205
224
  cacheKey: cacheRouting.key,
206
225
  iteration,
207
226
  useModel,
@@ -235,13 +235,18 @@ export function useXaiResponsesApi(opts, config) {
235
235
  }
236
236
 
237
237
  export function useXaiResponsesWebSocket(opts, config) {
238
+ // A pinned route (grok-oauth's cli-chat-proxy) takes its transport from the
239
+ // config alone: the xAI WebSocket connector targets api.x.ai, so no request
240
+ // option or env override may carry the OAuth bearer there.
238
241
  const raw =
239
- opts?.xaiResponsesTransport ??
240
- opts?.xaiTransport ??
241
- config?.responsesTransport ??
242
- config?.transport ??
243
- process.env.MIXDOG_XAI_RESPONSES_TRANSPORT ??
244
- process.env.MIXDOG_XAI_TRANSPORT;
242
+ config?.transportPinned === true
243
+ ? config.responsesTransport
244
+ : (opts?.xaiResponsesTransport ??
245
+ opts?.xaiTransport ??
246
+ config?.responsesTransport ??
247
+ config?.transport ??
248
+ process.env.MIXDOG_XAI_RESPONSES_TRANSPORT ??
249
+ process.env.MIXDOG_XAI_TRANSPORT);
245
250
  // Reference xAI/Grok parity is HTTP/SSE. WebSocket remains available only
246
251
  // when a caller explicitly selects a WS transport.
247
252
  if (raw == null || raw === '') return false;
@@ -78,6 +78,9 @@ export class OpenAICompatProvider {
78
78
  this.config = config;
79
79
  this.baseURL = baseURL;
80
80
  this.apiKey = apiKey;
81
+ // Whether Chat content blocks keep their Anthropic-style `cache_control`
82
+ // (OpenRouter documents it); a gateway that does not ignores or rejects it.
83
+ this.chatCacheControl = (config.chatCacheControl ?? preset?.chatCacheControl) === true;
81
84
  // Merge caller-supplied headers (config.extraHeaders) over the preset's.
82
85
  // Used e.g. by grok-oauth to inject the Grok CLI client headers for the
83
86
  // grok-build proxy. Backward-compatible: providers that pass no
@@ -256,7 +259,9 @@ export class OpenAICompatProvider {
256
259
  return fetchCompatModelItems(this);
257
260
  }
258
261
  async listModels() {
259
- return listCompatModels(this);
262
+ // A failed /models request must surface; an empty list would be cached as
263
+ // a complete catalog by the shared catalog loader.
264
+ return listCompatModels(this, { throwOnError: true });
260
265
  }
261
266
  async isAvailable() {
262
267
  return isCompatProviderAvailable(this);