mixdog 0.7.17 → 0.8.0

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 (836) hide show
  1. package/README.md +37 -331
  2. package/package.json +67 -99
  3. package/scripts/boot-smoke.mjs +94 -0
  4. package/scripts/build-tui.mjs +52 -0
  5. package/scripts/compact-smoke.mjs +199 -0
  6. package/scripts/lead-workflow-smoke.mjs +598 -0
  7. package/scripts/live-worker-smoke.mjs +239 -0
  8. package/scripts/output-style-smoke.mjs +101 -0
  9. package/scripts/smoke-loop-report.mjs +221 -0
  10. package/scripts/smoke-loop.mjs +201 -0
  11. package/scripts/smoke.mjs +113 -0
  12. package/scripts/tool-failures.mjs +143 -0
  13. package/scripts/tool-smoke.mjs +456 -0
  14. package/src/agents/debugger/AGENT.md +3 -0
  15. package/src/agents/debugger/agent.json +6 -0
  16. package/src/agents/explore/AGENT.md +4 -0
  17. package/src/agents/explore/agent.json +6 -0
  18. package/src/agents/heavy-worker/AGENT.md +3 -0
  19. package/src/agents/heavy-worker/agent.json +6 -0
  20. package/src/agents/maintainer/AGENT.md +3 -0
  21. package/src/agents/maintainer/agent.json +6 -0
  22. package/src/agents/reviewer/AGENT.md +3 -0
  23. package/src/agents/reviewer/agent.json +6 -0
  24. package/src/agents/scheduler-task.md +3 -0
  25. package/src/agents/web-researcher/AGENT.md +3 -0
  26. package/src/agents/web-researcher/agent.json +6 -0
  27. package/src/agents/webhook-handler.md +3 -0
  28. package/src/agents/worker/AGENT.md +3 -0
  29. package/src/agents/worker/agent.json +6 -0
  30. package/src/app.mjs +90 -0
  31. package/src/cli.mjs +11 -0
  32. package/src/defaults/hidden-roles.json +72 -0
  33. package/src/defaults/mixdog-config.template.json +15 -0
  34. package/src/hooks/lib/permission-evaluator.cjs +488 -0
  35. package/src/hooks/lib/settings-loader.cjs +112 -0
  36. package/src/lib/keychain-cjs.cjs +332 -0
  37. package/src/lib/plugin-paths.cjs +28 -0
  38. package/src/lib/rules-builder.cjs +315 -0
  39. package/src/mixdog-session-runtime.mjs +3704 -0
  40. package/src/output-styles/default.md +38 -0
  41. package/src/output-styles/extreme-simple.md +17 -0
  42. package/src/output-styles/simple.md +17 -0
  43. package/src/repl.mjs +322 -0
  44. package/src/rules/bridge/00-common.md +5 -0
  45. package/src/rules/bridge/20-skip-protocol.md +11 -0
  46. package/src/rules/bridge/30-explorer.md +4 -0
  47. package/src/rules/bridge/40-cycle1-agent.md +28 -0
  48. package/src/rules/bridge/41-cycle2-agent.md +59 -0
  49. package/src/rules/lead/00-tool-lead.md +5 -0
  50. package/src/rules/lead/01-general.md +5 -0
  51. package/src/rules/lead/02-channels.md +3 -0
  52. package/src/rules/lead/04-workflow.md +12 -0
  53. package/src/rules/shared/00-language.md +3 -0
  54. package/src/rules/shared/01-tool.md +3 -0
  55. package/src/runtime/agent/orchestrator/bridge-trace.mjs +814 -0
  56. package/src/runtime/agent/orchestrator/cache-mtime.mjs +60 -0
  57. package/src/runtime/agent/orchestrator/config.mjs +446 -0
  58. package/src/runtime/agent/orchestrator/context/collect.mjs +796 -0
  59. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +417 -0
  60. package/src/runtime/agent/orchestrator/internal-roles.mjs +188 -0
  61. package/src/runtime/agent/orchestrator/internal-tools.mjs +88 -0
  62. package/src/runtime/agent/orchestrator/mcp/client.mjs +345 -0
  63. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2104 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +784 -0
  65. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +341 -0
  66. package/src/runtime/agent/orchestrator/providers/gemini.mjs +1679 -0
  67. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +959 -0
  68. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +213 -0
  69. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +38 -0
  70. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +471 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +615 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +808 -0
  73. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +1719 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2587 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1953 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +136 -0
  77. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +317 -0
  78. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +109 -0
  79. package/src/runtime/agent/orchestrator/providers/registry.mjs +247 -0
  80. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +332 -0
  81. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +11 -0
  82. package/src/runtime/agent/orchestrator/providers/trace-utils.mjs +50 -0
  83. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  84. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +318 -0
  85. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +367 -0
  86. package/src/runtime/agent/orchestrator/session/compact.mjs +882 -0
  87. package/src/runtime/agent/orchestrator/session/context-utils.mjs +233 -0
  88. package/src/runtime/agent/orchestrator/session/loop.mjs +2320 -0
  89. package/src/runtime/agent/orchestrator/session/manager.mjs +2960 -0
  90. package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
  91. package/src/runtime/agent/orchestrator/session/store.mjs +663 -0
  92. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  93. package/src/runtime/agent/orchestrator/smart-bridge/bridge-llm.mjs +339 -0
  94. package/src/runtime/agent/orchestrator/smart-bridge/cache-strategy.mjs +419 -0
  95. package/src/runtime/agent/orchestrator/stall-policy.mjs +227 -0
  96. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +235 -0
  97. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +723 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +389 -0
  99. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +637 -0
  100. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +165 -0
  101. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +104 -0
  102. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +194 -0
  103. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +596 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +110 -0
  105. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +153 -0
  106. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  107. package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +189 -0
  108. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +731 -0
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +168 -0
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  111. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +465 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +160 -0
  113. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +982 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1087 -0
  115. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +231 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +223 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin.mjs +478 -0
  118. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  119. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4102 -0
  120. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  121. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +154 -0
  122. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +26 -0
  123. package/src/runtime/agent/orchestrator/tools/patch-binary-fetcher.mjs +143 -0
  124. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +18 -0
  125. package/src/runtime/agent/orchestrator/tools/patch.mjs +2772 -0
  126. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +114 -0
  127. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +880 -0
  128. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +312 -0
  129. package/src/runtime/channels/backends/discord.mjs +781 -0
  130. package/src/runtime/channels/data/voice-runtime-manifest.json +138 -0
  131. package/src/runtime/channels/index.mjs +3309 -0
  132. package/src/runtime/channels/lib/config.mjs +285 -0
  133. package/src/runtime/channels/lib/drop-trace.mjs +71 -0
  134. package/src/runtime/channels/lib/event-pipeline.mjs +81 -0
  135. package/src/runtime/channels/lib/holidays.mjs +138 -0
  136. package/src/runtime/channels/lib/hook-pipe-server.mjs +671 -0
  137. package/src/runtime/channels/lib/output-forwarder.mjs +765 -0
  138. package/src/runtime/channels/lib/runtime-paths.mjs +497 -0
  139. package/src/runtime/channels/lib/scheduler.mjs +710 -0
  140. package/src/runtime/channels/lib/session-discovery.mjs +102 -0
  141. package/src/runtime/channels/lib/state-file.mjs +68 -0
  142. package/src/runtime/channels/lib/status-snapshot.mjs +224 -0
  143. package/src/runtime/channels/lib/tool-format.mjs +124 -0
  144. package/src/runtime/channels/lib/transcript-discovery.mjs +195 -0
  145. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +734 -0
  146. package/src/runtime/channels/lib/webhook.mjs +1288 -0
  147. package/src/runtime/channels/tool-defs.mjs +177 -0
  148. package/src/runtime/lib/keychain-cjs.cjs +289 -0
  149. package/src/runtime/memory/data/runtime-manifest.json +40 -0
  150. package/src/runtime/memory/index.mjs +3600 -0
  151. package/src/runtime/memory/lib/core-memory-store.mjs +336 -0
  152. package/src/runtime/memory/lib/embedding-provider.mjs +275 -0
  153. package/src/runtime/memory/lib/embedding-worker.mjs +331 -0
  154. package/src/runtime/memory/lib/memory-cycle-requests.mjs +276 -0
  155. package/src/runtime/memory/lib/memory-cycle1.mjs +783 -0
  156. package/src/runtime/memory/lib/memory-cycle2.mjs +1389 -0
  157. package/src/runtime/memory/lib/memory-cycle3.mjs +646 -0
  158. package/src/runtime/memory/lib/memory-embed.mjs +300 -0
  159. package/src/runtime/memory/lib/memory-ops-policy.mjs +149 -0
  160. package/src/runtime/memory/lib/memory-recall-store.mjs +644 -0
  161. package/src/runtime/memory/lib/memory.mjs +418 -0
  162. package/src/runtime/memory/lib/pg/adapter.mjs +314 -0
  163. package/src/runtime/memory/lib/pg/process.mjs +366 -0
  164. package/src/runtime/memory/lib/pg/supervisor.mjs +495 -0
  165. package/src/runtime/memory/lib/runtime-fetcher.mjs +464 -0
  166. package/src/runtime/memory/lib/trace-store.mjs +734 -0
  167. package/src/runtime/memory/tool-defs.mjs +79 -0
  168. package/src/runtime/search/index.mjs +925 -0
  169. package/src/runtime/search/lib/config.mjs +61 -0
  170. package/src/runtime/search/lib/web-tools.mjs +1278 -0
  171. package/src/runtime/search/tool-defs.mjs +64 -0
  172. package/src/runtime/shared/atomic-file.mjs +435 -0
  173. package/src/runtime/shared/background-tasks.mjs +376 -0
  174. package/src/runtime/shared/child-guardian.mjs +98 -0
  175. package/src/runtime/shared/config.mjs +393 -0
  176. package/src/runtime/shared/err-text.mjs +121 -0
  177. package/src/runtime/shared/launcher-control.mjs +259 -0
  178. package/src/runtime/shared/llm/cost.mjs +66 -0
  179. package/src/runtime/shared/llm/http-agent.mjs +129 -0
  180. package/src/runtime/shared/open-url.mjs +37 -0
  181. package/src/runtime/shared/plugin-paths.mjs +25 -0
  182. package/src/runtime/shared/process-shutdown.mjs +147 -0
  183. package/src/runtime/shared/schedules-store.mjs +70 -0
  184. package/src/runtime/shared/tool-execution-contract.mjs +104 -0
  185. package/src/runtime/shared/tool-surface.mjs +950 -0
  186. package/src/runtime/shared/user-cwd.mjs +221 -0
  187. package/src/runtime/shared/user-data-guard.mjs +232 -0
  188. package/src/runtime/shared/workspace-router.mjs +259 -0
  189. package/src/standalone/bridge-tool.mjs +1414 -0
  190. package/src/standalone/channel-admin.mjs +366 -0
  191. package/src/standalone/channel-worker-preload.cjs +3 -0
  192. package/src/standalone/channel-worker.mjs +353 -0
  193. package/src/standalone/explore-tool.mjs +233 -0
  194. package/src/standalone/hook-bus.mjs +246 -0
  195. package/src/standalone/plugin-admin.mjs +247 -0
  196. package/src/standalone/provider-admin.mjs +338 -0
  197. package/src/standalone/seeds.mjs +94 -0
  198. package/src/standalone/usage-dashboard.mjs +510 -0
  199. package/src/tui/App.jsx +5438 -0
  200. package/src/tui/components/AnsiText.jsx +199 -0
  201. package/src/tui/components/ContextPanel.jsx +217 -0
  202. package/src/tui/components/Markdown.jsx +205 -0
  203. package/src/tui/components/MarkdownTable.jsx +204 -0
  204. package/src/tui/components/Message.jsx +103 -0
  205. package/src/tui/components/Picker.jsx +317 -0
  206. package/src/tui/components/PromptInput.jsx +584 -0
  207. package/src/tui/components/QueuedCommands.jsx +47 -0
  208. package/src/tui/components/SlashCommandPalette.jsx +114 -0
  209. package/src/tui/components/Spinner.jsx +317 -0
  210. package/src/tui/components/StatusLine.jsx +87 -0
  211. package/src/tui/components/TextEntryPanel.jsx +323 -0
  212. package/src/tui/components/ToolExecution.jsx +772 -0
  213. package/src/tui/components/TurnDone.jsx +78 -0
  214. package/src/tui/components/UsagePanel.jsx +331 -0
  215. package/src/tui/dist/index.mjs +12359 -0
  216. package/src/tui/engine.mjs +2410 -0
  217. package/src/tui/figures.mjs +50 -0
  218. package/src/tui/hooks/useEngine.mjs +16 -0
  219. package/src/tui/index.jsx +254 -0
  220. package/src/tui/input-editing.mjs +242 -0
  221. package/src/tui/markdown/format-token.mjs +194 -0
  222. package/src/tui/paste-attachments.mjs +198 -0
  223. package/src/tui/runtime/shared/process-shutdown.mjs +1 -0
  224. package/src/tui/spinner-verbs.mjs +45 -0
  225. package/src/tui/theme.mjs +67 -0
  226. package/src/tui/time-format.mjs +53 -0
  227. package/src/ui/ansi.mjs +115 -0
  228. package/src/ui/markdown.mjs +195 -0
  229. package/src/ui/statusline.mjs +730 -0
  230. package/src/ui/tool-card.mjs +101 -0
  231. package/src/vendor/statusline/bin/statusline-lib.mjs +805 -0
  232. package/src/vendor/statusline/bin/statusline-route.mjs +596 -0
  233. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +285 -0
  234. package/src/vendor/statusline/src/gateway/claude-current.mjs +320 -0
  235. package/src/vendor/statusline/src/gateway/route-meta.mjs +753 -0
  236. package/src/vendor/statusline/src/gateway/session-routes.mjs +244 -0
  237. package/src/workflows/default/WORKFLOW.md +7 -0
  238. package/src/workflows/default/workflow.json +14 -0
  239. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  240. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  241. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  242. package/vendor/ink/build/colorize.d.ts +3 -0
  243. package/vendor/ink/build/colorize.js +48 -0
  244. package/vendor/ink/build/colorize.js.map +1 -0
  245. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  246. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  247. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  248. package/vendor/ink/build/components/AnimationContext.d.ts +9 -0
  249. package/vendor/ink/build/components/AnimationContext.js +13 -0
  250. package/vendor/ink/build/components/AnimationContext.js.map +1 -0
  251. package/vendor/ink/build/components/App.d.ts +24 -0
  252. package/vendor/ink/build/components/App.js +554 -0
  253. package/vendor/ink/build/components/App.js.map +1 -0
  254. package/vendor/ink/build/components/AppContext.d.ts +80 -0
  255. package/vendor/ink/build/components/AppContext.js +25 -0
  256. package/vendor/ink/build/components/AppContext.js.map +1 -0
  257. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  258. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  259. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  260. package/vendor/ink/build/components/Box.d.ts +130 -0
  261. package/vendor/ink/build/components/Box.js +34 -0
  262. package/vendor/ink/build/components/Box.js.map +1 -0
  263. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  264. package/vendor/ink/build/components/CursorContext.js +8 -0
  265. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  266. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  267. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  268. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  269. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  270. package/vendor/ink/build/components/ErrorOverview.js +90 -0
  271. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  272. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  273. package/vendor/ink/build/components/FocusContext.js +17 -0
  274. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  275. package/vendor/ink/build/components/Newline.d.ts +13 -0
  276. package/vendor/ink/build/components/Newline.js +8 -0
  277. package/vendor/ink/build/components/Newline.js.map +1 -0
  278. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  279. package/vendor/ink/build/components/Spacer.js +11 -0
  280. package/vendor/ink/build/components/Spacer.js.map +1 -0
  281. package/vendor/ink/build/components/Static.d.ts +24 -0
  282. package/vendor/ink/build/components/Static.js +28 -0
  283. package/vendor/ink/build/components/Static.js.map +1 -0
  284. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  285. package/vendor/ink/build/components/StderrContext.js +13 -0
  286. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  287. package/vendor/ink/build/components/StdinContext.d.ts +28 -0
  288. package/vendor/ink/build/components/StdinContext.js +20 -0
  289. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  290. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  291. package/vendor/ink/build/components/StdoutContext.js +13 -0
  292. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  293. package/vendor/ink/build/components/Text.d.ts +55 -0
  294. package/vendor/ink/build/components/Text.js +50 -0
  295. package/vendor/ink/build/components/Text.js.map +1 -0
  296. package/vendor/ink/build/components/Transform.d.ts +16 -0
  297. package/vendor/ink/build/components/Transform.js +15 -0
  298. package/vendor/ink/build/components/Transform.js.map +1 -0
  299. package/vendor/ink/build/cursor-helpers.d.ts +39 -0
  300. package/vendor/ink/build/cursor-helpers.js +62 -0
  301. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  302. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  303. package/vendor/ink/build/devtools-window-polyfill.js +68 -0
  304. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  305. package/vendor/ink/build/devtools.d.ts +1 -0
  306. package/vendor/ink/build/devtools.js +36 -0
  307. package/vendor/ink/build/devtools.js.map +1 -0
  308. package/vendor/ink/build/dom.d.ts +62 -0
  309. package/vendor/ink/build/dom.js +143 -0
  310. package/vendor/ink/build/dom.js.map +1 -0
  311. package/vendor/ink/build/get-max-width.d.ts +3 -0
  312. package/vendor/ink/build/get-max-width.js +10 -0
  313. package/vendor/ink/build/get-max-width.js.map +1 -0
  314. package/vendor/ink/build/hooks/use-animation.d.ts +49 -0
  315. package/vendor/ink/build/hooks/use-animation.js +87 -0
  316. package/vendor/ink/build/hooks/use-animation.js.map +1 -0
  317. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  318. package/vendor/ink/build/hooks/use-app.js +8 -0
  319. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  320. package/vendor/ink/build/hooks/use-box-metrics.d.ts +59 -0
  321. package/vendor/ink/build/hooks/use-box-metrics.js +81 -0
  322. package/vendor/ink/build/hooks/use-box-metrics.js.map +1 -0
  323. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  324. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  325. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  326. package/vendor/ink/build/hooks/use-focus-manager.d.ts +43 -0
  327. package/vendor/ink/build/hooks/use-focus-manager.js +18 -0
  328. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  329. package/vendor/ink/build/hooks/use-focus.d.ts +30 -0
  330. package/vendor/ink/build/hooks/use-focus.js +43 -0
  331. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  332. package/vendor/ink/build/hooks/use-input.d.ts +132 -0
  333. package/vendor/ink/build/hooks/use-input.js +126 -0
  334. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  335. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +6 -0
  336. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +12 -0
  337. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  338. package/vendor/ink/build/hooks/use-paste.d.ts +35 -0
  339. package/vendor/ink/build/hooks/use-paste.js +62 -0
  340. package/vendor/ink/build/hooks/use-paste.js.map +1 -0
  341. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  342. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  343. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  344. package/vendor/ink/build/hooks/use-stdin.d.ts +7 -0
  345. package/vendor/ink/build/hooks/use-stdin.js +9 -0
  346. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  347. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  348. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  349. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  350. package/vendor/ink/build/hooks/use-window-size.d.ts +18 -0
  351. package/vendor/ink/build/hooks/use-window-size.js +22 -0
  352. package/vendor/ink/build/hooks/use-window-size.js.map +1 -0
  353. package/vendor/ink/build/index.d.ts +42 -0
  354. package/vendor/ink/build/index.js +24 -0
  355. package/vendor/ink/build/index.js.map +1 -0
  356. package/vendor/ink/build/ink.d.ts +146 -0
  357. package/vendor/ink/build/ink.js +1022 -0
  358. package/vendor/ink/build/ink.js.map +1 -0
  359. package/vendor/ink/build/input-parser.d.ts +10 -0
  360. package/vendor/ink/build/input-parser.js +194 -0
  361. package/vendor/ink/build/input-parser.js.map +1 -0
  362. package/vendor/ink/build/instances.d.ts +3 -0
  363. package/vendor/ink/build/instances.js +8 -0
  364. package/vendor/ink/build/instances.js.map +1 -0
  365. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  366. package/vendor/ink/build/kitty-keyboard.js +32 -0
  367. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  368. package/vendor/ink/build/log-update.d.ts +20 -0
  369. package/vendor/ink/build/log-update.js +261 -0
  370. package/vendor/ink/build/log-update.js.map +1 -0
  371. package/vendor/ink/build/measure-element.d.ts +20 -0
  372. package/vendor/ink/build/measure-element.js +13 -0
  373. package/vendor/ink/build/measure-element.js.map +1 -0
  374. package/vendor/ink/build/measure-text.d.ts +6 -0
  375. package/vendor/ink/build/measure-text.js +21 -0
  376. package/vendor/ink/build/measure-text.js.map +1 -0
  377. package/vendor/ink/build/output.d.ts +35 -0
  378. package/vendor/ink/build/output.js +328 -0
  379. package/vendor/ink/build/output.js.map +1 -0
  380. package/vendor/ink/build/parse-keypress.d.ts +20 -0
  381. package/vendor/ink/build/parse-keypress.js +495 -0
  382. package/vendor/ink/build/parse-keypress.js.map +1 -0
  383. package/vendor/ink/build/reconciler.d.ts +4 -0
  384. package/vendor/ink/build/reconciler.js +306 -0
  385. package/vendor/ink/build/reconciler.js.map +1 -0
  386. package/vendor/ink/build/render-background.d.ts +4 -0
  387. package/vendor/ink/build/render-background.js +25 -0
  388. package/vendor/ink/build/render-background.js.map +1 -0
  389. package/vendor/ink/build/render-border.d.ts +4 -0
  390. package/vendor/ink/build/render-border.js +84 -0
  391. package/vendor/ink/build/render-border.js.map +1 -0
  392. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  393. package/vendor/ink/build/render-node-to-output.js +162 -0
  394. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  395. package/vendor/ink/build/render-to-string.d.ts +38 -0
  396. package/vendor/ink/build/render-to-string.js +116 -0
  397. package/vendor/ink/build/render-to-string.js.map +1 -0
  398. package/vendor/ink/build/render.d.ts +176 -0
  399. package/vendor/ink/build/render.js +71 -0
  400. package/vendor/ink/build/render.js.map +1 -0
  401. package/vendor/ink/build/renderer.d.ts +8 -0
  402. package/vendor/ink/build/renderer.js +64 -0
  403. package/vendor/ink/build/renderer.js.map +1 -0
  404. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  405. package/vendor/ink/build/sanitize-ansi.js +27 -0
  406. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  407. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  408. package/vendor/ink/build/squash-text-nodes.js +36 -0
  409. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  410. package/vendor/ink/build/styles.d.ts +302 -0
  411. package/vendor/ink/build/styles.js +303 -0
  412. package/vendor/ink/build/styles.js.map +1 -0
  413. package/vendor/ink/build/utils.d.ts +9 -0
  414. package/vendor/ink/build/utils.js +19 -0
  415. package/vendor/ink/build/utils.js.map +1 -0
  416. package/vendor/ink/build/wrap-text.d.ts +3 -0
  417. package/vendor/ink/build/wrap-text.js +38 -0
  418. package/vendor/ink/build/wrap-text.js.map +1 -0
  419. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  420. package/vendor/ink/build/write-synchronized.js +9 -0
  421. package/vendor/ink/build/write-synchronized.js.map +1 -0
  422. package/vendor/ink/license +10 -0
  423. package/vendor/ink/package.json +137 -0
  424. package/.claude-plugin/marketplace.json +0 -34
  425. package/.claude-plugin/plugin.json +0 -20
  426. package/.gitattributes +0 -34
  427. package/.mcp.json +0 -14
  428. package/ARCHITECTURE.md +0 -77
  429. package/CHANGELOG.md +0 -30
  430. package/CONTRIBUTING.md +0 -45
  431. package/DATA-FLOW.md +0 -79
  432. package/LICENSE +0 -21
  433. package/SECURITY.md +0 -138
  434. package/UNINSTALL.md +0 -112
  435. package/agents/maintenance.md +0 -5
  436. package/agents/memory-classification.md +0 -30
  437. package/agents/scheduler-task.md +0 -18
  438. package/agents/webhook-handler.md +0 -27
  439. package/agents/worker.md +0 -24
  440. package/bin/bridge +0 -133
  441. package/bin/statusline-launcher.mjs +0 -82
  442. package/bin/statusline-lib.mjs +0 -558
  443. package/bin/statusline.mjs +0 -615
  444. package/bun.lock +0 -927
  445. package/commands/config.md +0 -16
  446. package/commands/doctor.md +0 -13
  447. package/commands/setup.md +0 -17
  448. package/defaults/hidden-roles.json +0 -68
  449. package/defaults/memory-chunk-prompt.md +0 -63
  450. package/defaults/mixdog-config.template.json +0 -27
  451. package/defaults/user-workflow.json +0 -8
  452. package/defaults/user-workflow.md +0 -17
  453. package/hooks/hooks.json +0 -73
  454. package/hooks/lib/active-instance.cjs +0 -77
  455. package/hooks/lib/permission-evaluator.cjs +0 -411
  456. package/hooks/lib/permission-route.cjs +0 -63
  457. package/hooks/lib/settings-loader.cjs +0 -117
  458. package/hooks/post-tool-use.cjs +0 -84
  459. package/hooks/pre-mcp-sandbox.cjs +0 -158
  460. package/hooks/pre-tool-subagent.cjs +0 -258
  461. package/hooks/session-start.cjs +0 -1479
  462. package/hooks/shim-launcher.cjs +0 -65
  463. package/hooks/turn-timer.cjs +0 -82
  464. package/lib/claude-md-writer.cjs +0 -386
  465. package/lib/keychain-cjs.cjs +0 -290
  466. package/lib/plugin-paths.cjs +0 -69
  467. package/lib/rules-builder.cjs +0 -241
  468. package/native/README.md +0 -117
  469. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  470. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  471. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  472. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  473. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  474. package/prompts/code-review.txt +0 -16
  475. package/prompts/security-audit.txt +0 -17
  476. package/rules/bridge/00-common.md +0 -39
  477. package/rules/bridge/20-skip-protocol.md +0 -18
  478. package/rules/bridge/30-explorer.md +0 -33
  479. package/rules/bridge/40-cycle1-agent.md +0 -52
  480. package/rules/bridge/41-cycle2-agent.md +0 -62
  481. package/rules/lead/00-tool-lead.md +0 -61
  482. package/rules/lead/01-general.md +0 -23
  483. package/rules/lead/02-channels.md +0 -49
  484. package/rules/lead/03-team.md +0 -27
  485. package/rules/lead/04-workflow.md +0 -20
  486. package/rules/shared/00-language.md +0 -14
  487. package/rules/shared/01-tool.md +0 -138
  488. package/scripts/bootstrap.mjs +0 -130
  489. package/scripts/bridge-unify-smoke.mjs +0 -308
  490. package/scripts/build-runtime-linux.sh +0 -348
  491. package/scripts/build-runtime-macos.sh +0 -217
  492. package/scripts/build-runtime-windows.ps1 +0 -242
  493. package/scripts/builtin-utils-smoke.mjs +0 -398
  494. package/scripts/bump.mjs +0 -80
  495. package/scripts/check-json.mjs +0 -45
  496. package/scripts/check-syntax-changed.mjs +0 -102
  497. package/scripts/check-syntax.mjs +0 -58
  498. package/scripts/code-graph-batch.test.mjs +0 -33
  499. package/scripts/config-preserve-smoke.mjs +0 -180
  500. package/scripts/doctor.mjs +0 -489
  501. package/scripts/edit-normalize-fuzz.mjs +0 -130
  502. package/scripts/edit-normalize-smoke.mjs +0 -401
  503. package/scripts/edit-operation-smoke.mjs +0 -369
  504. package/scripts/edit2-smoke.mjs +0 -63
  505. package/scripts/ensure-deps.mjs +0 -259
  506. package/scripts/fuzzy-e2e.mjs +0 -28
  507. package/scripts/fuzzy-smoke.mjs +0 -26
  508. package/scripts/generate-runtime-manifest.mjs +0 -166
  509. package/scripts/guard-smoke.mjs +0 -66
  510. package/scripts/hidden-role-schema-smoke.mjs +0 -162
  511. package/scripts/hook-routing-smoke.mjs +0 -29
  512. package/scripts/inject-input.ps1 +0 -204
  513. package/scripts/io-complex-smoke.mjs +0 -667
  514. package/scripts/io-explore-bench.mjs +0 -424
  515. package/scripts/io-guardrails-smoke.mjs +0 -205
  516. package/scripts/io-mini-bench-baseline.json +0 -11
  517. package/scripts/io-mini-bench.mjs +0 -216
  518. package/scripts/io-route-harness.mjs +0 -933
  519. package/scripts/io-telemetry-report.mjs +0 -691
  520. package/scripts/mutation-bench.mjs +0 -564
  521. package/scripts/mutation-io-smoke.mjs +0 -1097
  522. package/scripts/native-patch-bridge-smoke.mjs +0 -288
  523. package/scripts/native-patch-smoke.mjs +0 -304
  524. package/scripts/openai-oauth-catalog-smoke.mjs +0 -53
  525. package/scripts/patch-interior-context-smoke.mjs +0 -49
  526. package/scripts/patch-newline-utf8-smoke.mjs +0 -157
  527. package/scripts/perf-hook-smoke.mjs +0 -71
  528. package/scripts/permission-eval-smoke.mjs +0 -443
  529. package/scripts/prep-patch.mjs +0 -53
  530. package/scripts/prep-shim.mjs +0 -96
  531. package/scripts/provider-cache-smoke.mjs +0 -687
  532. package/scripts/report-runtime-health.mjs +0 -132
  533. package/scripts/resolve-bun.mjs +0 -60
  534. package/scripts/run-mcp.mjs +0 -1448
  535. package/scripts/salvage-v4a-shatter.test.mjs +0 -58
  536. package/scripts/scoped-cache-io-smoke.mjs +0 -103
  537. package/scripts/shell-policy-round3-smoke.mjs +0 -46
  538. package/scripts/smoke-runtime-negative.ps1 +0 -100
  539. package/scripts/smoke-runtime-negative.sh +0 -95
  540. package/scripts/stall-policy-smoke.mjs +0 -50
  541. package/scripts/start-memory-worker.mjs +0 -23
  542. package/scripts/statusline-launcher-smoke.mjs +0 -82
  543. package/scripts/stress-atomic-write.mjs +0 -1028
  544. package/scripts/test-fault-inject.mjs +0 -164
  545. package/scripts/test-large-file.mjs +0 -174
  546. package/scripts/tool-edge-smoke.mjs +0 -209
  547. package/scripts/uninstall.mjs +0 -201
  548. package/scripts/webhook-selfheal-smoke.mjs +0 -27
  549. package/scripts/write-overwrite-guard-smoke.mjs +0 -56
  550. package/server-main.mjs +0 -3109
  551. package/server.mjs +0 -468
  552. package/setup/config-merge.mjs +0 -246
  553. package/setup/install.mjs +0 -574
  554. package/setup/launch-core.mjs +0 -617
  555. package/setup/launch.mjs +0 -101
  556. package/setup/locate-claude.mjs +0 -56
  557. package/setup/mixdog-cli.mjs +0 -122
  558. package/setup/setup-server.mjs +0 -3305
  559. package/setup/setup.html +0 -3740
  560. package/setup/tui.mjs +0 -325
  561. package/skills/retro-skill-proposer/SKILL.md +0 -92
  562. package/skills/schedule-add/SKILL.md +0 -77
  563. package/skills/setup/SKILL.md +0 -356
  564. package/skills/webhook-add/SKILL.md +0 -81
  565. package/src/agent/bridge-stall-watchdog.mjs +0 -337
  566. package/src/agent/index.mjs +0 -2138
  567. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +0 -1010
  568. package/src/agent/orchestrator/bridge-retry.mjs +0 -220
  569. package/src/agent/orchestrator/bridge-trace.mjs +0 -583
  570. package/src/agent/orchestrator/cache-mtime.mjs +0 -58
  571. package/src/agent/orchestrator/config.mjs +0 -405
  572. package/src/agent/orchestrator/context/collect.mjs +0 -651
  573. package/src/agent/orchestrator/dispatch-persist.mjs +0 -549
  574. package/src/agent/orchestrator/drain-registry.mjs +0 -50
  575. package/src/agent/orchestrator/explore-validator.mjs +0 -8
  576. package/src/agent/orchestrator/internal-roles.mjs +0 -118
  577. package/src/agent/orchestrator/internal-tools.mjs +0 -88
  578. package/src/agent/orchestrator/jobs.mjs +0 -116
  579. package/src/agent/orchestrator/mcp/client.mjs +0 -364
  580. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +0 -1881
  581. package/src/agent/orchestrator/providers/anthropic.mjs +0 -594
  582. package/src/agent/orchestrator/providers/gemini.mjs +0 -1530
  583. package/src/agent/orchestrator/providers/grok-oauth.mjs +0 -779
  584. package/src/agent/orchestrator/providers/model-catalog.mjs +0 -374
  585. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +0 -366
  586. package/src/agent/orchestrator/providers/openai-compat.mjs +0 -1511
  587. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -1891
  588. package/src/agent/orchestrator/providers/openai-oauth.mjs +0 -1456
  589. package/src/agent/orchestrator/providers/openai-ws.mjs +0 -127
  590. package/src/agent/orchestrator/providers/registry.mjs +0 -192
  591. package/src/agent/orchestrator/providers/retry-classifier.mjs +0 -325
  592. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +0 -142
  593. package/src/agent/orchestrator/session/cache/read-cache.mjs +0 -319
  594. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +0 -361
  595. package/src/agent/orchestrator/session/loop.mjs +0 -1478
  596. package/src/agent/orchestrator/session/manager.mjs +0 -1991
  597. package/src/agent/orchestrator/session/result-classification.mjs +0 -65
  598. package/src/agent/orchestrator/session/store.mjs +0 -632
  599. package/src/agent/orchestrator/session/stream-watchdog.mjs +0 -130
  600. package/src/agent/orchestrator/session/tool-result-offload.mjs +0 -166
  601. package/src/agent/orchestrator/session/trim.mjs +0 -491
  602. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +0 -115
  603. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +0 -331
  604. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +0 -150
  605. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +0 -228
  606. package/src/agent/orchestrator/smart-bridge/index.mjs +0 -215
  607. package/src/agent/orchestrator/smart-bridge/profiles.mjs +0 -37
  608. package/src/agent/orchestrator/smart-bridge/registry.mjs +0 -348
  609. package/src/agent/orchestrator/stall-policy.mjs +0 -201
  610. package/src/agent/orchestrator/tool-loop-guard.mjs +0 -75
  611. package/src/agent/orchestrator/tools/bash-session.mjs +0 -722
  612. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -455
  613. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -480
  614. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -256
  615. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +0 -58
  616. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +0 -240
  617. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +0 -113
  618. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +0 -74
  619. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +0 -242
  620. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +0 -211
  621. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +0 -1364
  622. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +0 -126
  623. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +0 -141
  624. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +0 -194
  625. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +0 -60
  626. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +0 -168
  627. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +0 -173
  628. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +0 -48
  629. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -99
  630. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +0 -193
  631. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +0 -597
  632. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  633. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +0 -300
  634. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +0 -152
  635. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +0 -118
  636. package/src/agent/orchestrator/tools/builtin/read-open.mjs +0 -190
  637. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +0 -728
  638. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +0 -173
  639. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +0 -602
  640. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +0 -196
  641. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +0 -422
  642. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +0 -158
  643. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +0 -869
  644. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +0 -962
  645. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +0 -223
  646. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +0 -206
  647. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +0 -401
  648. package/src/agent/orchestrator/tools/builtin.mjs +0 -503
  649. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +0 -24
  650. package/src/agent/orchestrator/tools/code-graph.mjs +0 -4095
  651. package/src/agent/orchestrator/tools/cwd-tool.mjs +0 -298
  652. package/src/agent/orchestrator/tools/destructive-warning.mjs +0 -323
  653. package/src/agent/orchestrator/tools/edit-normalize.mjs +0 -603
  654. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +0 -154
  655. package/src/agent/orchestrator/tools/graph-manifest.json +0 -26
  656. package/src/agent/orchestrator/tools/host-input.mjs +0 -204
  657. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +0 -143
  658. package/src/agent/orchestrator/tools/patch-manifest.json +0 -26
  659. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +0 -20
  660. package/src/agent/orchestrator/tools/patch.mjs +0 -2754
  661. package/src/agent/orchestrator/tools/progress-message.mjs +0 -118
  662. package/src/agent/orchestrator/tools/shell-command.mjs +0 -865
  663. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +0 -7
  664. package/src/agent/orchestrator/tools/shell-snapshot.mjs +0 -313
  665. package/src/agent/orchestrator/workflow-store.mjs +0 -93
  666. package/src/agent/tool-defs.mjs +0 -103
  667. package/src/channels/backends/discord.mjs +0 -784
  668. package/src/channels/data/voice-runtime-manifest.json +0 -138
  669. package/src/channels/index.mjs +0 -3268
  670. package/src/channels/lib/config.mjs +0 -292
  671. package/src/channels/lib/drop-trace.mjs +0 -71
  672. package/src/channels/lib/event-pipeline.mjs +0 -81
  673. package/src/channels/lib/holidays.mjs +0 -138
  674. package/src/channels/lib/hook-pipe-server.mjs +0 -822
  675. package/src/channels/lib/output-forwarder.mjs +0 -765
  676. package/src/channels/lib/runtime-paths.mjs +0 -517
  677. package/src/channels/lib/scheduler.mjs +0 -723
  678. package/src/channels/lib/session-discovery.mjs +0 -103
  679. package/src/channels/lib/state-file.mjs +0 -68
  680. package/src/channels/lib/status-snapshot.mjs +0 -219
  681. package/src/channels/lib/tool-format.mjs +0 -140
  682. package/src/channels/lib/transcript-discovery.mjs +0 -195
  683. package/src/channels/lib/voice-runtime-fetcher.mjs +0 -734
  684. package/src/channels/lib/webhook.mjs +0 -1318
  685. package/src/channels/tool-defs.mjs +0 -170
  686. package/src/daemon/host.mjs +0 -118
  687. package/src/daemon/mcp-transport.mjs +0 -47
  688. package/src/daemon/session.mjs +0 -100
  689. package/src/daemon/thin-client.mjs +0 -71
  690. package/src/daemon/transport.mjs +0 -163
  691. package/src/memory/data/runtime-manifest.json +0 -40
  692. package/src/memory/index.mjs +0 -3332
  693. package/src/memory/lib/core-memory-store.mjs +0 -330
  694. package/src/memory/lib/embedding-provider.mjs +0 -269
  695. package/src/memory/lib/embedding-worker.mjs +0 -323
  696. package/src/memory/lib/memory-cycle1.mjs +0 -645
  697. package/src/memory/lib/memory-cycle2.mjs +0 -1284
  698. package/src/memory/lib/memory-cycle3.mjs +0 -540
  699. package/src/memory/lib/memory-embed.mjs +0 -299
  700. package/src/memory/lib/memory-ops-policy.mjs +0 -190
  701. package/src/memory/lib/memory-recall-store.mjs +0 -638
  702. package/src/memory/lib/memory.mjs +0 -412
  703. package/src/memory/lib/pg/adapter.mjs +0 -308
  704. package/src/memory/lib/pg/process.mjs +0 -360
  705. package/src/memory/lib/pg/supervisor.mjs +0 -396
  706. package/src/memory/lib/runtime-fetcher.mjs +0 -458
  707. package/src/memory/lib/trace-store.mjs +0 -728
  708. package/src/memory/tool-defs.mjs +0 -79
  709. package/src/search/index.mjs +0 -1173
  710. package/src/search/lib/backends/anthropic-oauth.mjs +0 -98
  711. package/src/search/lib/backends/exa.mjs +0 -50
  712. package/src/search/lib/backends/firecrawl.mjs +0 -61
  713. package/src/search/lib/backends/gemini-api.mjs +0 -83
  714. package/src/search/lib/backends/grok-oauth.mjs +0 -86
  715. package/src/search/lib/backends/index.mjs +0 -150
  716. package/src/search/lib/backends/openai-api.mjs +0 -144
  717. package/src/search/lib/backends/openai-oauth.mjs +0 -102
  718. package/src/search/lib/backends/openai-web-search.mjs +0 -76
  719. package/src/search/lib/backends/tavily.mjs +0 -55
  720. package/src/search/lib/backends/xai-api.mjs +0 -113
  721. package/src/search/lib/config.mjs +0 -192
  722. package/src/search/lib/provider-usage.mjs +0 -67
  723. package/src/search/lib/providers.mjs +0 -47
  724. package/src/search/lib/search-intent.mjs +0 -109
  725. package/src/search/lib/setup-handler.mjs +0 -261
  726. package/src/search/lib/web-tools.mjs +0 -1219
  727. package/src/search/tool-defs.mjs +0 -83
  728. package/src/setup/defender-exclusion.mjs +0 -183
  729. package/src/shared/atomic-file.mjs +0 -436
  730. package/src/shared/config.mjs +0 -372
  731. package/src/shared/daemon-recycle.mjs +0 -108
  732. package/src/shared/disable-claude-builtins.mjs +0 -91
  733. package/src/shared/err-text.mjs +0 -12
  734. package/src/shared/llm/cost.mjs +0 -66
  735. package/src/shared/llm/http-agent.mjs +0 -123
  736. package/src/shared/open-url.mjs +0 -62
  737. package/src/shared/plugin-paths.mjs +0 -58
  738. package/src/shared/schedules-store.mjs +0 -70
  739. package/src/shared/seed.mjs +0 -136
  740. package/src/shared/user-cwd.mjs +0 -225
  741. package/src/shared/user-data-guard.mjs +0 -244
  742. package/src/status/aggregator.mjs +0 -584
  743. package/src/status/server.mjs +0 -413
  744. package/tools.json +0 -1653
  745. /package/{defaults → src/defaults}/cycle3-review-prompt.md +0 -0
  746. /package/{defaults → src/defaults}/memory-promote-prompt.md +0 -0
  747. /package/{hooks → src/hooks}/lib/permission-rules.cjs +0 -0
  748. /package/{lib → src/lib}/config-cjs.cjs +0 -0
  749. /package/{lib → src/lib}/hook-pipe-path.cjs +0 -0
  750. /package/{lib → src/lib}/mixdog-debug.cjs +0 -0
  751. /package/{lib → src/lib}/text-utils.cjs +0 -0
  752. /package/{rules → src/rules}/bridge/42-cycle3-agent.md +0 -0
  753. /package/src/{agent → runtime/agent}/orchestrator/activity-bus.mjs +0 -0
  754. /package/src/{agent → runtime/agent}/orchestrator/providers/anthropic-betas.mjs +0 -0
  755. /package/src/{agent → runtime/agent}/orchestrator/session/abort-lookup.mjs +0 -0
  756. /package/src/{agent → runtime/agent}/orchestrator/session/cache/post-edit-marks.mjs +0 -0
  757. /package/src/{agent → runtime/agent}/orchestrator/session/cache/scoped-cache-outcome.mjs +0 -0
  758. /package/src/{agent → runtime/agent}/orchestrator/session/cache/util.mjs +0 -0
  759. /package/src/{agent → runtime/agent}/orchestrator/session/read-dedup.mjs +0 -0
  760. /package/src/{agent → runtime/agent}/orchestrator/session/save-session-worker.mjs +0 -0
  761. /package/src/{agent → runtime/agent}/orchestrator/smart-bridge/session-builder.mjs +0 -0
  762. /package/src/{agent → runtime/agent}/orchestrator/tools/bash-policy-scan.mjs +0 -0
  763. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/advisory-lock.mjs +0 -0
  764. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/atomic-write.mjs +0 -0
  765. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/binary-file.mjs +0 -0
  766. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cache-layers.mjs +0 -0
  767. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cwd-utils.mjs +0 -0
  768. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/device-paths.mjs +0 -0
  769. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -0
  770. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diff-utils.mjs +0 -0
  771. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/fs-reachability.mjs +0 -0
  772. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/grep-formatting.mjs +0 -0
  773. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/hash-utils.mjs +0 -0
  774. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/list-formatting.mjs +0 -0
  775. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/open-config-tool.mjs +0 -0
  776. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-locks.mjs +0 -0
  777. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-utils.mjs +0 -0
  778. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-args.mjs +0 -0
  779. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-batch.mjs +0 -0
  780. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-constants.mjs +0 -0
  781. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image-resize.mjs +0 -0
  782. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image.mjs +0 -0
  783. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-lines.mjs +0 -0
  784. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-mode-tool.mjs +0 -0
  785. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-range-index.mjs +0 -0
  786. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-ranges.mjs +0 -0
  787. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-special-files.mjs +0 -0
  788. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-tool.mjs +0 -0
  789. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-windows.mjs +0 -0
  790. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-analysis.mjs +0 -0
  791. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-output.mjs +0 -0
  792. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-helpers.mjs +0 -0
  793. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-validation.mjs +0 -0
  794. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/text-stats.mjs +0 -0
  795. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/windows-roots.mjs +0 -0
  796. /package/src/{agent → runtime/agent}/orchestrator/tools/code-graph-prewarm-worker.mjs +0 -0
  797. /package/src/{agent → runtime/agent}/orchestrator/tools/env-scrub.mjs +0 -0
  798. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-content-cache.mjs +0 -0
  799. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-planner.mjs +0 -0
  800. /package/src/{agent → runtime/agent}/orchestrator/tools/next-call-utils.mjs +0 -0
  801. /package/src/{agent → runtime/agent}/orchestrator/tools/result-compression.mjs +0 -0
  802. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-exec-policy.mjs +0 -0
  803. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy-danger-target.mjs +0 -0
  804. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy.mjs +0 -0
  805. /package/src/{channels → runtime/channels}/lib/cli-worker-host.mjs +0 -0
  806. /package/src/{channels → runtime/channels}/lib/config-lock.mjs +0 -0
  807. /package/src/{channels → runtime/channels}/lib/event-queue.mjs +0 -0
  808. /package/src/{channels → runtime/channels}/lib/executor.mjs +0 -0
  809. /package/src/{channels → runtime/channels}/lib/format.mjs +0 -0
  810. /package/src/{channels → runtime/channels}/lib/interaction-workflows.mjs +0 -0
  811. /package/src/{channels → runtime/channels}/lib/memory-client.mjs +0 -0
  812. /package/src/{channels → runtime/channels}/lib/session-control.mjs +0 -0
  813. /package/src/{channels → runtime/channels}/lib/settings.mjs +0 -0
  814. /package/src/{channels → runtime/channels}/lib/whisper-server.mjs +0 -0
  815. /package/src/{memory → runtime/memory}/lib/agent-ipc.mjs +0 -0
  816. /package/src/{memory → runtime/memory}/lib/bridge-trace-queries.mjs +0 -0
  817. /package/src/{memory → runtime/memory}/lib/llm-worker-host.mjs +0 -0
  818. /package/src/{memory → runtime/memory}/lib/memory-cycle.mjs +0 -0
  819. /package/src/{memory → runtime/memory}/lib/memory-extraction.mjs +0 -0
  820. /package/src/{memory → runtime/memory}/lib/memory-maintenance-store.mjs +0 -0
  821. /package/src/{memory → runtime/memory}/lib/memory-recall-id-patch.mjs +0 -0
  822. /package/src/{memory → runtime/memory}/lib/memory-recall-read-query.mjs +0 -0
  823. /package/src/{memory → runtime/memory}/lib/memory-recall-scope-filter.mjs +0 -0
  824. /package/src/{memory → runtime/memory}/lib/memory-retrievers.mjs +0 -0
  825. /package/src/{memory → runtime/memory}/lib/memory-score.mjs +0 -0
  826. /package/src/{memory → runtime/memory}/lib/memory-text-utils.mjs +0 -0
  827. /package/src/{memory → runtime/memory}/lib/model-profile.mjs +0 -0
  828. /package/src/{memory → runtime/memory}/lib/project-id-resolver.mjs +0 -0
  829. /package/src/{search → runtime/search}/lib/cache.mjs +0 -0
  830. /package/src/{search → runtime/search}/lib/formatter.mjs +0 -0
  831. /package/src/{search → runtime/search}/lib/state.mjs +0 -0
  832. /package/src/{shared → runtime/shared}/abort-controller.mjs +0 -0
  833. /package/src/{shared → runtime/shared}/llm/index.mjs +0 -0
  834. /package/src/{shared → runtime/shared}/llm/pid-cleanup.mjs +0 -0
  835. /package/src/{shared → runtime/shared}/llm/usage-log.mjs +0 -0
  836. /package/src/{shared → runtime/shared}/wsl.mjs +0 -0
@@ -0,0 +1,1719 @@
1
+ import OpenAI from 'openai';
2
+ import { createHash } from 'crypto';
3
+ import { loadConfig } from '../config.mjs';
4
+ import { withRetry } from './retry-classifier.mjs';
5
+ import { sendViaWebSocket } from './openai-oauth-ws.mjs';
6
+ import {
7
+ consumeCompatChatCompletionStream,
8
+ consumeCompatResponsesStream,
9
+ parseCompletedToolCallArgumentsJson,
10
+ } from './openai-compat-stream.mjs';
11
+ import { enrichModels, getModelMetadataSync } from './model-catalog.mjs';
12
+ import { appendBridgeTrace, traceBridgeUsage } from '../bridge-trace.mjs';
13
+ import {
14
+ resolveProviderCacheKey,
15
+ resolveProviderPromptCacheLane,
16
+ } from '../smart-bridge/cache-strategy.mjs';
17
+ import {
18
+ PROVIDER_FIRST_BYTE_TIMEOUT_MS,
19
+ PROVIDER_GENERATE_TOTAL_TIMEOUT_MS,
20
+ createTimeoutSignal,
21
+ createPassthroughSignal,
22
+ resolveTimeoutMs,
23
+ } from '../stall-policy.mjs';
24
+ import { traceHash, stableTraceStringify, summarizeTraceTools, traceTextShape } from './trace-utils.mjs';
25
+ import {
26
+ contentHasImage,
27
+ normalizeContentForOpenAIChat,
28
+ normalizeContentForOpenAIResponses,
29
+ splitToolContentForOpenAIChat,
30
+ splitToolContentForOpenAIResponses,
31
+ } from './media-normalization.mjs';
32
+ // OPENAI_COMPAT_PRESETS — self-declaring list of compat provider names and
33
+ // their base URLs / defaults. registry.mjs imports this export so there is no
34
+ // parallel OPENAI_COMPAT_PROVIDERS list to maintain separately.
35
+ export const OPENAI_COMPAT_PRESETS = {
36
+ deepseek: {
37
+ baseURL: 'https://api.deepseek.com',
38
+ defaultModel: 'deepseek-v4-pro',
39
+ },
40
+ xai: {
41
+ baseURL: 'https://api.x.ai/v1',
42
+ defaultModel: 'grok-4.3',
43
+ },
44
+ // OpenCode Go — low-cost coding-model subscription gateway. GLM / Kimi /
45
+ // DeepSeek / MiMo use the OpenAI-compatible chat surface; MiniMax / Qwen
46
+ // use the Anthropic-compatible messages surface. opencode-go.mjs provides
47
+ // the dual transport while this preset remains the shared base URL/key
48
+ // source. Auth is a single OPENCODE_API_KEY (Bearer).
49
+ 'opencode-go': {
50
+ baseURL: 'https://opencode.ai/zen/go/v1',
51
+ defaultModel: 'glm-5.2',
52
+ },
53
+ ollama: {
54
+ baseURL: 'http://localhost:11434/v1',
55
+ defaultModel: 'llama3.3:latest',
56
+ },
57
+ lmstudio: {
58
+ baseURL: 'http://localhost:1234/v1',
59
+ defaultModel: 'default',
60
+ },
61
+ };
62
+ const PRESETS = OPENAI_COMPAT_PRESETS;
63
+ const MODEL_LIST_TIMEOUT_MS = resolveTimeoutMs(
64
+ 'MIXDOG_COMPAT_MODEL_LIST_TIMEOUT_MS',
65
+ 10_000,
66
+ { minMs: 1_000, maxMs: PROVIDER_GENERATE_TOTAL_TIMEOUT_MS },
67
+ );
68
+
69
+ // SSRF guard for provider baseURL. config.baseURL comes from user JSON;
70
+ // reject non-http(s) schemes (file:/data:/ftp:/etc.) and require https for
71
+ // any non-localhost host. Localhost-only presets (ollama, lmstudio) and
72
+ // loopback hosts may use http. Throws a clear config error — no silent
73
+ // fallback — so misconfig surfaces immediately instead of leaking apiKey.
74
+ function assertSafeBaseURL(rawURL, providerName) {
75
+ let parsed;
76
+ try {
77
+ parsed = new URL(String(rawURL));
78
+ } catch {
79
+ throw new Error(`[provider:${providerName}] invalid baseURL: ${rawURL}`);
80
+ }
81
+ const scheme = parsed.protocol.toLowerCase();
82
+ if (scheme !== 'https:' && scheme !== 'http:') {
83
+ throw new Error(`[provider:${providerName}] baseURL scheme not allowed: ${parsed.protocol} (only http/https)`);
84
+ }
85
+ if (scheme === 'http:') {
86
+ const host = parsed.hostname.toLowerCase();
87
+ const isLocal = host === 'localhost' || host === '127.0.0.1' || host === '::1';
88
+ if (!isLocal) {
89
+ throw new Error(`[provider:${providerName}] baseURL must use https for non-localhost host (got ${parsed.protocol}//${parsed.hostname})`);
90
+ }
91
+ }
92
+ return rawURL;
93
+ }
94
+
95
+
96
+ function summarizeTraceMessages(messages) {
97
+ const summaries = (messages || []).map((m, index) => {
98
+ const content = typeof m?.content === 'string'
99
+ ? { type: 'text', ...traceTextShape(m.content) }
100
+ : { type: m?.content == null ? 'null' : typeof m.content, hash: traceHash(stableTraceStringify(m?.content ?? null)) };
101
+ const toolCalls = Array.isArray(m?.tool_calls)
102
+ ? m.tool_calls.map(tc => ({
103
+ name: tc?.function?.name || null,
104
+ argsHash: traceHash(tc?.function?.arguments || ''),
105
+ }))
106
+ : [];
107
+ return {
108
+ index,
109
+ role: m?.role || null,
110
+ content,
111
+ ...(typeof m?.reasoning_content === 'string'
112
+ ? { reasoningContent: traceTextShape(m.reasoning_content) }
113
+ : {}),
114
+ toolCallCount: toolCalls.length,
115
+ ...(toolCalls.length ? { toolCalls } : {}),
116
+ };
117
+ });
118
+ if (summaries.length <= 12) return summaries;
119
+ return [
120
+ ...summaries.slice(0, 8),
121
+ { omittedTurns: summaries.length - 12 },
122
+ ...summaries.slice(-4),
123
+ ];
124
+ }
125
+
126
+
127
+ function extractCompatCachedTokens(usage) {
128
+ const candidates = [
129
+ usage?.prompt_tokens_details?.cached_tokens,
130
+ usage?.input_tokens_details?.cached_tokens,
131
+ usage?.prompt_cache_hit_tokens,
132
+ usage?.cached_prompt_text_tokens,
133
+ ];
134
+ for (const v of candidates) {
135
+ const n = Number(v);
136
+ if (Number.isFinite(n) && n > 0) return n;
137
+ }
138
+ for (const v of candidates) {
139
+ const n = Number(v);
140
+ if (Number.isFinite(n)) return n;
141
+ }
142
+ return 0;
143
+ }
144
+
145
+ function positiveTokenInt(value) {
146
+ const n = Number(value);
147
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
148
+ }
149
+
150
+ function resolveCompatMaxOutputTokens(opts = {}) {
151
+ return positiveTokenInt(
152
+ opts.maxOutputTokens
153
+ ?? opts.outputTokens
154
+ ?? opts.max_output_tokens
155
+ ?? opts.maxTokens
156
+ ?? opts.max_tokens,
157
+ );
158
+ }
159
+
160
+ function xaiPrefixSeed({ opts, params, rawTools, model }) {
161
+ const providerKey = resolveProviderCacheKey(opts, 'xai');
162
+ const systemMessages = (params?.messages || [])
163
+ .filter(m => m?.role === 'system')
164
+ .map(m => String(m?.content ?? ''));
165
+ return stableTraceStringify({
166
+ scope: 'xai-prefix-model-system-tools',
167
+ providerKey: String(providerKey),
168
+ model: model || null,
169
+ systemMessages,
170
+ tools: summarizeTraceTools(rawTools),
171
+ });
172
+ }
173
+
174
+ function xaiCacheRouting(opts, params, rawTools, model) {
175
+ const sessionId = String(opts?.sessionId || opts?.session?.id || '').trim();
176
+ const providerKey = resolveProviderCacheKey(opts, 'xai');
177
+ const prefixSeed = xaiPrefixSeed({ opts, params, rawTools, model });
178
+ const prefixHash = traceHash(prefixSeed);
179
+ const routingSeed = stableTraceStringify({
180
+ scope: 'xai-chat-session-v1',
181
+ providerKey: String(providerKey),
182
+ model: model || null,
183
+ sessionId: sessionId || `ephemeral:${process.pid}`,
184
+ });
185
+ return {
186
+ key: deterministicUuidFromKey(routingSeed),
187
+ mode: sessionId ? 'session' : 'ephemeral',
188
+ seedHash: traceHash(routingSeed),
189
+ prefixHash,
190
+ ownerSessionHash: sessionId ? traceHash(sessionId) : null,
191
+ };
192
+ }
193
+
194
+ function xaiResponsesCacheRouting(opts, params, rawTools, model) {
195
+ // Default to 'prefix' so parallel workers sharing the same model + system
196
+ // + tools land on a common prompt_cache_key, letting xAI's server-side
197
+ // prefix cache hit across sessions instead of cold-starting per worker.
198
+ // Override with 'session' (env or opts) for legacy session-isolated lanes.
199
+ const scope = String(opts?.xaiResponsesCacheScope || process.env.MIXDOG_XAI_RESPONSES_CACHE_SCOPE || 'prefix')
200
+ .trim()
201
+ .toLowerCase();
202
+ if (scope !== 'prefix') {
203
+ return xaiCacheRouting(opts, params, rawTools, model);
204
+ }
205
+ const sessionId = String(opts?.sessionId || opts?.session?.id || '').trim();
206
+ const providerKey = resolveProviderCacheKey(opts, 'xai');
207
+ const prefixSeed = xaiPrefixSeed({ opts, params, rawTools, model });
208
+ const prefixHash = traceHash(prefixSeed);
209
+ const routingSeed = stableTraceStringify({
210
+ scope: 'xai-responses-prefix-v1',
211
+ providerKey: String(providerKey),
212
+ model: model || null,
213
+ prefixHash,
214
+ });
215
+ return {
216
+ key: deterministicUuidFromKey(routingSeed),
217
+ mode: 'prefix',
218
+ seedHash: traceHash(routingSeed),
219
+ prefixHash,
220
+ ownerSessionHash: sessionId ? traceHash(sessionId) : null,
221
+ };
222
+ }
223
+
224
+ function normalizeXaiReasoningEffort(value) {
225
+ const effort = String(value || '').trim().toLowerCase();
226
+ return ['none', 'low', 'medium', 'high'].includes(effort) ? effort : null;
227
+ }
228
+
229
+ function opencodeGoReasoningEffortValues(modelInfo) {
230
+ const effort = (modelInfo?.reasoningOptions || []).find((option) => option?.type === 'effort');
231
+ return Array.isArray(effort?.values)
232
+ ? effort.values.map((item) => String(item || '').trim().toLowerCase()).filter(Boolean)
233
+ : [];
234
+ }
235
+
236
+ function normalizeOpencodeGoReasoningEffort(value, modelInfo) {
237
+ const allowed = opencodeGoReasoningEffortValues(modelInfo);
238
+ if (!allowed.length) return null;
239
+ const effort = String(value || '').trim().toLowerCase();
240
+ if (allowed.includes(effort)) return effort;
241
+ if ((effort === 'max' || effort === 'xhigh') && allowed.includes('max')) return 'max';
242
+ if (['high', 'medium', 'low'].includes(effort) && allowed.includes('high')) return 'high';
243
+ return null;
244
+ }
245
+
246
+ function useXaiResponsesApi(opts, config) {
247
+ const raw = opts?.xaiApiMode
248
+ ?? config?.apiMode
249
+ ?? config?.xaiApiMode
250
+ ?? process.env.MIXDOG_XAI_API_MODE
251
+ ?? process.env.MIXDOG_XAI_RESPONSES;
252
+ if (raw == null || raw === '') return true;
253
+ const mode = String(raw).trim().toLowerCase();
254
+ return !['0', 'false', 'off', 'chat', 'chat-completions', 'chat_completions'].includes(mode);
255
+ }
256
+
257
+ function useXaiResponsesWebSocket(opts, config) {
258
+ const raw = opts?.xaiResponsesTransport
259
+ ?? opts?.xaiTransport
260
+ ?? config?.responsesTransport
261
+ ?? config?.transport
262
+ ?? process.env.MIXDOG_XAI_RESPONSES_TRANSPORT
263
+ ?? process.env.MIXDOG_XAI_TRANSPORT;
264
+ if (raw == null || raw === '') return true;
265
+ const transport = String(raw).trim().toLowerCase();
266
+ return !['0', 'false', 'off', 'http', 'https', 'responses-http', 'sdk'].includes(transport);
267
+ }
268
+
269
+ function useXaiResponsesWebSocketWarmup(opts, config, { previousResponseId, instructions, rawTools }) {
270
+ if (previousResponseId) return false;
271
+ const raw = opts?.xaiResponsesWarmup
272
+ ?? opts?.xaiWsWarmup
273
+ ?? config?.responsesWarmup
274
+ ?? config?.wsWarmup
275
+ ?? process.env.MIXDOG_XAI_RESPONSES_WARMUP
276
+ ?? process.env.MIXDOG_XAI_WS_WARMUP;
277
+ if (raw != null && raw !== '') {
278
+ const mode = String(raw).trim().toLowerCase();
279
+ if (['0', 'false', 'off', 'none', 'disabled'].includes(mode)) return false;
280
+ if (['1', 'true', 'on', 'always', 'force'].includes(mode)) return true;
281
+ }
282
+ return String(instructions || '').length >= 2048 || (Array.isArray(rawTools) && rawTools.length >= 10);
283
+ }
284
+
285
+ // Match OpenAI/Codex cache-lane semantics: default to 12 stable shards (via
286
+ // resolveProviderPromptCacheLane) and serialize each final shard. This gives
287
+ // Grok/xAI 10+ worker fanout without concurrent same-key cache contention.
288
+ const XAI_RESPONSES_CACHE_LANE_DEFAULT_MAX_IN_FLIGHT = 1;
289
+ const xaiResponsesCacheLanes = new Map();
290
+
291
+ function parseXaiPositiveInt(value, fallback) {
292
+ if (value == null || value === '') return fallback;
293
+ const text = String(value).trim().toLowerCase();
294
+ if (['0', 'false', 'off', 'none', 'disabled', 'unlimited', 'unbounded', 'auto'].includes(text)) return 0;
295
+ const n = Number(text);
296
+ if (!Number.isFinite(n)) return fallback;
297
+ return Math.max(0, Math.floor(n));
298
+ }
299
+
300
+ function xaiResponsesCacheLaneMaxInFlight(opts, config) {
301
+ return parseXaiPositiveInt(
302
+ opts?.xaiCacheMaxInFlight
303
+ ?? opts?.xaiResponsesCacheMaxInFlight
304
+ ?? opts?.grokCacheMaxInFlight
305
+ ?? opts?.grokResponsesCacheMaxInFlight
306
+ ?? config?.xaiCacheMaxInFlight
307
+ ?? config?.xaiResponsesCacheMaxInFlight
308
+ ?? config?.grokCacheMaxInFlight
309
+ ?? config?.grokResponsesCacheMaxInFlight
310
+ ?? process.env.MIXDOG_XAI_CACHE_MAX_INFLIGHT
311
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_MAX_INFLIGHT
312
+ ?? process.env.MIXDOG_GROK_CACHE_MAX_INFLIGHT
313
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_MAX_INFLIGHT
314
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_MAX_INFLIGHT
315
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_MAX_INFLIGHT,
316
+ XAI_RESPONSES_CACHE_LANE_DEFAULT_MAX_IN_FLIGHT,
317
+ );
318
+ }
319
+
320
+ function xaiResponsesCacheLaneQueueTimeoutMs(opts, config) {
321
+ return parseXaiPositiveInt(
322
+ opts?.xaiCacheQueueTimeoutMs
323
+ ?? opts?.xaiResponsesCacheQueueTimeoutMs
324
+ ?? opts?.grokCacheQueueTimeoutMs
325
+ ?? opts?.grokResponsesCacheQueueTimeoutMs
326
+ ?? config?.xaiCacheQueueTimeoutMs
327
+ ?? config?.xaiResponsesCacheQueueTimeoutMs
328
+ ?? config?.grokCacheQueueTimeoutMs
329
+ ?? config?.grokResponsesCacheQueueTimeoutMs
330
+ ?? process.env.MIXDOG_XAI_CACHE_QUEUE_TIMEOUT_MS
331
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_QUEUE_TIMEOUT_MS
332
+ ?? process.env.MIXDOG_GROK_CACHE_QUEUE_TIMEOUT_MS
333
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_QUEUE_TIMEOUT_MS
334
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_QUEUE_TIMEOUT_MS
335
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_QUEUE_TIMEOUT_MS,
336
+ 0,
337
+ );
338
+ }
339
+
340
+ function xaiResponsesPromptCacheLane(opts, config, cacheRouting) {
341
+ const shardOverride =
342
+ opts?.xaiCacheLaneShards
343
+ ?? opts?.xaiResponsesCacheLaneShards
344
+ ?? opts?.xaiCacheMaxParallel
345
+ ?? opts?.xaiResponsesCacheMaxParallel
346
+ ?? opts?.grokCacheLaneShards
347
+ ?? opts?.grokResponsesCacheLaneShards
348
+ ?? opts?.grokCacheMaxParallel
349
+ ?? opts?.grokResponsesCacheMaxParallel
350
+ ?? config?.xaiCacheLaneShards
351
+ ?? config?.xaiResponsesCacheLaneShards
352
+ ?? config?.xaiCacheMaxParallel
353
+ ?? config?.xaiResponsesCacheMaxParallel
354
+ ?? config?.grokCacheLaneShards
355
+ ?? config?.grokResponsesCacheLaneShards
356
+ ?? config?.grokCacheMaxParallel
357
+ ?? config?.grokResponsesCacheMaxParallel
358
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_MAX_PARALLEL
359
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_LANE_SHARDS
360
+ ?? process.env.MIXDOG_GROK_CACHE_MAX_PARALLEL
361
+ ?? process.env.MIXDOG_GROK_CACHE_LANE_SHARDS
362
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_MAX_PARALLEL
363
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_LANE_SHARDS
364
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_MAX_PARALLEL
365
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_LANE_SHARDS
366
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_MAX_PARALLEL
367
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_LANE_SHARDS;
368
+ const autoOverride =
369
+ opts?.xaiCacheLaneAuto
370
+ ?? opts?.xaiResponsesCacheLaneAuto
371
+ ?? opts?.grokCacheLaneAuto
372
+ ?? opts?.grokResponsesCacheLaneAuto
373
+ ?? config?.xaiCacheLaneAuto
374
+ ?? config?.xaiResponsesCacheLaneAuto
375
+ ?? config?.grokCacheLaneAuto
376
+ ?? config?.grokResponsesCacheLaneAuto
377
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_LANE_AUTO
378
+ ?? process.env.MIXDOG_GROK_CACHE_LANE_AUTO
379
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_LANE_AUTO
380
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_LANE_AUTO
381
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_LANE_AUTO;
382
+ const slotOverride =
383
+ opts?.xaiCacheLaneSlot
384
+ ?? opts?.xaiResponsesCacheLaneSlot
385
+ ?? opts?.grokCacheLaneSlot
386
+ ?? opts?.grokResponsesCacheLaneSlot;
387
+ const seed = String(
388
+ opts?.xaiCacheLaneSeed
389
+ ?? opts?.xaiResponsesCacheLaneSeed
390
+ ?? opts?.grokCacheLaneSeed
391
+ ?? opts?.grokResponsesCacheLaneSeed
392
+ ?? opts?.promptCacheLaneSeed
393
+ ?? opts?.sessionId
394
+ ?? opts?.session?.id
395
+ ?? cacheRouting?.ownerSessionHash
396
+ ?? cacheRouting?.key
397
+ ?? '',
398
+ );
399
+ return resolveProviderPromptCacheLane('xai', {
400
+ ...opts,
401
+ ...(shardOverride !== undefined ? { promptCacheLaneShards: shardOverride } : {}),
402
+ ...(autoOverride !== undefined ? { promptCacheLaneAuto: autoOverride } : {}),
403
+ ...(slotOverride !== undefined ? { promptCacheLaneSlot: slotOverride } : {}),
404
+ promptCacheLaneSeed: seed || 'xai-cache-lane',
405
+ }, config);
406
+ }
407
+
408
+ function xaiResponsesCacheLaneKey({ model, cacheRouting, opts, config }) {
409
+ const prefix = cacheRouting?.prefixHash || cacheRouting?.seedHash || cacheRouting?.key || 'unknown-prefix';
410
+ const lane = xaiResponsesPromptCacheLane(opts, config, cacheRouting);
411
+ const shard = Number.isFinite(Number(lane?.slot)) ? Number(lane.slot) : 0;
412
+ return {
413
+ key: `xai-responses:${model || 'default'}:${prefix}:shard-${shard}`,
414
+ shard,
415
+ lane,
416
+ };
417
+ }
418
+
419
+ function getXaiResponsesCacheLaneState(key, maxInFlight) {
420
+ let state = xaiResponsesCacheLanes.get(key);
421
+ if (!state) {
422
+ state = { key, active: 0, queue: [], maxInFlight, nextId: 0 };
423
+ xaiResponsesCacheLanes.set(key, state);
424
+ }
425
+ state.maxInFlight = maxInFlight;
426
+ return state;
427
+ }
428
+
429
+ function cleanupXaiResponsesCacheLane(state) {
430
+ if (state.active === 0 && state.queue.length === 0) {
431
+ xaiResponsesCacheLanes.delete(state.key);
432
+ }
433
+ }
434
+
435
+ function removeQueuedXaiCacheLaneRequest(state, request) {
436
+ const index = state.queue.indexOf(request);
437
+ if (index >= 0) state.queue.splice(index, 1);
438
+ cleanupXaiResponsesCacheLane(state);
439
+ }
440
+
441
+ function makeXaiCacheLaneHandle(state, requestId, enqueuedAt) {
442
+ let released = false;
443
+ return {
444
+ requestId,
445
+ waitedMs: Date.now() - enqueuedAt,
446
+ activeCount: state.active,
447
+ queueDepth: state.queue.length,
448
+ release() {
449
+ if (released) return;
450
+ released = true;
451
+ releaseXaiResponsesCacheLane(state);
452
+ },
453
+ };
454
+ }
455
+
456
+ function releaseXaiResponsesCacheLane(state) {
457
+ state.active = Math.max(0, state.active - 1);
458
+ while (state.queue.length > 0 && state.active < state.maxInFlight) {
459
+ const next = state.queue.shift();
460
+ next.cleanup?.();
461
+ state.active += 1;
462
+ next.resolve(makeXaiCacheLaneHandle(state, next.requestId, next.enqueuedAt));
463
+ }
464
+ cleanupXaiResponsesCacheLane(state);
465
+ }
466
+
467
+ function acquireXaiResponsesCacheLane({ key, maxInFlight, signal, timeoutMs }) {
468
+ const state = getXaiResponsesCacheLaneState(key, maxInFlight);
469
+ const requestId = ++state.nextId;
470
+ const enqueuedAt = Date.now();
471
+ if (state.active < state.maxInFlight) {
472
+ state.active += 1;
473
+ return Promise.resolve(makeXaiCacheLaneHandle(state, requestId, enqueuedAt));
474
+ }
475
+ return new Promise((resolve, reject) => {
476
+ const request = {
477
+ requestId,
478
+ enqueuedAt,
479
+ resolve,
480
+ reject,
481
+ cleanup: null,
482
+ };
483
+ const cleanup = () => {
484
+ if (request.timer) clearTimeout(request.timer);
485
+ if (signal && request.abortListener) signal.removeEventListener('abort', request.abortListener);
486
+ };
487
+ request.cleanup = cleanup;
488
+ request.abortListener = () => {
489
+ cleanup();
490
+ removeQueuedXaiCacheLaneRequest(state, request);
491
+ const reason = signal?.reason;
492
+ reject(reason instanceof Error ? reason : new Error('xAI cache lane wait aborted'));
493
+ };
494
+ if (signal?.aborted) {
495
+ request.abortListener();
496
+ return;
497
+ }
498
+ if (signal) signal.addEventListener('abort', request.abortListener, { once: true });
499
+ if (timeoutMs > 0) {
500
+ request.timer = setTimeout(() => {
501
+ cleanup();
502
+ removeQueuedXaiCacheLaneRequest(state, request);
503
+ reject(new Error(`xAI cache lane wait timed out after ${timeoutMs}ms`));
504
+ }, timeoutMs);
505
+ request.timer.unref?.();
506
+ }
507
+ state.queue.push(request);
508
+ });
509
+ }
510
+
511
+ function traceXaiCacheLane(opts, payload) {
512
+ if (!compatCacheTraceEnabled('xai')) return;
513
+ try {
514
+ appendBridgeTrace({
515
+ sessionId: opts?.sessionId || opts?.session?.id || null,
516
+ iteration: Number.isFinite(Number(opts?.iteration)) ? Number(opts.iteration) : null,
517
+ kind: 'cache_lane',
518
+ ...payload,
519
+ payload,
520
+ });
521
+ } catch {}
522
+ }
523
+
524
+ async function withXaiResponsesCacheLane({ opts, config, cacheRouting, model, transport, previousResponseId, inputCount, signal }, fn) {
525
+ const maxInFlight = xaiResponsesCacheLaneMaxInFlight(opts, config);
526
+ if (maxInFlight <= 0) {
527
+ const laneMeta = { enabled: false, maxInFlight: 0 };
528
+ return { value: await fn(laneMeta), laneMeta };
529
+ }
530
+ const { key: laneKey, shard, lane } = xaiResponsesCacheLaneKey({ model, cacheRouting, opts, config });
531
+ const timeoutMs = xaiResponsesCacheLaneQueueTimeoutMs(opts, config);
532
+ const state = getXaiResponsesCacheLaneState(laneKey, maxInFlight);
533
+ const queued = state.active >= state.maxInFlight;
534
+ if (queued) {
535
+ traceXaiCacheLane(opts, {
536
+ provider: 'xai',
537
+ api: 'responses',
538
+ transport,
539
+ event: 'queued',
540
+ lane_key_hash: traceHash(laneKey),
541
+ lane_shard: shard,
542
+ lane_shards: Number.isFinite(Number(lane?.shards)) ? Number(lane.shards) : null,
543
+ lane_auto: lane?.auto === true,
544
+ lane_seed_hash: lane?.seedHash || null,
545
+ max_in_flight: maxInFlight,
546
+ active: state.active,
547
+ queue_depth: state.queue.length,
548
+ previous_response_used: !!previousResponseId,
549
+ input_count: inputCount,
550
+ });
551
+ }
552
+ const handle = await acquireXaiResponsesCacheLane({ key: laneKey, maxInFlight, signal, timeoutMs });
553
+ const laneMeta = {
554
+ enabled: true,
555
+ laneKeyHash: traceHash(laneKey),
556
+ shard,
557
+ shards: Number.isFinite(Number(lane?.shards)) ? Number(lane.shards) : null,
558
+ auto: lane?.auto === true,
559
+ seedHash: lane?.seedHash || null,
560
+ maxInFlight,
561
+ queued,
562
+ waitMs: handle.waitedMs,
563
+ activeAfterAcquire: handle.activeCount,
564
+ queueDepthAfterAcquire: handle.queueDepth,
565
+ };
566
+ traceXaiCacheLane(opts, {
567
+ provider: 'xai',
568
+ api: 'responses',
569
+ transport,
570
+ event: 'acquired',
571
+ lane_key_hash: laneMeta.laneKeyHash,
572
+ lane_shard: shard,
573
+ lane_shards: laneMeta.shards,
574
+ lane_auto: laneMeta.auto,
575
+ lane_seed_hash: laneMeta.seedHash,
576
+ max_in_flight: maxInFlight,
577
+ wait_ms: laneMeta.waitMs,
578
+ active: laneMeta.activeAfterAcquire,
579
+ queue_depth: laneMeta.queueDepthAfterAcquire,
580
+ previous_response_used: !!previousResponseId,
581
+ input_count: inputCount,
582
+ });
583
+ const startedAt = Date.now();
584
+ try {
585
+ return { value: await fn(laneMeta), laneMeta };
586
+ } finally {
587
+ handle.release();
588
+ traceXaiCacheLane(opts, {
589
+ provider: 'xai',
590
+ api: 'responses',
591
+ transport,
592
+ event: 'released',
593
+ lane_key_hash: laneMeta.laneKeyHash,
594
+ lane_shard: shard,
595
+ lane_shards: laneMeta.shards,
596
+ lane_auto: laneMeta.auto,
597
+ lane_seed_hash: laneMeta.seedHash,
598
+ max_in_flight: maxInFlight,
599
+ held_ms: Date.now() - startedAt,
600
+ previous_response_used: !!previousResponseId,
601
+ input_count: inputCount,
602
+ });
603
+ }
604
+ }
605
+
606
+ function deterministicUuidFromKey(key) {
607
+ const hex = createHash('sha256').update(String(key ?? '')).digest('hex');
608
+ const variant = ((Number.parseInt(hex[16], 16) & 0x3) | 0x8).toString(16);
609
+ return [
610
+ hex.slice(0, 8),
611
+ hex.slice(8, 12),
612
+ '4' + hex.slice(13, 16),
613
+ variant + hex.slice(17, 20),
614
+ hex.slice(20, 32),
615
+ ].join('-');
616
+ }
617
+
618
+ function compatCacheTraceEnabled(provider) {
619
+ return process.env.MIXDOG_COMPAT_CACHE_TRACE === '1'
620
+ || process.env.MIXDOG_PROVIDER_CACHE_TRACE === '1'
621
+ || (provider === 'xai' && process.env.MIXDOG_XAI_CACHE_TRACE === '1');
622
+ }
623
+
624
+ function writeCompatCacheTrace({ provider, model, opts, params, rawTools, response, cacheRoutingKey, cacheRouting }) {
625
+ if (!compatCacheTraceEnabled(provider)) return;
626
+ try {
627
+ const usage = response?.usage || {};
628
+ const inputTokens = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0);
629
+ const cachedTokens = extractCompatCachedTokens(usage);
630
+ const toolShape = summarizeTraceTools(rawTools);
631
+ const traceMessages = Array.isArray(params?.messages) ? params.messages : [];
632
+ const trace = {
633
+ event: 'chat.completions',
634
+ provider,
635
+ model,
636
+ responseModel: response?.model || null,
637
+ owner: opts?.session?.owner || null,
638
+ role: opts?.session?.role || opts?.role || null,
639
+ permission: opts?.session?.permission || null,
640
+ toolPermission: opts?.session?.toolPermission || null,
641
+ profileId: opts?.session?.profileId || null,
642
+ sourceType: opts?.session?.sourceType || null,
643
+ sourceName: opts?.session?.sourceName || null,
644
+ sessionIdHash: opts?.sessionId ? traceHash(opts.sessionId) : null,
645
+ providerCacheKeyHash: opts?.providerCacheKey ? traceHash(opts.providerCacheKey) : null,
646
+ promptCacheKeyHash: opts?.promptCacheKey ? traceHash(opts.promptCacheKey) : null,
647
+ xGrokConvIdHash: provider === 'xai' && cacheRoutingKey ? traceHash(cacheRoutingKey) : null,
648
+ xGrokConvIdSeedHash: provider === 'xai' ? cacheRouting?.seedHash || null : null,
649
+ xGrokPromptPrefixHash: provider === 'xai' ? cacheRouting?.prefixHash || null : null,
650
+ xGrokConvIdMode: provider === 'xai' ? cacheRouting?.mode || null : null,
651
+ xGrokConvIdLaneIndex: provider === 'xai' ? cacheRouting?.laneIndex ?? null : null,
652
+ xGrokConvIdActiveLanes: provider === 'xai' ? cacheRouting?.activeLanes ?? null : null,
653
+ xGrokConvIdIdleLanes: provider === 'xai' ? cacheRouting?.idleLanes ?? null : null,
654
+ xGrokConvIdOwnerSessionHash: provider === 'xai' ? cacheRouting?.ownerSessionHash || null : null,
655
+ xaiReasoningEffort: provider === 'xai' ? params?.reasoning_effort || null : null,
656
+ messageCount: traceMessages.length,
657
+ messageFullHash: traceHash(stableTraceStringify(traceMessages)),
658
+ messagePrefixHash: traceHash(stableTraceStringify(traceMessages.slice(0, -1))),
659
+ lastMessageHash: traceMessages.length ? traceHash(stableTraceStringify(traceMessages.at(-1))) : null,
660
+ messages: summarizeTraceMessages(traceMessages),
661
+ toolCount: Array.isArray(rawTools) ? rawTools.length : 0,
662
+ toolSchemaHash: traceHash(stableTraceStringify(toolShape)),
663
+ usageKeys: Object.keys(usage || {}).sort(),
664
+ promptTokenDetailsKeys: Object.keys(usage?.prompt_tokens_details || {}).sort(),
665
+ inputTokenDetailsKeys: Object.keys(usage?.input_tokens_details || {}).sort(),
666
+ choiceMessageKeys: Object.keys(response?.choices?.[0]?.message || {}).sort(),
667
+ responseReasoningContent: typeof response?.choices?.[0]?.message?.reasoning_content === 'string'
668
+ ? traceTextShape(response.choices[0].message.reasoning_content)
669
+ : null,
670
+ responseReasoningTokens: Number(usage?.completion_tokens_details?.reasoning_tokens ?? 0),
671
+ inputTokens,
672
+ outputTokens: Number(usage.completion_tokens ?? usage.output_tokens ?? 0),
673
+ cachedTokens,
674
+ cacheHitRate: inputTokens > 0 ? Number((cachedTokens / inputTokens).toFixed(6)) : null,
675
+ costInUsdTicks: typeof usage.cost_in_usd_ticks === 'number' ? usage.cost_in_usd_ticks : null,
676
+ };
677
+ process.stderr.write(`[compat-cache-trace] ${JSON.stringify(trace)}\n`);
678
+ } catch (err) {
679
+ process.stderr.write(`[compat-cache-trace] failed: ${err?.message || err}\n`);
680
+ }
681
+ }
682
+
683
+ function summarizeResponsesInput(input) {
684
+ return (input || []).map((item, index) => ({
685
+ index,
686
+ type: item?.type || null,
687
+ role: item?.role || null,
688
+ callIdHash: item?.call_id ? traceHash(item.call_id) : null,
689
+ name: item?.name || null,
690
+ content: typeof item?.content === 'string'
691
+ ? { type: 'text', ...traceTextShape(item.content) }
692
+ : { type: item?.content == null ? 'null' : typeof item.content, hash: traceHash(stableTraceStringify(item?.content ?? null)) },
693
+ output: typeof item?.output === 'string' ? traceTextShape(item.output) : null,
694
+ }));
695
+ }
696
+
697
+ function xaiUsageStats(usage) {
698
+ const inputTokens = Number(usage?.input_tokens ?? usage?.prompt_tokens ?? 0);
699
+ const outputTokens = Number(usage?.output_tokens ?? usage?.completion_tokens ?? 0);
700
+ const cachedTokens = extractCompatCachedTokens(usage);
701
+ const hitRate = inputTokens > 0 ? Number((cachedTokens / inputTokens).toFixed(6)) : null;
702
+ return { inputTokens, outputTokens, cachedTokens, hitRate };
703
+ }
704
+
705
+ function xaiSanitizedRequestSansInput(params) {
706
+ const { input: _input, ...rest } = params || {};
707
+ const out = { ...rest };
708
+ if (out.prompt_cache_key) out.prompt_cache_key = traceHash(out.prompt_cache_key);
709
+ if (out.previous_response_id) out.previous_response_id = traceHash(out.previous_response_id);
710
+ if (typeof out.instructions === 'string') out.instructions = traceHash(out.instructions);
711
+ return out;
712
+ }
713
+
714
+ function xaiResponsesFingerprintPayload({ model, opts, params, rawTools, response, cacheRouting, previousResponseId, inputStartIndex, continuationResetReason, transport, cacheLane }) {
715
+ const usage = response?.usage || {};
716
+ const { inputTokens, outputTokens, cachedTokens, hitRate } = xaiUsageStats(usage);
717
+ const toolShape = summarizeTraceTools(rawTools);
718
+ const instructions = typeof params?.instructions === 'string' ? params.instructions : '';
719
+ const requestSansInput = xaiSanitizedRequestSansInput(params);
720
+ const contextShape = {
721
+ provider: 'xai',
722
+ api: 'responses',
723
+ model: model || null,
724
+ promptCacheKeyHash: params?.prompt_cache_key ? traceHash(params.prompt_cache_key) : null,
725
+ instructions,
726
+ tools: toolShape,
727
+ reasoning: params?.reasoning || null,
728
+ store: params?.store ?? null,
729
+ };
730
+ const previousResponseUsed = Boolean(previousResponseId);
731
+ const midTurnCold = previousResponseUsed
732
+ && inputTokens >= 1024
733
+ && (cachedTokens <= 512 || (hitRate != null && hitRate < 0.1));
734
+ return {
735
+ provider: 'xai',
736
+ api: 'responses',
737
+ transport: transport || null,
738
+ model: model || null,
739
+ response_model: response?.model || null,
740
+ session_id_hash: opts?.sessionId ? traceHash(opts.sessionId) : null,
741
+ provider_cache_key_hash: opts?.providerCacheKey ? traceHash(opts.providerCacheKey) : null,
742
+ prompt_cache_key_option_hash: opts?.promptCacheKey ? traceHash(opts.promptCacheKey) : null,
743
+ prompt_cache_key_hash: params?.prompt_cache_key ? traceHash(params.prompt_cache_key) : null,
744
+ xai_prompt_prefix_hash: cacheRouting?.prefixHash || null,
745
+ xai_cache_mode: cacheRouting?.mode || null,
746
+ xai_cache_seed_hash: cacheRouting?.seedHash || null,
747
+ owner_session_hash: cacheRouting?.ownerSessionHash || null,
748
+ response_id_hash: response?.id ? traceHash(response.id) : null,
749
+ previous_response_id_hash: previousResponseId ? traceHash(previousResponseId) : null,
750
+ previous_response_used: previousResponseUsed,
751
+ continuation_reset_reason: continuationResetReason || null,
752
+ input_start_index: inputStartIndex,
753
+ input_count: Array.isArray(params?.input) ? params.input.length : 0,
754
+ input_hash: traceHash(stableTraceStringify(params?.input || [])),
755
+ request_sans_input_hash: traceHash(stableTraceStringify(requestSansInput)),
756
+ context_prefix_hash: traceHash(stableTraceStringify(contextShape)),
757
+ has_instructions: instructions.length > 0,
758
+ instructions_chars: instructions.length,
759
+ instructions_hash: instructions ? traceHash(instructions) : null,
760
+ reasoning_effort: params?.reasoning?.effort || null,
761
+ tool_count: Array.isArray(rawTools) ? rawTools.length : 0,
762
+ tool_schema_hash: traceHash(stableTraceStringify(toolShape)),
763
+ tool_names_hash: traceHash(stableTraceStringify(toolShape.map(t => t?.name || null))),
764
+ xai_cache_lane_enabled: cacheLane?.enabled === true,
765
+ xai_cache_lane_hash: cacheLane?.laneKeyHash || null,
766
+ xai_cache_lane_shard: Number.isFinite(Number(cacheLane?.shard)) ? Number(cacheLane.shard) : null,
767
+ xai_cache_lane_shards: Number.isFinite(Number(cacheLane?.shards)) ? Number(cacheLane.shards) : null,
768
+ xai_cache_lane_auto: cacheLane?.auto === true,
769
+ xai_cache_lane_seed_hash: cacheLane?.seedHash || null,
770
+ xai_cache_lane_max_in_flight: Number.isFinite(Number(cacheLane?.maxInFlight)) ? Number(cacheLane.maxInFlight) : null,
771
+ xai_cache_lane_wait_ms: Number.isFinite(Number(cacheLane?.waitMs)) ? Number(cacheLane.waitMs) : null,
772
+ xai_cache_lane_queued: cacheLane?.queued === true,
773
+ input_tokens: inputTokens,
774
+ output_tokens: outputTokens,
775
+ cached_tokens: cachedTokens,
776
+ cache_hit_rate: hitRate,
777
+ mid_turn_cold: midTurnCold,
778
+ };
779
+ }
780
+
781
+ function traceXaiResponsesCacheContext(args) {
782
+ if (!compatCacheTraceEnabled('xai')) return;
783
+ try {
784
+ const payload = xaiResponsesFingerprintPayload(args);
785
+ const sessionId = args?.opts?.sessionId || args?.opts?.session?.id || null;
786
+ const iteration = Number.isFinite(Number(args?.opts?.iteration)) ? Number(args.opts.iteration) : null;
787
+ appendBridgeTrace({
788
+ sessionId,
789
+ iteration,
790
+ kind: 'cache_context',
791
+ ...payload,
792
+ payload,
793
+ });
794
+ if (payload.mid_turn_cold) {
795
+ const anomalyPayload = {
796
+ ...payload,
797
+ anomaly: 'xai_mid_turn_cold_cache',
798
+ reason: 'previous_response_id_present_but_cached_tokens_low',
799
+ };
800
+ appendBridgeTrace({
801
+ sessionId,
802
+ iteration,
803
+ kind: 'cache_anomaly',
804
+ ...anomalyPayload,
805
+ payload: anomalyPayload,
806
+ });
807
+ }
808
+ } catch (err) {
809
+ process.stderr.write(`[compat-cache-trace] xai context trace failed: ${err?.message || err}\n`);
810
+ }
811
+ }
812
+
813
+ function writeXaiResponsesCacheTrace({ model, opts, params, rawTools, response, cacheRouting, previousResponseId, inputStartIndex, continuationResetReason, transport, cacheLane }) {
814
+ if (!compatCacheTraceEnabled('xai')) return;
815
+ try {
816
+ const usage = response?.usage || {};
817
+ const fingerprint = xaiResponsesFingerprintPayload({
818
+ model,
819
+ opts,
820
+ params,
821
+ rawTools,
822
+ response,
823
+ cacheRouting,
824
+ previousResponseId,
825
+ inputStartIndex,
826
+ continuationResetReason,
827
+ transport,
828
+ cacheLane,
829
+ });
830
+ const inputTokens = fingerprint.input_tokens;
831
+ const cachedTokens = fingerprint.cached_tokens;
832
+ const toolShape = summarizeTraceTools(rawTools);
833
+ const trace = {
834
+ event: 'responses',
835
+ provider: 'xai',
836
+ transport: transport || null,
837
+ model,
838
+ responseModel: response?.model || null,
839
+ responseIdHash: response?.id ? traceHash(response.id) : null,
840
+ previousResponseIdHash: previousResponseId ? traceHash(previousResponseId) : null,
841
+ owner: opts?.session?.owner || null,
842
+ role: opts?.session?.role || opts?.role || null,
843
+ permission: opts?.session?.permission || null,
844
+ toolPermission: opts?.session?.toolPermission || null,
845
+ profileId: opts?.session?.profileId || null,
846
+ sourceType: opts?.session?.sourceType || null,
847
+ sourceName: opts?.session?.sourceName || null,
848
+ sessionIdHash: opts?.sessionId ? traceHash(opts.sessionId) : null,
849
+ promptCacheKeyHash: params?.prompt_cache_key ? traceHash(params.prompt_cache_key) : null,
850
+ xGrokPromptPrefixHash: cacheRouting?.prefixHash || null,
851
+ xGrokConvIdMode: cacheRouting?.mode || null,
852
+ xaiReasoningEffort: params?.reasoning?.effort || null,
853
+ previousResponseUsed: Boolean(previousResponseId),
854
+ inputStartIndex,
855
+ inputCount: Array.isArray(params?.input) ? params.input.length : 0,
856
+ cacheLaneEnabled: fingerprint.xai_cache_lane_enabled,
857
+ cacheLaneHash: fingerprint.xai_cache_lane_hash,
858
+ cacheLaneShard: fingerprint.xai_cache_lane_shard,
859
+ cacheLaneMaxInFlight: fingerprint.xai_cache_lane_max_in_flight,
860
+ cacheLaneWaitMs: fingerprint.xai_cache_lane_wait_ms,
861
+ cacheLaneQueued: fingerprint.xai_cache_lane_queued,
862
+ input: summarizeResponsesInput(params?.input || []),
863
+ toolCount: Array.isArray(rawTools) ? rawTools.length : 0,
864
+ toolSchemaHash: traceHash(stableTraceStringify(toolShape)),
865
+ toolNamesHash: fingerprint.tool_names_hash,
866
+ requestSansInputHash: fingerprint.request_sans_input_hash,
867
+ contextPrefixHash: fingerprint.context_prefix_hash,
868
+ instructionsHash: fingerprint.instructions_hash,
869
+ instructionsChars: fingerprint.instructions_chars,
870
+ usageKeys: Object.keys(usage || {}).sort(),
871
+ inputTokenDetailsKeys: Object.keys(usage?.input_tokens_details || {}).sort(),
872
+ outputTokenDetailsKeys: Object.keys(usage?.output_tokens_details || {}).sort(),
873
+ outputTypes: (response?.output || []).map(item => item?.type || null),
874
+ inputTokens,
875
+ outputTokens: fingerprint.output_tokens,
876
+ cachedTokens,
877
+ cacheHitRate: fingerprint.cache_hit_rate,
878
+ midTurnCold: fingerprint.mid_turn_cold,
879
+ costInUsdTicks: typeof usage.cost_in_usd_ticks === 'number' ? usage.cost_in_usd_ticks : null,
880
+ };
881
+ process.stderr.write(`[compat-cache-trace] ${JSON.stringify(trace)}\n`);
882
+ } catch (err) {
883
+ process.stderr.write(`[compat-cache-trace] failed: ${err?.message || err}\n`);
884
+ }
885
+ }
886
+
887
+ function toOpenAIMessages(messages, providerName, options = {}) {
888
+ // NOTE: chat.completions has no equivalent slot for replaying reasoning
889
+ // encrypted_content the way the Responses API does (no `type:'reasoning'`
890
+ // input item). Whatever reasoningItems may be attached to assistant
891
+ // messages by the openai-oauth provider is intentionally dropped here —
892
+ // strict providers (xai) reject unknown roles/types and would 400 the
893
+ // request. Documented in v0.1.160 (GPT reasoning replay).
894
+ //
895
+ // DeepSeek thinking models require the prior turn's `reasoning_content`
896
+ // string to be echoed back inside the assistant message, otherwise the API
897
+ // returns 400. xAI reasoning models also preserve their official multi-turn
898
+ // shape and cache prefix stability when prior assistant reasoning_content
899
+ // is replayed; reasoning_effort itself remains caller/user-selected.
900
+ const replaysReasoningContent = options.replaysReasoningContent === true
901
+ || providerName === 'deepseek'
902
+ || providerName === 'xai';
903
+ const out = [];
904
+ const pendingToolMedia = [];
905
+ const flushToolMedia = () => {
906
+ if (!pendingToolMedia.length) return;
907
+ out.push({ role: 'user', content: pendingToolMedia.splice(0) });
908
+ };
909
+ for (const m of messages) {
910
+ if (m.role === 'tool') {
911
+ const { output, mediaContent } = splitToolContentForOpenAIChat(m.content);
912
+ out.push({
913
+ role: 'tool',
914
+ tool_call_id: m.toolCallId || '',
915
+ content: output,
916
+ });
917
+ if (mediaContent) pendingToolMedia.push(...mediaContent);
918
+ continue;
919
+ }
920
+ flushToolMedia();
921
+ if (m.role === 'assistant' && m.toolCalls?.length) {
922
+ const msg = {
923
+ role: 'assistant',
924
+ content: normalizeContentForOpenAIChat(m.content, { role: 'assistant' }) || null,
925
+ tool_calls: m.toolCalls.map((tc) => ({
926
+ id: tc.id,
927
+ type: 'function',
928
+ function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },
929
+ })),
930
+ };
931
+ if (replaysReasoningContent && m.reasoningContent) msg.reasoning_content = m.reasoningContent;
932
+ out.push(msg);
933
+ continue;
934
+ }
935
+ if (m.role === 'assistant' && replaysReasoningContent && m.reasoningContent) {
936
+ out.push({ role: m.role, content: normalizeContentForOpenAIChat(m.content, { role: 'assistant' }), reasoning_content: m.reasoningContent });
937
+ continue;
938
+ }
939
+ out.push({ role: m.role, content: normalizeContentForOpenAIChat(m.content, { role: m.role }) });
940
+ }
941
+ flushToolMedia();
942
+ return out;
943
+ }
944
+
945
+ function messagesHaveImageContent(messages) {
946
+ return (messages || []).some((m) => contentHasImage(m?.content));
947
+ }
948
+
949
+ function toOpenAITools(tools) {
950
+ return tools.map((t) => ({
951
+ type: 'function',
952
+ function: {
953
+ name: t.name,
954
+ description: t.description,
955
+ parameters: t.inputSchema,
956
+ },
957
+ }));
958
+ }
959
+ function toResponsesTools(tools) {
960
+ return tools.map((t) => ({
961
+ type: 'function',
962
+ name: t.name,
963
+ description: t.description,
964
+ parameters: t.inputSchema,
965
+ }));
966
+ }
967
+ function parseToolCalls(choice, label) {
968
+ const calls = choice.message?.tool_calls;
969
+ if (!calls?.length)
970
+ return undefined;
971
+ // finish_reason present ⇒ the turn completed; a JSON.parse failure on the
972
+ // arguments is deterministic bad JSON (permanent), not stream truncation.
973
+ const finishReason = choice.finish_reason || null;
974
+ return calls
975
+ .filter((tc) => tc.type === 'function')
976
+ .map((tc) => ({
977
+ id: tc.id,
978
+ name: tc.function.name,
979
+ arguments: parseCompletedToolCallArgumentsJson(tc.function.arguments, label, { id: tc.id, name: tc.function.name, finishReason }),
980
+ }));
981
+ }
982
+ function parseResponsesToolCalls(response, label) {
983
+ const out = [];
984
+ // A Responses tool call is only parsed off a completed/done item, so any
985
+ // malformed-JSON failure here is deterministic, not mid-stream truncation.
986
+ const finishReason = response?.status || 'completed';
987
+ for (const item of response?.output || []) {
988
+ if (item?.type !== 'function_call') continue;
989
+ out.push({
990
+ id: item.call_id || item.id,
991
+ name: item.name,
992
+ arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id || item.id, name: item.name, finishReason }),
993
+ });
994
+ }
995
+ return out.length ? out : undefined;
996
+ }
997
+ function responseOutputText(response) {
998
+ if (typeof response?.output_text === 'string') return response.output_text;
999
+ const chunks = [];
1000
+ for (const item of response?.output || []) {
1001
+ if (item?.type !== 'message' || !Array.isArray(item.content)) continue;
1002
+ for (const part of item.content) {
1003
+ if (part?.type === 'output_text' && typeof part.text === 'string') chunks.push(part.text);
1004
+ }
1005
+ }
1006
+ return chunks.join('');
1007
+ }
1008
+ function toResponsesInputMessage(m, pendingToolMedia = null) {
1009
+ if (m.role === 'tool') {
1010
+ const { output, mediaContent } = splitToolContentForOpenAIResponses(m.content);
1011
+ const item = {
1012
+ type: 'function_call_output',
1013
+ call_id: m.toolCallId || '',
1014
+ output: output,
1015
+ };
1016
+ if (mediaContent && pendingToolMedia) pendingToolMedia.push(...mediaContent);
1017
+ return item;
1018
+ }
1019
+ if (m.role === 'assistant' && Array.isArray(m.toolCalls) && m.toolCalls.length > 0) {
1020
+ const items = [];
1021
+ if (m.content) items.push({ role: 'assistant', content: normalizeContentForOpenAIResponses(m.content, { role: 'assistant' }) });
1022
+ for (const tc of m.toolCalls) {
1023
+ items.push({
1024
+ type: 'function_call',
1025
+ call_id: tc.id,
1026
+ name: tc.name,
1027
+ arguments: JSON.stringify(tc.arguments || {}),
1028
+ });
1029
+ }
1030
+ return items;
1031
+ }
1032
+ return { role: m.role, content: normalizeContentForOpenAIResponses(m.content || '', { role: m.role }) };
1033
+ }
1034
+ function xaiSystemInstructions(messages) {
1035
+ const instructions = (messages || [])
1036
+ .filter(m => m?.role === 'system')
1037
+ .map(m => String(m.content || ''))
1038
+ .filter(Boolean)
1039
+ .join('\n\n');
1040
+ return instructions || undefined;
1041
+ }
1042
+ function toXaiResponsesInput(messages, providerState, options = {}) {
1043
+ const includeSystem = options.includeSystem !== false;
1044
+ const state = providerState?.xaiResponses || null;
1045
+ let startIndex = 0;
1046
+ let resetReason = null;
1047
+ let previousResponseId = typeof state?.previousResponseId === 'string' ? state.previousResponseId : null;
1048
+ const expectedModel = options.model ? String(options.model) : '';
1049
+ const stateModel = state?.model ? String(state.model) : '';
1050
+ const seen = Number.isInteger(state?.seenMessageCount) ? state.seenMessageCount : null;
1051
+ if (previousResponseId && expectedModel && stateModel && stateModel !== expectedModel) {
1052
+ previousResponseId = null;
1053
+ resetReason = 'model_changed';
1054
+ }
1055
+ if (previousResponseId && (seen == null || seen < 0 || seen > messages.length)) {
1056
+ previousResponseId = null;
1057
+ resetReason = seen == null ? 'missing_seen_message_count' : 'seen_message_count_out_of_range';
1058
+ }
1059
+ if (previousResponseId) {
1060
+ startIndex = Math.max(0, Math.min(seen, messages.length));
1061
+ if (messages[startIndex]?.role === 'assistant') startIndex += 1;
1062
+ }
1063
+ const input = [];
1064
+ const pendingToolMedia = [];
1065
+ const flushToolMedia = () => {
1066
+ if (!pendingToolMedia.length) return;
1067
+ input.push({ role: 'user', content: pendingToolMedia.splice(0) });
1068
+ };
1069
+ for (const m of messages.slice(startIndex)) {
1070
+ if (!includeSystem && m.role === 'system') continue;
1071
+ if (m.role !== 'tool') flushToolMedia();
1072
+ const converted = toResponsesInputMessage(m, pendingToolMedia);
1073
+ if (Array.isArray(converted)) input.push(...converted);
1074
+ else input.push(converted);
1075
+ }
1076
+ flushToolMedia();
1077
+ return { input, previousResponseId, startIndex, continuationResetReason: resetReason };
1078
+ }
1079
+ export class OpenAICompatProvider {
1080
+ // Chat Completions prompt_tokens is already the total (includes cached).
1081
+ // Covers grok-oauth and all OPENAI_COMPAT_PRESETS. See registry.mjs.
1082
+ static inputExcludesCache = false;
1083
+ name;
1084
+ client;
1085
+ defaultModel;
1086
+ config;
1087
+ baseURL;
1088
+ apiKey;
1089
+ defaultHeaders;
1090
+ /** @type {Array<{id:string,contextWindow:number,provider:string}>|null} */
1091
+ _enrichedModels;
1092
+ constructor(name, config) {
1093
+ const preset = PRESETS[name];
1094
+ const baseURL = assertSafeBaseURL(config.baseURL || preset?.baseURL || 'http://localhost:8080/v1', name);
1095
+ const apiKey = config.apiKey || 'no-key';
1096
+ this.name = name;
1097
+ this.config = config;
1098
+ this.baseURL = baseURL;
1099
+ this.apiKey = apiKey;
1100
+ // Merge caller-supplied headers (config.extraHeaders) over the preset's.
1101
+ // Used e.g. by grok-oauth to inject the Grok CLI client headers for the
1102
+ // grok-build proxy. Backward-compatible: providers that pass no
1103
+ // extraHeaders behave exactly as before.
1104
+ this.defaultHeaders = { ...(preset?.extraHeaders || {}), ...(config.extraHeaders || {}) };
1105
+ this.defaultModel = preset?.defaultModel || 'default';
1106
+ this.client = new OpenAI({
1107
+ baseURL,
1108
+ apiKey,
1109
+ defaultHeaders: this.defaultHeaders,
1110
+ });
1111
+ }
1112
+ reloadApiKey() {
1113
+ try {
1114
+ const freshConfig = loadConfig();
1115
+ const cfg = freshConfig.providers?.[this.name];
1116
+ const preset = PRESETS[this.name];
1117
+ const newKey = cfg?.apiKey || this.config.apiKey;
1118
+ const baseURL = assertSafeBaseURL(cfg?.baseURL || this.config.baseURL || preset?.baseURL || 'http://localhost:8080/v1', this.name);
1119
+ if (newKey) {
1120
+ this.config = { ...(this.config || {}), ...(cfg || {}), apiKey: newKey, baseURL };
1121
+ this.baseURL = baseURL;
1122
+ this.apiKey = newKey;
1123
+ this.defaultHeaders = { ...(preset?.extraHeaders || {}), ...(this.config.extraHeaders || {}) };
1124
+ this.client = new OpenAI({
1125
+ baseURL,
1126
+ apiKey: newKey,
1127
+ defaultHeaders: this.defaultHeaders,
1128
+ });
1129
+ }
1130
+ } catch { /* best effort */ }
1131
+ }
1132
+ async send(messages, model, tools, sendOpts) {
1133
+ try {
1134
+ return await this._doSend(messages, model, tools, sendOpts);
1135
+ } catch (err) {
1136
+ if (err.message && (err.message.includes('401') || err.message.includes('403'))) {
1137
+ process.stderr.write(`[provider] Auth error, re-reading config...\n`);
1138
+ this.reloadApiKey();
1139
+ return await this._doSend(messages, model, tools, sendOpts);
1140
+ }
1141
+ throw err;
1142
+ }
1143
+ }
1144
+ async _doSend(messages, model, tools, sendOpts) {
1145
+ const useModel = model || this.defaultModel;
1146
+ const opts = sendOpts || {};
1147
+ if (this.name === 'xai' && useXaiResponsesApi(opts, this.config)) {
1148
+ if (useXaiResponsesWebSocket(opts, this.config) && !messagesHaveImageContent(messages)) {
1149
+ return await this._doSendXaiResponsesWebSocket(messages, useModel, tools, opts);
1150
+ }
1151
+ return await this._doSendXaiResponses(messages, useModel, tools, opts);
1152
+ }
1153
+ const signal = opts.signal || null;
1154
+ if (signal?.aborted) {
1155
+ const reason = signal.reason;
1156
+ throw reason instanceof Error ? reason : new Error('OpenAI-compat request aborted by session close');
1157
+ }
1158
+ const modelInfo = this.name === 'opencode-go'
1159
+ ? (this.getCachedModelInfo(useModel) || getModelMetadataSync(useModel, this.name))
1160
+ : null;
1161
+ const replaysReasoningContent = modelInfo?.reasoningContentField === 'reasoning_content';
1162
+ const params = {
1163
+ model: useModel,
1164
+ messages: toOpenAIMessages(messages, this.name, { replaysReasoningContent }),
1165
+ };
1166
+ const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
1167
+ if (maxOutputTokens) params.max_tokens = maxOutputTokens;
1168
+ if (tools?.length) {
1169
+ params.tools = toOpenAITools(tools);
1170
+ }
1171
+ if (this.name === 'xai') {
1172
+ const reasoningEffort = normalizeXaiReasoningEffort(opts.xaiReasoningEffort
1173
+ ?? opts.effort
1174
+ ?? this.config?.reasoningEffort
1175
+ ?? process.env.MIXDOG_XAI_REASONING_EFFORT);
1176
+ if (reasoningEffort) params.reasoning_effort = reasoningEffort;
1177
+ }
1178
+ if (this.name === 'opencode-go') {
1179
+ const reasoningEffort = normalizeOpencodeGoReasoningEffort(opts.effort ?? this.config?.reasoningEffort, modelInfo);
1180
+ if (reasoningEffort) {
1181
+ params.reasoning_effort = reasoningEffort;
1182
+ params.thinking = { type: 'enabled' };
1183
+ }
1184
+ }
1185
+ // Streaming (params.stream = true is always set below): no absolute
1186
+ // wall-clock cap on a healthy stream. A fixed total-lifetime timer
1187
+ // false-aborts live long-reasoning turns that are still emitting SSE
1188
+ // deltas. Mirror the OAuth passthrough pattern (anthropic-oauth) —
1189
+ // totalSignal is a pure pass-through of the external signal with no
1190
+ // timer. The stream is bounded instead by the per-attempt first-byte
1191
+ // timeout (PROVIDER_FIRST_BYTE_TIMEOUT_MS) for a wedged socket, the
1192
+ // external signal (client disconnect / replaced request), and the SSE
1193
+ // idle watchdog for a stream that goes dead mid-flight.
1194
+ const totalSignal = createPassthroughSignal(signal);
1195
+ const cacheRouting = this.name === 'xai'
1196
+ ? xaiCacheRouting(opts, params, tools || [], useModel)
1197
+ : null;
1198
+ const cacheRoutingKey = cacheRouting?.key || null;
1199
+ // Note: x-grok-conv-id is documented as a routing hint, but in our
1200
+ // measured parallel-worker traffic it caused alternating cold caches
1201
+ // (server-side per-conv shard isolation). Vercel ai-sdk and other
1202
+ // reference clients omit it entirely and rely on xAI's automatic
1203
+ // prompt-prefix caching, which holds up to 95%+ hit even across
1204
+ // parallel workers. Keep the header off by default.
1205
+ // Shared retry: deepseek / xai / other compat backends all sit behind
1206
+ // their own load balancers and emit 5xx / "overloaded" under burst
1207
+ // traffic. The withRetry wrapper preserves abort behavior via
1208
+ // mergedSignal and only retries when classifyError() says transient.
1209
+ params.stream = true;
1210
+ params.stream_options = { include_usage: true };
1211
+ let assembled;
1212
+ try {
1213
+ assembled = await withRetry(
1214
+ async ({ signal: attemptSignal }) => {
1215
+ try { opts.onStageChange?.('requesting'); } catch { /* heartbeat best-effort */ }
1216
+ const stream = await withRetry(
1217
+ ({ signal: openSignal }) => this.client.chat.completions.create(params, { signal: openSignal }),
1218
+ {
1219
+ signal: attemptSignal,
1220
+ perAttemptTimeoutMs: PROVIDER_FIRST_BYTE_TIMEOUT_MS,
1221
+ perAttemptLabel: `${this.name} first byte`,
1222
+ },
1223
+ );
1224
+ try { opts.onStageChange?.('streaming'); } catch { /* heartbeat best-effort */ }
1225
+ return consumeCompatChatCompletionStream(stream, {
1226
+ signal: attemptSignal,
1227
+ label: this.name,
1228
+ onStreamDelta: opts.onStreamDelta,
1229
+ onToolCall: opts.onToolCall,
1230
+ onTextDelta: opts.onTextDelta,
1231
+ parseToolCalls,
1232
+ });
1233
+ },
1234
+ {
1235
+ signal: totalSignal.signal,
1236
+ onRetry: ({ attempt, lastErr, delayMs, delayReason }) => {
1237
+ const delayLabel = Number.isFinite(Number(delayMs)) ? `, delay ${delayMs}ms${delayReason ? ` (${delayReason})` : ''}` : '';
1238
+ process.stderr.write(`[${this.name}] retry attempt ${attempt + 1} after ${lastErr?.message || lastErr?.code || 'transient error'}${delayLabel}\n`);
1239
+ },
1240
+ },
1241
+ );
1242
+ } finally {
1243
+ totalSignal.cleanup();
1244
+ }
1245
+ const response = assembled.response;
1246
+ const choice = response.choices[0];
1247
+ const toolCalls = assembled.toolCalls;
1248
+ // Capture finish_reason early so we can refuse to return an
1249
+ // incomplete completion as final content. OpenAI-compat backends use
1250
+ // `length` (max_tokens / model context overflow) and `content_filter`
1251
+ // (moderation cutoff) to flag responses that were terminated before
1252
+ // the model finished its turn — treating those as success silently
1253
+ // surfaces truncated text and lets the loop accept a partial answer.
1254
+ const stopReason = choice?.finish_reason || null;
1255
+ if ((stopReason === 'length' && Array.isArray(toolCalls) && toolCalls.length > 0)
1256
+ || stopReason === 'content_filter') {
1257
+ const err = Object.assign(
1258
+ new Error(`${this.name} response incomplete: finish_reason=${stopReason}`),
1259
+ {
1260
+ name: 'ProviderIncompleteError',
1261
+ code: 'PROVIDER_INCOMPLETE',
1262
+ providerIncomplete: true,
1263
+ finishReason: stopReason,
1264
+ partialContent: choice?.message?.content || '',
1265
+ partialToolCalls: toolCalls,
1266
+ model: response.model || useModel,
1267
+ responseId: response.id || null,
1268
+ rawUsage: response.usage || null,
1269
+ },
1270
+ );
1271
+ throw err;
1272
+ }
1273
+ writeCompatCacheTrace({
1274
+ provider: this.name,
1275
+ model: useModel,
1276
+ opts,
1277
+ params,
1278
+ rawTools: tools || [],
1279
+ response,
1280
+ cacheRoutingKey,
1281
+ cacheRouting,
1282
+ });
1283
+ if (response.usage) {
1284
+ const inputTokens = Number(response.usage.prompt_tokens ?? response.usage.input_tokens ?? 0);
1285
+ const cachedTokens = extractCompatCachedTokens(response.usage);
1286
+ traceBridgeUsage({
1287
+ sessionId: opts.sessionId || opts.session?.id || null,
1288
+ iteration: Number.isFinite(Number(opts.iteration)) ? Number(opts.iteration) : null,
1289
+ inputTokens,
1290
+ outputTokens: Number(response.usage.completion_tokens ?? response.usage.output_tokens ?? 0),
1291
+ cachedTokens,
1292
+ cacheWriteTokens: 0,
1293
+ promptTokens: inputTokens,
1294
+ model: response.model || useModel,
1295
+ modelDisplay: response.model || useModel,
1296
+ responseId: response.id || null,
1297
+ rawUsage: response.usage,
1298
+ provider: this.name,
1299
+ });
1300
+ }
1301
+ // Capture provider reasoning_content so loop.mjs can attach it to the
1302
+ // assistant message and echo it back next turn for providers that
1303
+ // require or benefit from that official multi-turn shape.
1304
+ const capturesReasoningContent = this.name === 'deepseek' || this.name === 'xai' || replaysReasoningContent;
1305
+ const reasoningContent = (capturesReasoningContent && typeof assembled.reasoningContent === 'string')
1306
+ ? assembled.reasoningContent
1307
+ : null;
1308
+ return {
1309
+ content: assembled.content || '',
1310
+ // Streamed chunks can omit `model`; fall back to the requested
1311
+ // model so callers never receive a null model identifier.
1312
+ model: response.model || useModel,
1313
+ toolCalls,
1314
+ stopReason,
1315
+ ...(reasoningContent ? { reasoningContent } : {}),
1316
+ usage: response.usage ? (() => {
1317
+ const input = response.usage.prompt_tokens ?? response.usage.input_tokens ?? 0;
1318
+ const cached = extractCompatCachedTokens(response.usage);
1319
+ // xAI Grok returns the actual billed amount in `cost_in_usd_ticks`
1320
+ // (1 tick = $1e-10, per docs.x.ai). Surface it as costUsd so the
1321
+ // session manager skips the catalog-rate fallback and records the
1322
+ // provider-billed value verbatim.
1323
+ const ticks = response.usage.cost_in_usd_ticks;
1324
+ const costUsd = typeof ticks === 'number' && ticks >= 0
1325
+ ? Number((ticks * 1e-10).toFixed(8))
1326
+ : undefined;
1327
+ return {
1328
+ inputTokens: input,
1329
+ outputTokens: response.usage.completion_tokens ?? response.usage.output_tokens ?? 0,
1330
+ cachedTokens: cached,
1331
+ // Chat Completions prompt_tokens is already the total prompt
1332
+ // the model ingested (cached is a subset) — alias directly.
1333
+ promptTokens: input,
1334
+ raw: { ...response.usage },
1335
+ ...(costUsd != null ? { costUsd } : {}),
1336
+ };
1337
+ })() : undefined,
1338
+ };
1339
+ }
1340
+ async _doSendXaiResponses(messages, useModel, tools, opts) {
1341
+ const signal = opts.signal || null;
1342
+ if (signal?.aborted) {
1343
+ const reason = signal.reason;
1344
+ throw reason instanceof Error ? reason : new Error('xAI Responses request aborted by session close');
1345
+ }
1346
+ const chatMessagesForTrace = toOpenAIMessages(messages, this.name);
1347
+ const cacheRouting = xaiResponsesCacheRouting(opts, { messages: chatMessagesForTrace }, tools || [], useModel);
1348
+ const { input, previousResponseId, startIndex, continuationResetReason } = toXaiResponsesInput(
1349
+ messages,
1350
+ opts.providerState,
1351
+ { model: useModel },
1352
+ );
1353
+ const params = {
1354
+ model: useModel,
1355
+ input,
1356
+ store: true,
1357
+ prompt_cache_key: cacheRouting.key,
1358
+ };
1359
+ if (previousResponseId) params.previous_response_id = previousResponseId;
1360
+ if (tools?.length) params.tools = toResponsesTools(tools);
1361
+ // SSE transport: report 'requesting' until the stream opens, then
1362
+ // per-chunk onStreamDelta feeds the bridge stall watchdog.
1363
+ try { opts.onStageChange?.('requesting'); } catch { /* heartbeat best-effort */ }
1364
+ const reasoningEffort = normalizeXaiReasoningEffort(opts.xaiReasoningEffort
1365
+ ?? opts.effort
1366
+ ?? this.config?.reasoningEffort
1367
+ ?? process.env.MIXDOG_XAI_REASONING_EFFORT);
1368
+ if (reasoningEffort) params.reasoning = { effort: reasoningEffort };
1369
+ params.stream = true;
1370
+ let response;
1371
+ let cacheLane = null;
1372
+ const scheduled = await withXaiResponsesCacheLane({
1373
+ opts,
1374
+ config: this.config,
1375
+ cacheRouting,
1376
+ model: useModel,
1377
+ transport: 'http',
1378
+ previousResponseId,
1379
+ inputCount: Array.isArray(input) ? input.length : 0,
1380
+ signal,
1381
+ }, async (laneMeta) => {
1382
+ cacheLane = laneMeta;
1383
+ // Streaming (params.stream = true above): pass-through external
1384
+ // signal with no absolute wall-clock cap — see _doSend. The stream
1385
+ // is bounded by the per-attempt first-byte timeout, the external
1386
+ // signal, and the SSE idle watchdog, never a fixed total timer that
1387
+ // would false-abort a healthy long-reasoning stream.
1388
+ const totalSignal = createPassthroughSignal(signal);
1389
+ try {
1390
+ return await withRetry(
1391
+ async ({ signal: attemptSignal }) => {
1392
+ const stream = await withRetry(
1393
+ ({ signal: openSignal }) => this.client.responses.create(params, { signal: openSignal }),
1394
+ {
1395
+ signal: attemptSignal,
1396
+ perAttemptTimeoutMs: PROVIDER_FIRST_BYTE_TIMEOUT_MS,
1397
+ perAttemptLabel: 'xai responses first byte',
1398
+ },
1399
+ );
1400
+ try { opts.onStageChange?.('streaming'); } catch { /* heartbeat best-effort */ }
1401
+ return consumeCompatResponsesStream(stream, {
1402
+ signal: attemptSignal,
1403
+ label: 'xai:responses',
1404
+ onStreamDelta: opts.onStreamDelta,
1405
+ onToolCall: opts.onToolCall,
1406
+ onTextDelta: opts.onTextDelta,
1407
+ parseResponsesToolCalls,
1408
+ responseOutputText,
1409
+ });
1410
+ },
1411
+ {
1412
+ signal: totalSignal.signal,
1413
+ onRetry: ({ attempt, lastErr, delayMs, delayReason }) => {
1414
+ const delayLabel = Number.isFinite(Number(delayMs)) ? `, delay ${delayMs}ms${delayReason ? ` (${delayReason})` : ''}` : '';
1415
+ process.stderr.write(`[xai:responses] retry attempt ${attempt + 1} after ${lastErr?.message || lastErr?.code || 'transient error'}${delayLabel}\n`);
1416
+ },
1417
+ },
1418
+ );
1419
+ } finally {
1420
+ totalSignal.cleanup();
1421
+ }
1422
+ });
1423
+ const streamed = scheduled.value;
1424
+ response = streamed.response;
1425
+ cacheLane = cacheLane || scheduled.laneMeta;
1426
+ const toolCalls = streamed.toolCalls;
1427
+ writeXaiResponsesCacheTrace({
1428
+ model: useModel,
1429
+ opts,
1430
+ params,
1431
+ rawTools: tools || [],
1432
+ response,
1433
+ cacheRouting,
1434
+ previousResponseId,
1435
+ inputStartIndex: startIndex,
1436
+ continuationResetReason,
1437
+ transport: 'http',
1438
+ cacheLane,
1439
+ });
1440
+ traceXaiResponsesCacheContext({
1441
+ model: useModel,
1442
+ opts,
1443
+ params,
1444
+ rawTools: tools || [],
1445
+ response,
1446
+ cacheRouting,
1447
+ previousResponseId,
1448
+ inputStartIndex: startIndex,
1449
+ continuationResetReason,
1450
+ transport: 'http',
1451
+ cacheLane,
1452
+ });
1453
+ if (response.usage) {
1454
+ const inputTokens = Number(response.usage.input_tokens ?? response.usage.prompt_tokens ?? 0);
1455
+ const cachedTokens = extractCompatCachedTokens(response.usage);
1456
+ traceBridgeUsage({
1457
+ sessionId: opts.sessionId || opts.session?.id || null,
1458
+ iteration: Number.isFinite(Number(opts.iteration)) ? Number(opts.iteration) : null,
1459
+ inputTokens,
1460
+ outputTokens: Number(response.usage.output_tokens ?? response.usage.completion_tokens ?? 0),
1461
+ cachedTokens,
1462
+ cacheWriteTokens: 0,
1463
+ promptTokens: inputTokens,
1464
+ model: response.model || useModel,
1465
+ modelDisplay: response.model || useModel,
1466
+ responseId: response.id || null,
1467
+ rawUsage: response.usage,
1468
+ provider: 'xai',
1469
+ });
1470
+ }
1471
+ const nextPreviousResponseId = streamed.stopReason === 'length' ? null : response.id;
1472
+ return {
1473
+ content: streamed.content,
1474
+ model: response.model || useModel,
1475
+ toolCalls,
1476
+ stopReason: streamed.stopReason || null,
1477
+ providerState: {
1478
+ ...(opts.providerState || {}),
1479
+ xaiResponses: {
1480
+ previousResponseId: nextPreviousResponseId,
1481
+ seenMessageCount: Array.isArray(messages) ? messages.length : 0,
1482
+ model: response.model || useModel,
1483
+ updatedAt: Date.now(),
1484
+ },
1485
+ },
1486
+ usage: response.usage ? (() => {
1487
+ const inputTokens = response.usage.input_tokens ?? response.usage.prompt_tokens ?? 0;
1488
+ const ticks = response.usage.cost_in_usd_ticks;
1489
+ const costUsd = typeof ticks === 'number' && ticks >= 0
1490
+ ? Number((ticks * 1e-10).toFixed(8))
1491
+ : undefined;
1492
+ return {
1493
+ inputTokens,
1494
+ outputTokens: response.usage.output_tokens ?? response.usage.completion_tokens ?? 0,
1495
+ cachedTokens: extractCompatCachedTokens(response.usage),
1496
+ promptTokens: inputTokens,
1497
+ raw: { ...response.usage },
1498
+ ...(costUsd != null ? { costUsd } : {}),
1499
+ };
1500
+ })() : undefined,
1501
+ };
1502
+ }
1503
+ async _doSendXaiResponsesWebSocket(messages, useModel, tools, opts) {
1504
+ const signal = opts.signal || null;
1505
+ if (signal?.aborted) {
1506
+ const reason = signal.reason;
1507
+ throw reason instanceof Error ? reason : new Error('xAI Responses WebSocket request aborted by session close');
1508
+ }
1509
+ const apiKey = this.config?.apiKey || process.env.XAI_API_KEY;
1510
+ if (!apiKey) throw new Error('xAI API key not configured');
1511
+ const chatMessagesForTrace = toOpenAIMessages(messages, this.name);
1512
+ const cacheRouting = xaiResponsesCacheRouting(opts, { messages: chatMessagesForTrace }, tools || [], useModel);
1513
+ const { input, previousResponseId, startIndex, continuationResetReason } = toXaiResponsesInput(
1514
+ messages,
1515
+ opts.providerState,
1516
+ { includeSystem: false, model: useModel },
1517
+ );
1518
+ const params = {
1519
+ model: useModel,
1520
+ input,
1521
+ // xAI's WebSocket continuation is documented for store=false, but
1522
+ // the public endpoint currently returns previous_response_not_found
1523
+ // in our live probes unless the chain is stored.
1524
+ store: true,
1525
+ prompt_cache_key: cacheRouting.key,
1526
+ };
1527
+ const instructions = xaiSystemInstructions(messages);
1528
+ if (previousResponseId) params.previous_response_id = previousResponseId;
1529
+ // xAI rejects instructions together with previous_response_id; the
1530
+ // first response already anchors instructions for the continuation.
1531
+ else if (instructions) params.instructions = instructions;
1532
+ if (tools?.length) params.tools = toResponsesTools(tools);
1533
+ const reasoningEffort = normalizeXaiReasoningEffort(opts.xaiReasoningEffort
1534
+ ?? opts.effort
1535
+ ?? this.config?.reasoningEffort
1536
+ ?? process.env.MIXDOG_XAI_REASONING_EFFORT);
1537
+ if (reasoningEffort) params.reasoning = { effort: reasoningEffort };
1538
+ const warmupBody = useXaiResponsesWebSocketWarmup(opts, this.config, {
1539
+ previousResponseId,
1540
+ instructions,
1541
+ rawTools: tools || [],
1542
+ })
1543
+ ? { ...params, generate: false, input: [] }
1544
+ : null;
1545
+ const iteration = Number.isFinite(Number(opts.iteration)) ? Number(opts.iteration) : null;
1546
+ let cacheLane = null;
1547
+ const scheduled = await withXaiResponsesCacheLane({
1548
+ opts,
1549
+ config: this.config,
1550
+ cacheRouting,
1551
+ model: useModel,
1552
+ transport: 'websocket',
1553
+ previousResponseId,
1554
+ inputCount: Array.isArray(input) ? input.length : 0,
1555
+ signal,
1556
+ }, async (laneMeta) => {
1557
+ cacheLane = laneMeta;
1558
+ return await sendViaWebSocket({
1559
+ auth: { type: 'xai', apiKey },
1560
+ body: params,
1561
+ sendOpts: opts,
1562
+ onStreamDelta: typeof opts.onStreamDelta === 'function' ? opts.onStreamDelta : null,
1563
+ onToolCall: typeof opts.onToolCall === 'function' ? opts.onToolCall : null,
1564
+ onTextDelta: typeof opts.onTextDelta === 'function' ? opts.onTextDelta : null,
1565
+ onStageChange: typeof opts.onStageChange === 'function' ? opts.onStageChange : null,
1566
+ externalSignal: signal,
1567
+ poolKey: opts.sessionId || opts.session?.id || null,
1568
+ cacheKey: cacheRouting.key,
1569
+ iteration,
1570
+ useModel,
1571
+ displayModel: (id) => id,
1572
+ includeResponseId: true,
1573
+ traceProvider: 'xai',
1574
+ logSuppressedReasoningDeltas: false,
1575
+ warmupBody,
1576
+ });
1577
+ });
1578
+ const result = scheduled.value;
1579
+ cacheLane = cacheLane || scheduled.laneMeta;
1580
+ const responseId = result.responseId || previousResponseId || null;
1581
+ const nextPreviousResponseId = result.stopReason === 'length' ? null : responseId;
1582
+ const rawUsage = result.usage?.raw || result.usage || null;
1583
+ const traceParams = result.__warmup?.requestBody || params;
1584
+ writeXaiResponsesCacheTrace({
1585
+ model: useModel,
1586
+ opts,
1587
+ params: traceParams,
1588
+ rawTools: tools || [],
1589
+ response: {
1590
+ id: responseId,
1591
+ model: result.model || useModel,
1592
+ output: [],
1593
+ usage: rawUsage,
1594
+ },
1595
+ cacheRouting,
1596
+ previousResponseId,
1597
+ inputStartIndex: startIndex,
1598
+ continuationResetReason,
1599
+ transport: 'websocket',
1600
+ cacheLane,
1601
+ });
1602
+ traceXaiResponsesCacheContext({
1603
+ model: useModel,
1604
+ opts,
1605
+ params: traceParams,
1606
+ rawTools: tools || [],
1607
+ response: {
1608
+ id: responseId,
1609
+ model: result.model || useModel,
1610
+ output: [],
1611
+ usage: rawUsage,
1612
+ },
1613
+ cacheRouting,
1614
+ previousResponseId,
1615
+ inputStartIndex: startIndex,
1616
+ continuationResetReason,
1617
+ transport: 'websocket',
1618
+ cacheLane,
1619
+ });
1620
+ const ticks = rawUsage?.cost_in_usd_ticks;
1621
+ const costUsd = typeof ticks === 'number' && ticks >= 0
1622
+ ? Number((ticks * 1e-10).toFixed(8))
1623
+ : undefined;
1624
+ return {
1625
+ content: result.content || '',
1626
+ model: result.model || useModel,
1627
+ toolCalls: result.toolCalls,
1628
+ stopReason: result.stopReason || null,
1629
+ providerState: {
1630
+ ...(opts.providerState || {}),
1631
+ xaiResponses: {
1632
+ previousResponseId: nextPreviousResponseId,
1633
+ seenMessageCount: Array.isArray(messages) ? messages.length : 0,
1634
+ model: result.model || useModel,
1635
+ updatedAt: Date.now(),
1636
+ transport: 'websocket',
1637
+ },
1638
+ },
1639
+ usage: result.usage ? {
1640
+ ...result.usage,
1641
+ ...(costUsd != null ? { costUsd } : {}),
1642
+ } : undefined,
1643
+ };
1644
+ }
1645
+ async _fetchModelItems() {
1646
+ const timeout = createTimeoutSignal(null, MODEL_LIST_TIMEOUT_MS, `${this.name} model list`);
1647
+ try {
1648
+ const res = await fetch(`${String(this.baseURL || '').replace(/\/+$/, '')}/models`, {
1649
+ method: 'GET',
1650
+ headers: {
1651
+ Authorization: `Bearer ${this.apiKey || 'no-key'}`,
1652
+ ...(this.defaultHeaders || {}),
1653
+ },
1654
+ signal: timeout.signal,
1655
+ });
1656
+ if (!res.ok) throw new Error(`${this.name} models ${res.status}`);
1657
+ const data = await res.json();
1658
+ if (Array.isArray(data?.data)) return data.data;
1659
+ if (Array.isArray(data)) return data;
1660
+ return [];
1661
+ } finally {
1662
+ timeout.cleanup();
1663
+ }
1664
+ }
1665
+ async listModels() {
1666
+ try {
1667
+ const list = await this._fetchModelItems();
1668
+ const models = [];
1669
+ for (const m of list) {
1670
+ const contextWindow = Number(
1671
+ m?.context_window
1672
+ ?? m?.max_context_window
1673
+ ?? m?.max_input_tokens
1674
+ ?? m?.max_model_len
1675
+ ?? m?.context_length
1676
+ ?? m?.contextWindow
1677
+ ?? 0,
1678
+ );
1679
+ const outputTokens = Number(
1680
+ m?.max_output_tokens
1681
+ ?? m?.output_tokens
1682
+ ?? m?.maxOutputTokens
1683
+ ?? 0,
1684
+ );
1685
+ models.push({
1686
+ id: m?.id,
1687
+ name: m?.id,
1688
+ provider: this.name,
1689
+ contextWindow: Number.isFinite(contextWindow) && contextWindow > 0 ? contextWindow : 0,
1690
+ outputTokens: Number.isFinite(outputTokens) && outputTokens > 0 ? outputTokens : null,
1691
+ created: typeof m?.created === 'number' ? m.created : null,
1692
+ });
1693
+ }
1694
+ const filtered = models.filter(m => m.id);
1695
+ const enriched = await enrichModels(filtered);
1696
+ this._enrichedModels = enriched;
1697
+ return enriched;
1698
+ }
1699
+ catch {
1700
+ return [];
1701
+ }
1702
+ }
1703
+ async isAvailable() {
1704
+ try {
1705
+ await this._fetchModelItems();
1706
+ return true;
1707
+ }
1708
+ catch {
1709
+ return false;
1710
+ }
1711
+ }
1712
+ /** @param {string} model */
1713
+ getCachedModelInfo(model) {
1714
+ if (Array.isArray(this._enrichedModels)) {
1715
+ return this._enrichedModels.find(m => m.id === model) || null;
1716
+ }
1717
+ return null;
1718
+ }
1719
+ }