mixdog 0.7.18 → 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 (844) 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/http-agent.mjs +129 -0
  179. package/src/runtime/shared/open-url.mjs +37 -0
  180. package/src/runtime/shared/plugin-paths.mjs +25 -0
  181. package/src/runtime/shared/process-shutdown.mjs +147 -0
  182. package/src/runtime/shared/schedules-store.mjs +70 -0
  183. package/src/runtime/shared/tool-execution-contract.mjs +104 -0
  184. package/src/runtime/shared/tool-surface.mjs +950 -0
  185. package/src/runtime/shared/user-cwd.mjs +221 -0
  186. package/src/runtime/shared/user-data-guard.mjs +232 -0
  187. package/src/runtime/shared/workspace-router.mjs +259 -0
  188. package/src/standalone/bridge-tool.mjs +1414 -0
  189. package/src/standalone/channel-admin.mjs +366 -0
  190. package/src/standalone/channel-worker-preload.cjs +3 -0
  191. package/src/standalone/channel-worker.mjs +353 -0
  192. package/src/standalone/explore-tool.mjs +233 -0
  193. package/src/standalone/hook-bus.mjs +246 -0
  194. package/src/standalone/plugin-admin.mjs +247 -0
  195. package/src/standalone/provider-admin.mjs +338 -0
  196. package/src/standalone/seeds.mjs +94 -0
  197. package/src/standalone/usage-dashboard.mjs +510 -0
  198. package/src/tui/App.jsx +5438 -0
  199. package/src/tui/components/AnsiText.jsx +199 -0
  200. package/src/tui/components/ContextPanel.jsx +217 -0
  201. package/src/tui/components/Markdown.jsx +205 -0
  202. package/src/tui/components/MarkdownTable.jsx +204 -0
  203. package/src/tui/components/Message.jsx +103 -0
  204. package/src/tui/components/Picker.jsx +317 -0
  205. package/src/tui/components/PromptInput.jsx +584 -0
  206. package/src/tui/components/QueuedCommands.jsx +47 -0
  207. package/src/tui/components/SlashCommandPalette.jsx +114 -0
  208. package/src/tui/components/Spinner.jsx +317 -0
  209. package/src/tui/components/StatusLine.jsx +87 -0
  210. package/src/tui/components/TextEntryPanel.jsx +323 -0
  211. package/src/tui/components/ToolExecution.jsx +772 -0
  212. package/src/tui/components/TurnDone.jsx +78 -0
  213. package/src/tui/components/UsagePanel.jsx +331 -0
  214. package/src/tui/dist/index.mjs +12359 -0
  215. package/src/tui/engine.mjs +2410 -0
  216. package/src/tui/figures.mjs +50 -0
  217. package/src/tui/hooks/useEngine.mjs +16 -0
  218. package/src/tui/index.jsx +254 -0
  219. package/src/tui/input-editing.mjs +242 -0
  220. package/src/tui/markdown/format-token.mjs +194 -0
  221. package/src/tui/paste-attachments.mjs +198 -0
  222. package/src/tui/runtime/shared/process-shutdown.mjs +1 -0
  223. package/src/tui/spinner-verbs.mjs +45 -0
  224. package/src/tui/theme.mjs +67 -0
  225. package/src/tui/time-format.mjs +53 -0
  226. package/src/ui/ansi.mjs +115 -0
  227. package/src/ui/markdown.mjs +195 -0
  228. package/src/ui/statusline.mjs +730 -0
  229. package/src/ui/tool-card.mjs +101 -0
  230. package/src/vendor/statusline/bin/statusline-lib.mjs +805 -0
  231. package/src/vendor/statusline/bin/statusline-route.mjs +596 -0
  232. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +285 -0
  233. package/src/vendor/statusline/src/gateway/claude-current.mjs +320 -0
  234. package/src/vendor/statusline/src/gateway/route-meta.mjs +753 -0
  235. package/src/vendor/statusline/src/gateway/session-routes.mjs +244 -0
  236. package/src/workflows/default/WORKFLOW.md +7 -0
  237. package/src/workflows/default/workflow.json +14 -0
  238. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  239. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  240. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  241. package/vendor/ink/build/colorize.d.ts +3 -0
  242. package/vendor/ink/build/colorize.js +48 -0
  243. package/vendor/ink/build/colorize.js.map +1 -0
  244. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  245. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  246. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  247. package/vendor/ink/build/components/AnimationContext.d.ts +9 -0
  248. package/vendor/ink/build/components/AnimationContext.js +13 -0
  249. package/vendor/ink/build/components/AnimationContext.js.map +1 -0
  250. package/vendor/ink/build/components/App.d.ts +24 -0
  251. package/vendor/ink/build/components/App.js +554 -0
  252. package/vendor/ink/build/components/App.js.map +1 -0
  253. package/vendor/ink/build/components/AppContext.d.ts +80 -0
  254. package/vendor/ink/build/components/AppContext.js +25 -0
  255. package/vendor/ink/build/components/AppContext.js.map +1 -0
  256. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  257. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  258. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  259. package/vendor/ink/build/components/Box.d.ts +130 -0
  260. package/vendor/ink/build/components/Box.js +34 -0
  261. package/vendor/ink/build/components/Box.js.map +1 -0
  262. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  263. package/vendor/ink/build/components/CursorContext.js +8 -0
  264. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  265. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  266. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  267. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  268. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  269. package/vendor/ink/build/components/ErrorOverview.js +90 -0
  270. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  271. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  272. package/vendor/ink/build/components/FocusContext.js +17 -0
  273. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  274. package/vendor/ink/build/components/Newline.d.ts +13 -0
  275. package/vendor/ink/build/components/Newline.js +8 -0
  276. package/vendor/ink/build/components/Newline.js.map +1 -0
  277. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  278. package/vendor/ink/build/components/Spacer.js +11 -0
  279. package/vendor/ink/build/components/Spacer.js.map +1 -0
  280. package/vendor/ink/build/components/Static.d.ts +24 -0
  281. package/vendor/ink/build/components/Static.js +28 -0
  282. package/vendor/ink/build/components/Static.js.map +1 -0
  283. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  284. package/vendor/ink/build/components/StderrContext.js +13 -0
  285. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  286. package/vendor/ink/build/components/StdinContext.d.ts +28 -0
  287. package/vendor/ink/build/components/StdinContext.js +20 -0
  288. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  289. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  290. package/vendor/ink/build/components/StdoutContext.js +13 -0
  291. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  292. package/vendor/ink/build/components/Text.d.ts +55 -0
  293. package/vendor/ink/build/components/Text.js +50 -0
  294. package/vendor/ink/build/components/Text.js.map +1 -0
  295. package/vendor/ink/build/components/Transform.d.ts +16 -0
  296. package/vendor/ink/build/components/Transform.js +15 -0
  297. package/vendor/ink/build/components/Transform.js.map +1 -0
  298. package/vendor/ink/build/cursor-helpers.d.ts +39 -0
  299. package/vendor/ink/build/cursor-helpers.js +62 -0
  300. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  301. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  302. package/vendor/ink/build/devtools-window-polyfill.js +68 -0
  303. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  304. package/vendor/ink/build/devtools.d.ts +1 -0
  305. package/vendor/ink/build/devtools.js +36 -0
  306. package/vendor/ink/build/devtools.js.map +1 -0
  307. package/vendor/ink/build/dom.d.ts +62 -0
  308. package/vendor/ink/build/dom.js +143 -0
  309. package/vendor/ink/build/dom.js.map +1 -0
  310. package/vendor/ink/build/get-max-width.d.ts +3 -0
  311. package/vendor/ink/build/get-max-width.js +10 -0
  312. package/vendor/ink/build/get-max-width.js.map +1 -0
  313. package/vendor/ink/build/hooks/use-animation.d.ts +49 -0
  314. package/vendor/ink/build/hooks/use-animation.js +87 -0
  315. package/vendor/ink/build/hooks/use-animation.js.map +1 -0
  316. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  317. package/vendor/ink/build/hooks/use-app.js +8 -0
  318. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  319. package/vendor/ink/build/hooks/use-box-metrics.d.ts +59 -0
  320. package/vendor/ink/build/hooks/use-box-metrics.js +81 -0
  321. package/vendor/ink/build/hooks/use-box-metrics.js.map +1 -0
  322. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  323. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  324. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  325. package/vendor/ink/build/hooks/use-focus-manager.d.ts +43 -0
  326. package/vendor/ink/build/hooks/use-focus-manager.js +18 -0
  327. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  328. package/vendor/ink/build/hooks/use-focus.d.ts +30 -0
  329. package/vendor/ink/build/hooks/use-focus.js +43 -0
  330. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  331. package/vendor/ink/build/hooks/use-input.d.ts +132 -0
  332. package/vendor/ink/build/hooks/use-input.js +126 -0
  333. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  334. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +6 -0
  335. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +12 -0
  336. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  337. package/vendor/ink/build/hooks/use-paste.d.ts +35 -0
  338. package/vendor/ink/build/hooks/use-paste.js +62 -0
  339. package/vendor/ink/build/hooks/use-paste.js.map +1 -0
  340. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  341. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  342. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  343. package/vendor/ink/build/hooks/use-stdin.d.ts +7 -0
  344. package/vendor/ink/build/hooks/use-stdin.js +9 -0
  345. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  346. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  347. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  348. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  349. package/vendor/ink/build/hooks/use-window-size.d.ts +18 -0
  350. package/vendor/ink/build/hooks/use-window-size.js +22 -0
  351. package/vendor/ink/build/hooks/use-window-size.js.map +1 -0
  352. package/vendor/ink/build/index.d.ts +42 -0
  353. package/vendor/ink/build/index.js +24 -0
  354. package/vendor/ink/build/index.js.map +1 -0
  355. package/vendor/ink/build/ink.d.ts +146 -0
  356. package/vendor/ink/build/ink.js +1022 -0
  357. package/vendor/ink/build/ink.js.map +1 -0
  358. package/vendor/ink/build/input-parser.d.ts +10 -0
  359. package/vendor/ink/build/input-parser.js +194 -0
  360. package/vendor/ink/build/input-parser.js.map +1 -0
  361. package/vendor/ink/build/instances.d.ts +3 -0
  362. package/vendor/ink/build/instances.js +8 -0
  363. package/vendor/ink/build/instances.js.map +1 -0
  364. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  365. package/vendor/ink/build/kitty-keyboard.js +32 -0
  366. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  367. package/vendor/ink/build/log-update.d.ts +20 -0
  368. package/vendor/ink/build/log-update.js +261 -0
  369. package/vendor/ink/build/log-update.js.map +1 -0
  370. package/vendor/ink/build/measure-element.d.ts +20 -0
  371. package/vendor/ink/build/measure-element.js +13 -0
  372. package/vendor/ink/build/measure-element.js.map +1 -0
  373. package/vendor/ink/build/measure-text.d.ts +6 -0
  374. package/vendor/ink/build/measure-text.js +21 -0
  375. package/vendor/ink/build/measure-text.js.map +1 -0
  376. package/vendor/ink/build/output.d.ts +35 -0
  377. package/vendor/ink/build/output.js +328 -0
  378. package/vendor/ink/build/output.js.map +1 -0
  379. package/vendor/ink/build/parse-keypress.d.ts +20 -0
  380. package/vendor/ink/build/parse-keypress.js +495 -0
  381. package/vendor/ink/build/parse-keypress.js.map +1 -0
  382. package/vendor/ink/build/reconciler.d.ts +4 -0
  383. package/vendor/ink/build/reconciler.js +306 -0
  384. package/vendor/ink/build/reconciler.js.map +1 -0
  385. package/vendor/ink/build/render-background.d.ts +4 -0
  386. package/vendor/ink/build/render-background.js +25 -0
  387. package/vendor/ink/build/render-background.js.map +1 -0
  388. package/vendor/ink/build/render-border.d.ts +4 -0
  389. package/vendor/ink/build/render-border.js +84 -0
  390. package/vendor/ink/build/render-border.js.map +1 -0
  391. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  392. package/vendor/ink/build/render-node-to-output.js +162 -0
  393. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  394. package/vendor/ink/build/render-to-string.d.ts +38 -0
  395. package/vendor/ink/build/render-to-string.js +116 -0
  396. package/vendor/ink/build/render-to-string.js.map +1 -0
  397. package/vendor/ink/build/render.d.ts +176 -0
  398. package/vendor/ink/build/render.js +71 -0
  399. package/vendor/ink/build/render.js.map +1 -0
  400. package/vendor/ink/build/renderer.d.ts +8 -0
  401. package/vendor/ink/build/renderer.js +64 -0
  402. package/vendor/ink/build/renderer.js.map +1 -0
  403. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  404. package/vendor/ink/build/sanitize-ansi.js +27 -0
  405. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  406. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  407. package/vendor/ink/build/squash-text-nodes.js +36 -0
  408. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  409. package/vendor/ink/build/styles.d.ts +302 -0
  410. package/vendor/ink/build/styles.js +303 -0
  411. package/vendor/ink/build/styles.js.map +1 -0
  412. package/vendor/ink/build/utils.d.ts +9 -0
  413. package/vendor/ink/build/utils.js +19 -0
  414. package/vendor/ink/build/utils.js.map +1 -0
  415. package/vendor/ink/build/wrap-text.d.ts +3 -0
  416. package/vendor/ink/build/wrap-text.js +38 -0
  417. package/vendor/ink/build/wrap-text.js.map +1 -0
  418. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  419. package/vendor/ink/build/write-synchronized.js +9 -0
  420. package/vendor/ink/build/write-synchronized.js.map +1 -0
  421. package/vendor/ink/license +10 -0
  422. package/vendor/ink/package.json +137 -0
  423. package/.claude-plugin/marketplace.json +0 -34
  424. package/.claude-plugin/plugin.json +0 -20
  425. package/.gitattributes +0 -34
  426. package/.mcp.json +0 -14
  427. package/ARCHITECTURE.md +0 -77
  428. package/CHANGELOG.md +0 -30
  429. package/CONTRIBUTING.md +0 -45
  430. package/DATA-FLOW.md +0 -79
  431. package/LICENSE +0 -21
  432. package/SECURITY.md +0 -138
  433. package/UNINSTALL.md +0 -115
  434. package/agents/maintenance.md +0 -5
  435. package/agents/memory-classification.md +0 -30
  436. package/agents/scheduler-task.md +0 -18
  437. package/agents/webhook-handler.md +0 -27
  438. package/agents/worker.md +0 -24
  439. package/bin/bridge +0 -133
  440. package/bin/statusline-launcher.mjs +0 -82
  441. package/bin/statusline-lib.mjs +0 -581
  442. package/bin/statusline-route.mjs +0 -273
  443. package/bin/statusline.mjs +0 -638
  444. package/bun.lock +0 -927
  445. package/commands/config.md +0 -16
  446. package/commands/doctor.md +0 -13
  447. package/commands/model.md +0 -61
  448. package/commands/setup.md +0 -17
  449. package/defaults/hidden-roles.json +0 -68
  450. package/defaults/memory-chunk-prompt.md +0 -63
  451. package/defaults/mixdog-config.template.json +0 -27
  452. package/defaults/user-workflow.json +0 -8
  453. package/defaults/user-workflow.md +0 -17
  454. package/hooks/hooks.json +0 -73
  455. package/hooks/lib/active-instance.cjs +0 -77
  456. package/hooks/lib/permission-evaluator.cjs +0 -411
  457. package/hooks/lib/permission-route.cjs +0 -63
  458. package/hooks/lib/settings-loader.cjs +0 -117
  459. package/hooks/post-tool-use.cjs +0 -84
  460. package/hooks/pre-mcp-sandbox.cjs +0 -158
  461. package/hooks/pre-tool-subagent.cjs +0 -258
  462. package/hooks/session-start.cjs +0 -1493
  463. package/hooks/shim-launcher.cjs +0 -65
  464. package/hooks/turn-timer.cjs +0 -82
  465. package/lib/claude-md-writer.cjs +0 -386
  466. package/lib/keychain-cjs.cjs +0 -290
  467. package/lib/plugin-paths.cjs +0 -69
  468. package/lib/rules-builder.cjs +0 -241
  469. package/native/README.md +0 -117
  470. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  471. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  472. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  473. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  474. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  475. package/prompts/code-review.txt +0 -16
  476. package/prompts/security-audit.txt +0 -17
  477. package/rules/bridge/00-common.md +0 -39
  478. package/rules/bridge/20-skip-protocol.md +0 -18
  479. package/rules/bridge/30-explorer.md +0 -33
  480. package/rules/bridge/40-cycle1-agent.md +0 -52
  481. package/rules/bridge/41-cycle2-agent.md +0 -62
  482. package/rules/lead/00-tool-lead.md +0 -61
  483. package/rules/lead/01-general.md +0 -26
  484. package/rules/lead/02-channels.md +0 -49
  485. package/rules/lead/03-team.md +0 -27
  486. package/rules/lead/04-workflow.md +0 -20
  487. package/rules/shared/00-language.md +0 -14
  488. package/rules/shared/01-tool.md +0 -138
  489. package/scripts/bootstrap.mjs +0 -130
  490. package/scripts/bridge-unify-smoke.mjs +0 -308
  491. package/scripts/build-runtime-linux.sh +0 -348
  492. package/scripts/build-runtime-macos.sh +0 -217
  493. package/scripts/build-runtime-windows.ps1 +0 -242
  494. package/scripts/builtin-utils-smoke.mjs +0 -398
  495. package/scripts/bump.mjs +0 -80
  496. package/scripts/check-json.mjs +0 -45
  497. package/scripts/check-syntax-changed.mjs +0 -102
  498. package/scripts/check-syntax.mjs +0 -58
  499. package/scripts/code-graph-batch.test.mjs +0 -33
  500. package/scripts/config-preserve-smoke.mjs +0 -180
  501. package/scripts/doctor.mjs +0 -489
  502. package/scripts/edit-normalize-fuzz.mjs +0 -130
  503. package/scripts/edit-normalize-smoke.mjs +0 -401
  504. package/scripts/edit-operation-smoke.mjs +0 -369
  505. package/scripts/edit2-smoke.mjs +0 -63
  506. package/scripts/ensure-deps.mjs +0 -259
  507. package/scripts/fuzzy-e2e.mjs +0 -28
  508. package/scripts/fuzzy-smoke.mjs +0 -26
  509. package/scripts/gateway-model.mjs +0 -596
  510. package/scripts/generate-runtime-manifest.mjs +0 -166
  511. package/scripts/guard-smoke.mjs +0 -66
  512. package/scripts/hidden-role-schema-smoke.mjs +0 -162
  513. package/scripts/hook-routing-smoke.mjs +0 -29
  514. package/scripts/inject-input.ps1 +0 -204
  515. package/scripts/io-complex-smoke.mjs +0 -667
  516. package/scripts/io-explore-bench.mjs +0 -424
  517. package/scripts/io-guardrails-smoke.mjs +0 -205
  518. package/scripts/io-mini-bench-baseline.json +0 -11
  519. package/scripts/io-mini-bench.mjs +0 -216
  520. package/scripts/io-route-harness.mjs +0 -933
  521. package/scripts/io-telemetry-report.mjs +0 -691
  522. package/scripts/lib/gateway-inventory.mjs +0 -178
  523. package/scripts/lib/gateway-settings.mjs +0 -78
  524. package/scripts/mutation-bench.mjs +0 -564
  525. package/scripts/mutation-io-smoke.mjs +0 -1097
  526. package/scripts/native-patch-bridge-smoke.mjs +0 -288
  527. package/scripts/native-patch-smoke.mjs +0 -304
  528. package/scripts/openai-oauth-catalog-smoke.mjs +0 -53
  529. package/scripts/patch-interior-context-smoke.mjs +0 -49
  530. package/scripts/patch-newline-utf8-smoke.mjs +0 -157
  531. package/scripts/perf-hook-smoke.mjs +0 -71
  532. package/scripts/permission-eval-smoke.mjs +0 -443
  533. package/scripts/prep-patch.mjs +0 -53
  534. package/scripts/prep-shim.mjs +0 -96
  535. package/scripts/provider-cache-smoke.mjs +0 -687
  536. package/scripts/report-runtime-health.mjs +0 -132
  537. package/scripts/resolve-bun.mjs +0 -60
  538. package/scripts/run-mcp.mjs +0 -1473
  539. package/scripts/salvage-v4a-shatter.test.mjs +0 -58
  540. package/scripts/scoped-cache-io-smoke.mjs +0 -103
  541. package/scripts/shell-policy-round3-smoke.mjs +0 -46
  542. package/scripts/smoke-runtime-negative.ps1 +0 -100
  543. package/scripts/smoke-runtime-negative.sh +0 -95
  544. package/scripts/stall-policy-smoke.mjs +0 -50
  545. package/scripts/start-memory-worker.mjs +0 -23
  546. package/scripts/statusline-launcher-smoke.mjs +0 -235
  547. package/scripts/stress-atomic-write.mjs +0 -1028
  548. package/scripts/test-fault-inject.mjs +0 -164
  549. package/scripts/test-large-file.mjs +0 -174
  550. package/scripts/tool-edge-smoke.mjs +0 -209
  551. package/scripts/uninstall.mjs +0 -238
  552. package/scripts/webhook-selfheal-smoke.mjs +0 -27
  553. package/scripts/write-overwrite-guard-smoke.mjs +0 -56
  554. package/server-main.mjs +0 -3350
  555. package/server.mjs +0 -468
  556. package/setup/config-merge.mjs +0 -246
  557. package/setup/install.mjs +0 -574
  558. package/setup/launch-core.mjs +0 -617
  559. package/setup/launch.mjs +0 -101
  560. package/setup/locate-claude.mjs +0 -56
  561. package/setup/mixdog-cli.mjs +0 -122
  562. package/setup/setup-server.mjs +0 -3305
  563. package/setup/setup.html +0 -3740
  564. package/setup/tui.mjs +0 -325
  565. package/skills/retro-skill-proposer/SKILL.md +0 -92
  566. package/skills/schedule-add/SKILL.md +0 -77
  567. package/skills/setup/SKILL.md +0 -356
  568. package/skills/webhook-add/SKILL.md +0 -81
  569. package/src/agent/bridge-stall-watchdog.mjs +0 -337
  570. package/src/agent/index.mjs +0 -2229
  571. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +0 -1010
  572. package/src/agent/orchestrator/bridge-retry.mjs +0 -220
  573. package/src/agent/orchestrator/bridge-trace.mjs +0 -601
  574. package/src/agent/orchestrator/cache-mtime.mjs +0 -58
  575. package/src/agent/orchestrator/config.mjs +0 -405
  576. package/src/agent/orchestrator/context/collect.mjs +0 -651
  577. package/src/agent/orchestrator/dispatch-persist.mjs +0 -549
  578. package/src/agent/orchestrator/drain-registry.mjs +0 -50
  579. package/src/agent/orchestrator/explore-validator.mjs +0 -8
  580. package/src/agent/orchestrator/internal-roles.mjs +0 -118
  581. package/src/agent/orchestrator/internal-tools.mjs +0 -88
  582. package/src/agent/orchestrator/jobs.mjs +0 -116
  583. package/src/agent/orchestrator/mcp/client.mjs +0 -364
  584. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +0 -1884
  585. package/src/agent/orchestrator/providers/anthropic.mjs +0 -598
  586. package/src/agent/orchestrator/providers/gemini.mjs +0 -1530
  587. package/src/agent/orchestrator/providers/grok-oauth.mjs +0 -779
  588. package/src/agent/orchestrator/providers/model-catalog.mjs +0 -374
  589. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +0 -366
  590. package/src/agent/orchestrator/providers/openai-compat.mjs +0 -1511
  591. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -1891
  592. package/src/agent/orchestrator/providers/openai-oauth.mjs +0 -1456
  593. package/src/agent/orchestrator/providers/openai-ws.mjs +0 -127
  594. package/src/agent/orchestrator/providers/registry.mjs +0 -192
  595. package/src/agent/orchestrator/providers/retry-classifier.mjs +0 -325
  596. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +0 -142
  597. package/src/agent/orchestrator/session/cache/read-cache.mjs +0 -319
  598. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +0 -361
  599. package/src/agent/orchestrator/session/loop.mjs +0 -1619
  600. package/src/agent/orchestrator/session/manager.mjs +0 -1991
  601. package/src/agent/orchestrator/session/result-classification.mjs +0 -65
  602. package/src/agent/orchestrator/session/store.mjs +0 -632
  603. package/src/agent/orchestrator/session/stream-watchdog.mjs +0 -130
  604. package/src/agent/orchestrator/session/tool-result-offload.mjs +0 -166
  605. package/src/agent/orchestrator/session/trim.mjs +0 -491
  606. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +0 -115
  607. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +0 -331
  608. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +0 -150
  609. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +0 -228
  610. package/src/agent/orchestrator/smart-bridge/index.mjs +0 -215
  611. package/src/agent/orchestrator/smart-bridge/profiles.mjs +0 -37
  612. package/src/agent/orchestrator/smart-bridge/registry.mjs +0 -348
  613. package/src/agent/orchestrator/stall-policy.mjs +0 -201
  614. package/src/agent/orchestrator/tool-loop-guard.mjs +0 -75
  615. package/src/agent/orchestrator/tools/bash-session.mjs +0 -722
  616. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -511
  617. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -480
  618. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -256
  619. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +0 -58
  620. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +0 -240
  621. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +0 -113
  622. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +0 -74
  623. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +0 -242
  624. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +0 -211
  625. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +0 -1364
  626. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +0 -126
  627. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +0 -141
  628. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +0 -194
  629. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +0 -60
  630. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +0 -168
  631. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +0 -173
  632. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +0 -48
  633. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -99
  634. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +0 -193
  635. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +0 -597
  636. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  637. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +0 -300
  638. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +0 -152
  639. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +0 -118
  640. package/src/agent/orchestrator/tools/builtin/read-open.mjs +0 -190
  641. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +0 -728
  642. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +0 -173
  643. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +0 -602
  644. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +0 -196
  645. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +0 -422
  646. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +0 -158
  647. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +0 -869
  648. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +0 -962
  649. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +0 -223
  650. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +0 -206
  651. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +0 -401
  652. package/src/agent/orchestrator/tools/builtin.mjs +0 -503
  653. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +0 -24
  654. package/src/agent/orchestrator/tools/code-graph.mjs +0 -4095
  655. package/src/agent/orchestrator/tools/cwd-tool.mjs +0 -298
  656. package/src/agent/orchestrator/tools/destructive-warning.mjs +0 -323
  657. package/src/agent/orchestrator/tools/edit-normalize.mjs +0 -603
  658. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +0 -154
  659. package/src/agent/orchestrator/tools/graph-manifest.json +0 -26
  660. package/src/agent/orchestrator/tools/host-input.mjs +0 -204
  661. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +0 -143
  662. package/src/agent/orchestrator/tools/patch-manifest.json +0 -26
  663. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +0 -20
  664. package/src/agent/orchestrator/tools/patch.mjs +0 -2754
  665. package/src/agent/orchestrator/tools/progress-message.mjs +0 -118
  666. package/src/agent/orchestrator/tools/shell-command.mjs +0 -865
  667. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +0 -7
  668. package/src/agent/orchestrator/tools/shell-snapshot.mjs +0 -313
  669. package/src/agent/orchestrator/workflow-store.mjs +0 -93
  670. package/src/agent/tool-defs.mjs +0 -110
  671. package/src/channels/backends/discord.mjs +0 -784
  672. package/src/channels/data/voice-runtime-manifest.json +0 -138
  673. package/src/channels/index.mjs +0 -3268
  674. package/src/channels/lib/config.mjs +0 -292
  675. package/src/channels/lib/drop-trace.mjs +0 -71
  676. package/src/channels/lib/event-pipeline.mjs +0 -81
  677. package/src/channels/lib/holidays.mjs +0 -138
  678. package/src/channels/lib/hook-pipe-server.mjs +0 -822
  679. package/src/channels/lib/output-forwarder.mjs +0 -765
  680. package/src/channels/lib/runtime-paths.mjs +0 -552
  681. package/src/channels/lib/scheduler.mjs +0 -723
  682. package/src/channels/lib/session-discovery.mjs +0 -103
  683. package/src/channels/lib/state-file.mjs +0 -68
  684. package/src/channels/lib/status-snapshot.mjs +0 -219
  685. package/src/channels/lib/tool-format.mjs +0 -140
  686. package/src/channels/lib/transcript-discovery.mjs +0 -195
  687. package/src/channels/lib/voice-runtime-fetcher.mjs +0 -734
  688. package/src/channels/lib/webhook.mjs +0 -1318
  689. package/src/channels/tool-defs.mjs +0 -170
  690. package/src/daemon/host.mjs +0 -118
  691. package/src/daemon/mcp-transport.mjs +0 -47
  692. package/src/daemon/session.mjs +0 -100
  693. package/src/daemon/thin-client.mjs +0 -71
  694. package/src/daemon/transport.mjs +0 -163
  695. package/src/gateway/claude-current.mjs +0 -255
  696. package/src/gateway/oauth-usage.mjs +0 -598
  697. package/src/gateway/route-meta.mjs +0 -629
  698. package/src/gateway/server.mjs +0 -713
  699. package/src/memory/data/runtime-manifest.json +0 -40
  700. package/src/memory/index.mjs +0 -3332
  701. package/src/memory/lib/core-memory-store.mjs +0 -330
  702. package/src/memory/lib/embedding-provider.mjs +0 -269
  703. package/src/memory/lib/embedding-worker.mjs +0 -323
  704. package/src/memory/lib/memory-cycle1.mjs +0 -645
  705. package/src/memory/lib/memory-cycle2.mjs +0 -1284
  706. package/src/memory/lib/memory-cycle3.mjs +0 -540
  707. package/src/memory/lib/memory-embed.mjs +0 -299
  708. package/src/memory/lib/memory-ops-policy.mjs +0 -190
  709. package/src/memory/lib/memory-recall-store.mjs +0 -638
  710. package/src/memory/lib/memory.mjs +0 -412
  711. package/src/memory/lib/pg/adapter.mjs +0 -308
  712. package/src/memory/lib/pg/process.mjs +0 -360
  713. package/src/memory/lib/pg/supervisor.mjs +0 -396
  714. package/src/memory/lib/runtime-fetcher.mjs +0 -458
  715. package/src/memory/lib/trace-store.mjs +0 -728
  716. package/src/memory/tool-defs.mjs +0 -79
  717. package/src/search/index.mjs +0 -1173
  718. package/src/search/lib/backends/anthropic-oauth.mjs +0 -98
  719. package/src/search/lib/backends/exa.mjs +0 -50
  720. package/src/search/lib/backends/firecrawl.mjs +0 -61
  721. package/src/search/lib/backends/gemini-api.mjs +0 -83
  722. package/src/search/lib/backends/grok-oauth.mjs +0 -86
  723. package/src/search/lib/backends/index.mjs +0 -150
  724. package/src/search/lib/backends/openai-api.mjs +0 -144
  725. package/src/search/lib/backends/openai-oauth.mjs +0 -102
  726. package/src/search/lib/backends/openai-web-search.mjs +0 -76
  727. package/src/search/lib/backends/tavily.mjs +0 -55
  728. package/src/search/lib/backends/xai-api.mjs +0 -113
  729. package/src/search/lib/config.mjs +0 -192
  730. package/src/search/lib/provider-usage.mjs +0 -67
  731. package/src/search/lib/providers.mjs +0 -47
  732. package/src/search/lib/search-intent.mjs +0 -109
  733. package/src/search/lib/setup-handler.mjs +0 -261
  734. package/src/search/lib/web-tools.mjs +0 -1219
  735. package/src/search/tool-defs.mjs +0 -83
  736. package/src/setup/defender-exclusion.mjs +0 -183
  737. package/src/shared/atomic-file.mjs +0 -436
  738. package/src/shared/config.mjs +0 -372
  739. package/src/shared/daemon-recycle.mjs +0 -108
  740. package/src/shared/disable-claude-builtins.mjs +0 -91
  741. package/src/shared/err-text.mjs +0 -12
  742. package/src/shared/llm/http-agent.mjs +0 -123
  743. package/src/shared/open-url.mjs +0 -62
  744. package/src/shared/plugin-paths.mjs +0 -58
  745. package/src/shared/schedules-store.mjs +0 -70
  746. package/src/shared/seed.mjs +0 -161
  747. package/src/shared/user-cwd.mjs +0 -225
  748. package/src/shared/user-data-guard.mjs +0 -244
  749. package/src/status/aggregator.mjs +0 -584
  750. package/src/status/server.mjs +0 -413
  751. package/tools.json +0 -1671
  752. /package/{defaults → src/defaults}/cycle3-review-prompt.md +0 -0
  753. /package/{defaults → src/defaults}/memory-promote-prompt.md +0 -0
  754. /package/{hooks → src/hooks}/lib/permission-rules.cjs +0 -0
  755. /package/{lib → src/lib}/config-cjs.cjs +0 -0
  756. /package/{lib → src/lib}/hook-pipe-path.cjs +0 -0
  757. /package/{lib → src/lib}/mixdog-debug.cjs +0 -0
  758. /package/{lib → src/lib}/text-utils.cjs +0 -0
  759. /package/{rules → src/rules}/bridge/42-cycle3-agent.md +0 -0
  760. /package/src/{agent → runtime/agent}/orchestrator/activity-bus.mjs +0 -0
  761. /package/src/{agent → runtime/agent}/orchestrator/providers/anthropic-betas.mjs +0 -0
  762. /package/src/{agent → runtime/agent}/orchestrator/session/abort-lookup.mjs +0 -0
  763. /package/src/{agent → runtime/agent}/orchestrator/session/cache/post-edit-marks.mjs +0 -0
  764. /package/src/{agent → runtime/agent}/orchestrator/session/cache/scoped-cache-outcome.mjs +0 -0
  765. /package/src/{agent → runtime/agent}/orchestrator/session/cache/util.mjs +0 -0
  766. /package/src/{agent → runtime/agent}/orchestrator/session/read-dedup.mjs +0 -0
  767. /package/src/{agent → runtime/agent}/orchestrator/session/save-session-worker.mjs +0 -0
  768. /package/src/{agent → runtime/agent}/orchestrator/smart-bridge/session-builder.mjs +0 -0
  769. /package/src/{agent → runtime/agent}/orchestrator/tools/bash-policy-scan.mjs +0 -0
  770. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/advisory-lock.mjs +0 -0
  771. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/atomic-write.mjs +0 -0
  772. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/binary-file.mjs +0 -0
  773. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cache-layers.mjs +0 -0
  774. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cwd-utils.mjs +0 -0
  775. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/device-paths.mjs +0 -0
  776. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -0
  777. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diff-utils.mjs +0 -0
  778. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/fs-reachability.mjs +0 -0
  779. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/grep-formatting.mjs +0 -0
  780. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/hash-utils.mjs +0 -0
  781. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/list-formatting.mjs +0 -0
  782. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/open-config-tool.mjs +0 -0
  783. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-locks.mjs +0 -0
  784. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-utils.mjs +0 -0
  785. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-args.mjs +0 -0
  786. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-batch.mjs +0 -0
  787. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-constants.mjs +0 -0
  788. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image-resize.mjs +0 -0
  789. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image.mjs +0 -0
  790. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-lines.mjs +0 -0
  791. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-mode-tool.mjs +0 -0
  792. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-range-index.mjs +0 -0
  793. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-ranges.mjs +0 -0
  794. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-special-files.mjs +0 -0
  795. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-tool.mjs +0 -0
  796. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-windows.mjs +0 -0
  797. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-analysis.mjs +0 -0
  798. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-output.mjs +0 -0
  799. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-helpers.mjs +0 -0
  800. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-validation.mjs +0 -0
  801. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/text-stats.mjs +0 -0
  802. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/windows-roots.mjs +0 -0
  803. /package/src/{agent → runtime/agent}/orchestrator/tools/code-graph-prewarm-worker.mjs +0 -0
  804. /package/src/{agent → runtime/agent}/orchestrator/tools/env-scrub.mjs +0 -0
  805. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-content-cache.mjs +0 -0
  806. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-planner.mjs +0 -0
  807. /package/src/{agent → runtime/agent}/orchestrator/tools/next-call-utils.mjs +0 -0
  808. /package/src/{agent → runtime/agent}/orchestrator/tools/result-compression.mjs +0 -0
  809. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-exec-policy.mjs +0 -0
  810. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy-danger-target.mjs +0 -0
  811. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy.mjs +0 -0
  812. /package/src/{channels → runtime/channels}/lib/cli-worker-host.mjs +0 -0
  813. /package/src/{channels → runtime/channels}/lib/config-lock.mjs +0 -0
  814. /package/src/{channels → runtime/channels}/lib/event-queue.mjs +0 -0
  815. /package/src/{channels → runtime/channels}/lib/executor.mjs +0 -0
  816. /package/src/{channels → runtime/channels}/lib/format.mjs +0 -0
  817. /package/src/{channels → runtime/channels}/lib/interaction-workflows.mjs +0 -0
  818. /package/src/{channels → runtime/channels}/lib/memory-client.mjs +0 -0
  819. /package/src/{channels → runtime/channels}/lib/session-control.mjs +0 -0
  820. /package/src/{channels → runtime/channels}/lib/settings.mjs +0 -0
  821. /package/src/{channels → runtime/channels}/lib/whisper-server.mjs +0 -0
  822. /package/src/{memory → runtime/memory}/lib/agent-ipc.mjs +0 -0
  823. /package/src/{memory → runtime/memory}/lib/bridge-trace-queries.mjs +0 -0
  824. /package/src/{memory → runtime/memory}/lib/llm-worker-host.mjs +0 -0
  825. /package/src/{memory → runtime/memory}/lib/memory-cycle.mjs +0 -0
  826. /package/src/{memory → runtime/memory}/lib/memory-extraction.mjs +0 -0
  827. /package/src/{memory → runtime/memory}/lib/memory-maintenance-store.mjs +0 -0
  828. /package/src/{memory → runtime/memory}/lib/memory-recall-id-patch.mjs +0 -0
  829. /package/src/{memory → runtime/memory}/lib/memory-recall-read-query.mjs +0 -0
  830. /package/src/{memory → runtime/memory}/lib/memory-recall-scope-filter.mjs +0 -0
  831. /package/src/{memory → runtime/memory}/lib/memory-retrievers.mjs +0 -0
  832. /package/src/{memory → runtime/memory}/lib/memory-score.mjs +0 -0
  833. /package/src/{memory → runtime/memory}/lib/memory-text-utils.mjs +0 -0
  834. /package/src/{memory → runtime/memory}/lib/model-profile.mjs +0 -0
  835. /package/src/{memory → runtime/memory}/lib/project-id-resolver.mjs +0 -0
  836. /package/src/{search → runtime/search}/lib/cache.mjs +0 -0
  837. /package/src/{search → runtime/search}/lib/formatter.mjs +0 -0
  838. /package/src/{search → runtime/search}/lib/state.mjs +0 -0
  839. /package/src/{shared → runtime/shared}/abort-controller.mjs +0 -0
  840. /package/src/{shared → runtime/shared}/llm/cost.mjs +0 -0
  841. /package/src/{shared → runtime/shared}/llm/index.mjs +0 -0
  842. /package/src/{shared → runtime/shared}/llm/pid-cleanup.mjs +0 -0
  843. /package/src/{shared → runtime/shared}/llm/usage-log.mjs +0 -0
  844. /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
+ }