mixdog 0.9.3 → 0.9.5

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 (382) hide show
  1. package/README.md +112 -38
  2. package/package.json +10 -3
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/r5-orchestrated-task.json +7 -0
  7. package/scripts/bench/review-tasks.json +20 -0
  8. package/scripts/bench/round-codex.json +114 -0
  9. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  10. package/scripts/bench/round-mixdog-lead.json +269 -0
  11. package/scripts/bench/round-mixdog.json +126 -0
  12. package/scripts/bench/round-r10-bigsample.json +679 -0
  13. package/scripts/bench/round-r11-codexalign.json +257 -0
  14. package/scripts/bench/round-r13-clientmeta.json +464 -0
  15. package/scripts/bench/round-r14-betafeatures.json +466 -0
  16. package/scripts/bench/round-r15-fulldefault.json +462 -0
  17. package/scripts/bench/round-r16-sessionid.json +466 -0
  18. package/scripts/bench/round-r17-wirebytes.json +456 -0
  19. package/scripts/bench/round-r18-prewarm.json +468 -0
  20. package/scripts/bench/round-r19-clean.json +472 -0
  21. package/scripts/bench/round-r20-prewarm-clean.json +475 -0
  22. package/scripts/bench/round-r21-delta-retry.json +473 -0
  23. package/scripts/bench/round-r22-full-probe.json +693 -0
  24. package/scripts/bench/round-r23-itemprobe.json +701 -0
  25. package/scripts/bench/round-r24-shapefix.json +677 -0
  26. package/scripts/bench/round-r25-serial.json +464 -0
  27. package/scripts/bench/round-r26-parallel3.json +671 -0
  28. package/scripts/bench/round-r27-parallel10.json +894 -0
  29. package/scripts/bench/round-r28-parallel10-stagger.json +882 -0
  30. package/scripts/bench/round-r29-parallel10-stagger166.json +886 -0
  31. package/scripts/bench/round-r30-instid.json +253 -0
  32. package/scripts/bench/round-r31-upgradeprobe.json +256 -0
  33. package/scripts/bench/round-r32-vs-codex-lead.json +254 -0
  34. package/scripts/bench/round-r33-vs-codex-codex.json +115 -0
  35. package/scripts/bench/round-r34-orchestrated.json +120 -0
  36. package/scripts/bench/round-r35-orchestrated-codex.json +61 -0
  37. package/scripts/bench/round-r36-orchestrated-capped.json +128 -0
  38. package/scripts/bench/round-r4-codex.json +114 -0
  39. package/scripts/bench/round-r4-mixed.json +225 -0
  40. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  41. package/scripts/bench/round-r6-codex.json +114 -0
  42. package/scripts/bench/round-r6-solo.json +257 -0
  43. package/scripts/bench/round-r7-full.json +254 -0
  44. package/scripts/bench/round-r8-fulldefault.json +255 -0
  45. package/scripts/bench-run.mjs +251 -32
  46. package/scripts/freevar-smoke.mjs +95 -0
  47. package/scripts/internal-comms-bench.mjs +3 -4
  48. package/scripts/internal-comms-smoke.mjs +10 -9
  49. package/scripts/model-catalog-audit.mjs +209 -0
  50. package/scripts/model-list-sanitize-test.mjs +37 -0
  51. package/scripts/mouse-probe.mjs +45 -0
  52. package/scripts/output-style-bench.mjs +13 -6
  53. package/scripts/output-style-smoke.mjs +4 -4
  54. package/scripts/provider-toolcall-test.mjs +7 -3
  55. package/scripts/recall-bench.mjs +76 -13
  56. package/scripts/recall-quality-cases.json +12 -0
  57. package/scripts/recall-usecase-cases.json +18 -0
  58. package/scripts/session-bench.mjs +152 -6
  59. package/scripts/tool-smoke.mjs +25 -65
  60. package/scripts/tui-render-smoke.mjs +90 -0
  61. package/scripts/webhook-smoke.mjs +208 -0
  62. package/src/agents/debugger/AGENT.md +4 -1
  63. package/src/agents/heavy-worker/AGENT.md +9 -8
  64. package/src/agents/maintainer/AGENT.md +4 -0
  65. package/src/agents/reviewer/AGENT.md +2 -1
  66. package/src/agents/scheduler-task/AGENT.md +2 -3
  67. package/src/agents/webhook-handler/AGENT.md +2 -3
  68. package/src/agents/worker/AGENT.md +10 -7
  69. package/src/app.mjs +12 -1
  70. package/src/headless-role.mjs +7 -1
  71. package/src/lib/rules-builder.cjs +4 -0
  72. package/src/mixdog-session-runtime.mjs +647 -2056
  73. package/src/output-styles/default.md +30 -9
  74. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  75. package/src/output-styles/minimal.md +8 -6
  76. package/src/output-styles/simple.md +21 -7
  77. package/src/rules/agent/00-common.md +6 -3
  78. package/src/rules/agent/30-explorer.md +16 -5
  79. package/src/rules/lead/01-general.md +5 -5
  80. package/src/rules/lead/lead-brief.md +15 -0
  81. package/src/rules/lead/lead-tool.md +6 -15
  82. package/src/rules/shared/01-tool.md +17 -21
  83. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +8 -3
  84. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  85. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  86. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  87. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  88. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  89. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  90. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  91. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +62 -20
  92. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  93. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  94. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +81 -1281
  95. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  96. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -3
  97. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  99. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  100. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  101. package/src/runtime/agent/orchestrator/providers/gemini.mjs +43 -1013
  102. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +17 -3
  103. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +105 -11
  104. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +356 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  109. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +40 -1143
  110. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +740 -0
  111. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  112. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +349 -2131
  113. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +143 -1002
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +229 -0
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +465 -0
  117. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  119. package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +80 -0
  120. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  121. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  122. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  123. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  124. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  125. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  126. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  127. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  128. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +14 -2
  129. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -3
  131. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +275 -0
  132. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  133. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  134. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  135. package/src/runtime/agent/orchestrator/session/loop.mjs +278 -402
  136. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  137. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +7 -4
  138. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +12 -0
  139. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  140. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  141. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  142. package/src/runtime/agent/orchestrator/session/manager.mjs +166 -1087
  143. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  144. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  145. package/src/runtime/agent/orchestrator/stall-policy.mjs +20 -1
  146. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  147. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  148. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +35 -44
  149. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  152. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -92
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  155. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +28 -265
  157. package/src/runtime/agent/orchestrator/tools/builtin.mjs +0 -6
  158. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +57 -3
  159. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +10 -122
  161. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  163. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  164. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  165. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  166. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  167. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  168. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  169. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  170. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  171. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  172. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  173. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +0 -21
  174. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -72
  175. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  176. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  177. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  178. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  179. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  180. package/src/runtime/channels/backends/discord.mjs +27 -318
  181. package/src/runtime/channels/backends/telegram.mjs +8 -12
  182. package/src/runtime/channels/index.mjs +247 -701
  183. package/src/runtime/channels/lib/backend-dispatch.mjs +46 -0
  184. package/src/runtime/channels/lib/config.mjs +37 -149
  185. package/src/runtime/channels/lib/event-pipeline.mjs +22 -5
  186. package/src/runtime/channels/lib/event-queue.mjs +78 -13
  187. package/src/runtime/channels/lib/inbound-routing.mjs +74 -0
  188. package/src/runtime/channels/lib/interaction-workflows.mjs +5 -113
  189. package/src/runtime/channels/lib/output-forwarder.mjs +1 -1
  190. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  191. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  192. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  193. package/src/runtime/channels/lib/scheduler.mjs +27 -113
  194. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  195. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  196. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  197. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  198. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  199. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  200. package/src/runtime/channels/lib/webhook/deliveries.mjs +313 -0
  201. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  202. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  203. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  204. package/src/runtime/channels/lib/webhook.mjs +43 -616
  205. package/src/runtime/channels/tool-defs.mjs +11 -130
  206. package/src/runtime/memory/index.mjs +210 -1948
  207. package/src/runtime/memory/lib/core-memory-store.mjs +5 -1
  208. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  209. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  210. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  211. package/src/runtime/memory/lib/ko-morph.mjs +195 -0
  212. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  213. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  214. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  215. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  216. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  217. package/src/runtime/memory/lib/memory-cycle2.mjs +24 -842
  218. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  219. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  220. package/src/runtime/memory/lib/memory-recall-store.mjs +69 -12
  221. package/src/runtime/memory/lib/memory-text-utils.mjs +46 -0
  222. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  223. package/src/runtime/memory/lib/query-handlers.mjs +802 -0
  224. package/src/runtime/memory/lib/recall-format.mjs +55 -0
  225. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  226. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  227. package/src/runtime/memory/tool-defs.mjs +5 -13
  228. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  229. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  230. package/src/runtime/search/lib/web-tools.mjs +24 -602
  231. package/src/runtime/shared/atomic-file.mjs +26 -1
  232. package/src/runtime/shared/config.mjs +14 -4
  233. package/src/runtime/shared/launcher-control.mjs +2 -2
  234. package/src/runtime/shared/markdown-frontmatter.mjs +19 -0
  235. package/src/runtime/shared/schedules-store.mjs +13 -3
  236. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  237. package/src/runtime/shared/tool-primitives.mjs +308 -0
  238. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  239. package/src/runtime/shared/tool-surface.mjs +80 -898
  240. package/src/runtime/shared/transcript-writer.mjs +23 -0
  241. package/src/runtime/shared/update-checker.mjs +7 -4
  242. package/src/session-runtime/config-helpers.mjs +119 -2
  243. package/src/session-runtime/config-lifecycle.mjs +232 -0
  244. package/src/session-runtime/cwd-plugins.mjs +226 -0
  245. package/src/session-runtime/mcp-glue.mjs +177 -0
  246. package/src/session-runtime/model-recency.mjs +111 -0
  247. package/src/session-runtime/native-search.mjs +247 -0
  248. package/src/session-runtime/output-styles.mjs +11 -9
  249. package/src/session-runtime/prewarm.mjs +142 -0
  250. package/src/session-runtime/provider-models.mjs +278 -0
  251. package/src/session-runtime/provider-usage.mjs +120 -0
  252. package/src/session-runtime/quick-model-rows.mjs +205 -0
  253. package/src/session-runtime/quick-search-models.mjs +47 -0
  254. package/src/session-runtime/session-hooks.mjs +93 -0
  255. package/src/session-runtime/settings-api.mjs +352 -0
  256. package/src/session-runtime/tool-catalog.mjs +29 -29
  257. package/src/session-runtime/tool-defs.mjs +84 -0
  258. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  259. package/src/session-runtime/workflow.mjs +1 -1
  260. package/src/standalone/agent-tool/helpers.mjs +237 -0
  261. package/src/standalone/agent-tool/notify.mjs +107 -0
  262. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  263. package/src/standalone/agent-tool/render.mjs +152 -0
  264. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  265. package/src/standalone/agent-tool.mjs +138 -669
  266. package/src/standalone/channel-admin.mjs +102 -90
  267. package/src/standalone/channel-worker.mjs +4 -7
  268. package/src/standalone/explore-tool.mjs +64 -14
  269. package/src/standalone/hook-bus/config.mjs +207 -0
  270. package/src/standalone/hook-bus/constants.mjs +90 -0
  271. package/src/standalone/hook-bus/handlers.mjs +481 -0
  272. package/src/standalone/hook-bus/payload.mjs +31 -0
  273. package/src/standalone/hook-bus/rules.mjs +77 -0
  274. package/src/standalone/hook-bus.mjs +77 -870
  275. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  276. package/src/standalone/opencode-go-login.mjs +5 -1
  277. package/src/standalone/provider-admin.mjs +1 -16
  278. package/src/standalone/usage-dashboard.mjs +3 -1
  279. package/src/tui/App.jsx +1059 -8110
  280. package/src/tui/app/app-format.mjs +213 -0
  281. package/src/tui/app/channel-pickers.mjs +508 -0
  282. package/src/tui/app/clipboard.mjs +67 -0
  283. package/src/tui/app/core-memory-picker.mjs +210 -0
  284. package/src/tui/app/extension-pickers.mjs +506 -0
  285. package/src/tui/app/input-parsers.mjs +193 -0
  286. package/src/tui/app/maintenance-pickers.mjs +356 -0
  287. package/src/tui/app/model-options.mjs +334 -0
  288. package/src/tui/app/model-picker.mjs +365 -0
  289. package/src/tui/app/onboarding-steps.mjs +400 -0
  290. package/src/tui/app/project-picker.mjs +247 -0
  291. package/src/tui/app/provider-setup-picker.mjs +580 -0
  292. package/src/tui/app/resume-picker.mjs +55 -0
  293. package/src/tui/app/route-pickers.mjs +419 -0
  294. package/src/tui/app/settings-picker.mjs +489 -0
  295. package/src/tui/app/slash-commands.mjs +101 -0
  296. package/src/tui/app/slash-dispatch.mjs +427 -0
  297. package/src/tui/app/text-layout.mjs +46 -0
  298. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  299. package/src/tui/app/transcript-window.mjs +677 -0
  300. package/src/tui/app/use-mouse-input.mjs +460 -0
  301. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  302. package/src/tui/app/use-transcript-scroll.mjs +512 -0
  303. package/src/tui/app/use-transcript-window.mjs +607 -0
  304. package/src/tui/components/ConfirmBar.jsx +10 -7
  305. package/src/tui/components/Picker.jsx +64 -15
  306. package/src/tui/components/PromptInput.jsx +33 -102
  307. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  308. package/src/tui/components/StatusLine.jsx +69 -15
  309. package/src/tui/components/TextEntryPanel.jsx +11 -0
  310. package/src/tui/components/ToolExecution.jsx +52 -594
  311. package/src/tui/components/TranscriptItem.jsx +105 -0
  312. package/src/tui/components/UsagePanel.jsx +18 -4
  313. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  314. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  315. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  316. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  317. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  318. package/src/tui/display-width.mjs +20 -3
  319. package/src/tui/dist/index.mjs +13553 -12384
  320. package/src/tui/engine/agent-job-feed.mjs +133 -0
  321. package/src/tui/engine/notification-plan.mjs +76 -0
  322. package/src/tui/engine/render-timing.mjs +17 -0
  323. package/src/tui/engine/tool-approval.mjs +94 -0
  324. package/src/tui/engine/tool-card-results.mjs +234 -0
  325. package/src/tui/engine/tool-result-status.mjs +135 -0
  326. package/src/tui/engine.mjs +170 -574
  327. package/src/tui/figures.mjs +5 -0
  328. package/src/tui/index.jsx +65 -1
  329. package/src/tui/input-editing.mjs +2 -2
  330. package/src/tui/markdown/format-token.mjs +4 -1
  331. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  332. package/src/tui/theme.mjs +6 -0
  333. package/src/ui/statusline-agents.mjs +213 -0
  334. package/src/ui/statusline-format.mjs +146 -0
  335. package/src/ui/statusline-segments.mjs +148 -0
  336. package/src/ui/statusline.mjs +77 -501
  337. package/src/ui/tool-card.mjs +0 -1
  338. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  339. package/src/workflows/default/WORKFLOW.md +16 -18
  340. package/src/workflows/sequential/WORKFLOW.md +16 -18
  341. package/vendor/ink/build/display-width.js +19 -3
  342. package/vendor/ink/build/ink.js +112 -7
  343. package/vendor/ink/build/log-update.js +17 -3
  344. package/vendor/ink/build/wrap-text.js +125 -0
  345. package/scripts/_test-folder-dialog.mjs +0 -30
  346. package/scripts/fix-brief-fn.mjs +0 -35
  347. package/scripts/fix-format-tool-surface.mjs +0 -24
  348. package/scripts/fix-tool-exec-visible.mjs +0 -42
  349. package/scripts/patch-agent-brief.mjs +0 -48
  350. package/scripts/patch-app.mjs +0 -21
  351. package/scripts/patch-app2.mjs +0 -18
  352. package/scripts/patch-dist-brief.mjs +0 -96
  353. package/scripts/patch-tool-exec.mjs +0 -70
  354. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  355. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  356. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  357. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  358. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  359. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +0 -162
  360. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  361. package/src/runtime/channels/lib/holidays.mjs +0 -138
  362. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  363. package/src/runtime/shared/task-notification-envelope.test.mjs +0 -107
  364. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  365. package/src/standalone/agent-task-status.test.mjs +0 -76
  366. package/src/tui/components/tool-output-format.test.mjs +0 -399
  367. package/src/tui/display-width.test.mjs +0 -35
  368. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  369. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  370. package/src/tui/input-editing.selection.test.mjs +0 -75
  371. package/src/tui/markdown/format-token.test.mjs +0 -354
  372. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  373. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  374. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  375. package/src/tui/paste-fix.test.mjs +0 -119
  376. package/src/tui/prompt-history-store.test.mjs +0 -52
  377. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  378. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  379. package/src/ui/markdown.test.mjs +0 -70
  380. package/src/ui/statusline-context-label.test.mjs +0 -15
  381. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  382. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,760 @@
1
+ /**
2
+ * openai-compat-xai.mjs — xAI/Grok Responses-API routing, prompt-cache lanes
3
+ * and cache tracing for the OpenAI-compat provider.
4
+ *
5
+ * Extracted from openai-compat.mjs. Owns the xAI cache-lane singletons
6
+ * (xaiResponsesCacheLanes) plus cache routing/fingerprint/trace helpers and
7
+ * the compat cache trace writer shared by chat-completions and Responses
8
+ * paths. openai-compat.mjs imports the routing/lane/trace entry points.
9
+ */
10
+ import { createHash } from 'crypto';
11
+ import { appendAgentTrace } from '../agent-trace.mjs';
12
+ import {
13
+ resolveProviderCacheKey,
14
+ resolveProviderPromptCacheLane,
15
+ } from '../agent-runtime/cache-strategy.mjs';
16
+ import { shouldFallbackTransport } from './retry-classifier.mjs';
17
+ import { traceHash, stableTraceStringify, summarizeTraceTools, traceTextShape } from './trace-utils.mjs';
18
+ import { summarizeTraceMessages, extractCompatCachedTokens } from './openai-compat-trace.mjs';
19
+
20
+ export function xaiPrefixSeed({ opts, params, rawTools, model }) {
21
+ const providerKey = resolveProviderCacheKey(opts, 'xai');
22
+ const systemMessages = (params?.messages || [])
23
+ .filter(m => m?.role === 'system')
24
+ .map(m => String(m?.content ?? ''));
25
+ return stableTraceStringify({
26
+ scope: 'xai-prefix-model-system-tools',
27
+ providerKey: String(providerKey),
28
+ model: model || null,
29
+ systemMessages,
30
+ tools: summarizeTraceTools(rawTools),
31
+ });
32
+ }
33
+
34
+ export function xaiCacheRouting(opts, params, rawTools, model) {
35
+ const sessionId = String(opts?.sessionId || opts?.session?.id || '').trim();
36
+ const providerKey = resolveProviderCacheKey(opts, 'xai');
37
+ const prefixSeed = xaiPrefixSeed({ opts, params, rawTools, model });
38
+ const prefixHash = traceHash(prefixSeed);
39
+ const routingSeed = stableTraceStringify({
40
+ scope: 'xai-chat-session-v1',
41
+ providerKey: String(providerKey),
42
+ model: model || null,
43
+ sessionId: sessionId || `ephemeral:${process.pid}`,
44
+ });
45
+ return {
46
+ key: deterministicUuidFromKey(routingSeed),
47
+ mode: sessionId ? 'session' : 'ephemeral',
48
+ seedHash: traceHash(routingSeed),
49
+ prefixHash,
50
+ ownerSessionHash: sessionId ? traceHash(sessionId) : null,
51
+ };
52
+ }
53
+
54
+ export function xaiResponsesCacheRouting(opts, params, rawTools, model) {
55
+ // Default to 'prefix' so parallel workers sharing the same model + system
56
+ // + tools land on a common prompt_cache_key, letting xAI's server-side
57
+ // prefix cache hit across sessions instead of cold-starting per worker.
58
+ // Override with 'session' (env or opts) for legacy session-isolated lanes.
59
+ const scope = String(opts?.xaiResponsesCacheScope || process.env.MIXDOG_XAI_RESPONSES_CACHE_SCOPE || 'prefix')
60
+ .trim()
61
+ .toLowerCase();
62
+ if (scope !== 'prefix') {
63
+ return xaiCacheRouting(opts, params, rawTools, model);
64
+ }
65
+ const sessionId = String(opts?.sessionId || opts?.session?.id || '').trim();
66
+ const providerKey = resolveProviderCacheKey(opts, 'xai');
67
+ const prefixSeed = xaiPrefixSeed({ opts, params, rawTools, model });
68
+ const prefixHash = traceHash(prefixSeed);
69
+ const routingSeed = stableTraceStringify({
70
+ scope: 'xai-responses-prefix-v1',
71
+ providerKey: String(providerKey),
72
+ model: model || null,
73
+ prefixHash,
74
+ });
75
+ return {
76
+ key: deterministicUuidFromKey(routingSeed),
77
+ mode: 'prefix',
78
+ seedHash: traceHash(routingSeed),
79
+ prefixHash,
80
+ ownerSessionHash: sessionId ? traceHash(sessionId) : null,
81
+ };
82
+ }
83
+
84
+ export function normalizeXaiReasoningEffort(value) {
85
+ const effort = String(value || '').trim().toLowerCase();
86
+ return ['none', 'low', 'medium', 'high'].includes(effort) ? effort : null;
87
+ }
88
+
89
+ export function opencodeGoReasoningEffortValues(modelInfo) {
90
+ const effort = (modelInfo?.reasoningOptions || []).find((option) => option?.type === 'effort');
91
+ return Array.isArray(effort?.values)
92
+ ? effort.values.map((item) => String(item || '').trim().toLowerCase()).filter(Boolean)
93
+ : [];
94
+ }
95
+
96
+ export function normalizeOpencodeGoReasoningEffort(value, modelInfo) {
97
+ const allowed = opencodeGoReasoningEffortValues(modelInfo);
98
+ if (!allowed.length) return null;
99
+ const effort = String(value || '').trim().toLowerCase();
100
+ if (allowed.includes(effort)) return effort;
101
+ if ((effort === 'max' || effort === 'xhigh') && allowed.includes('max')) return 'max';
102
+ if (['high', 'medium', 'low'].includes(effort) && allowed.includes('high')) return 'high';
103
+ return null;
104
+ }
105
+
106
+ export function useXaiResponsesApi(opts, config) {
107
+ const raw = opts?.xaiApiMode
108
+ ?? config?.apiMode
109
+ ?? config?.xaiApiMode
110
+ ?? process.env.MIXDOG_XAI_API_MODE
111
+ ?? process.env.MIXDOG_XAI_RESPONSES;
112
+ if (raw == null || raw === '') return true;
113
+ const mode = String(raw).trim().toLowerCase();
114
+ return !['0', 'false', 'off', 'chat', 'chat-completions', 'chat_completions'].includes(mode);
115
+ }
116
+
117
+ export function useXaiResponsesWebSocket(opts, config) {
118
+ const raw = opts?.xaiResponsesTransport
119
+ ?? opts?.xaiTransport
120
+ ?? config?.responsesTransport
121
+ ?? config?.transport
122
+ ?? process.env.MIXDOG_XAI_RESPONSES_TRANSPORT
123
+ ?? process.env.MIXDOG_XAI_TRANSPORT;
124
+ if (raw == null || raw === '') return true;
125
+ const transport = String(raw).trim().toLowerCase();
126
+ return !['0', 'false', 'off', 'http', 'https', 'responses-http', 'sdk'].includes(transport);
127
+ }
128
+
129
+ function _envFlag(name, fallback = true) {
130
+ const raw = process.env[name];
131
+ if (raw == null || raw === '') return fallback;
132
+ return !['0', 'false', 'off', 'no'].includes(String(raw).toLowerCase());
133
+ }
134
+
135
+ // xAI WS→HTTP transport fallback → shared shouldFallbackTransport
136
+ // (retry-classifier.mjs). Identical deny-order + allow-list; the per-provider
137
+ // env flag is computed here and passed via `enabled`.
138
+ export function _shouldFallbackXaiWsToHttp(err, signal) {
139
+ return shouldFallbackTransport(err, {
140
+ signal,
141
+ enabled: _envFlag('MIXDOG_XAI_WS_HTTP_FALLBACK', true),
142
+ });
143
+ }
144
+
145
+ export function useXaiResponsesWebSocketWarmup(opts, config, { previousResponseId, instructions, rawTools }) {
146
+ if (previousResponseId) return false;
147
+ const raw = opts?.xaiResponsesWarmup
148
+ ?? opts?.xaiWsWarmup
149
+ ?? config?.responsesWarmup
150
+ ?? config?.wsWarmup
151
+ ?? process.env.MIXDOG_XAI_RESPONSES_WARMUP
152
+ ?? process.env.MIXDOG_XAI_WS_WARMUP;
153
+ if (raw != null && raw !== '') {
154
+ const mode = String(raw).trim().toLowerCase();
155
+ if (['0', 'false', 'off', 'none', 'disabled'].includes(mode)) return false;
156
+ if (['1', 'true', 'on', 'always', 'force'].includes(mode)) return true;
157
+ }
158
+ return String(instructions || '').length >= 2048 || (Array.isArray(rawTools) && rawTools.length >= 10);
159
+ }
160
+
161
+ // Codex-aligned default: no compat cache lane/serialization. Keep the override
162
+ // knobs so live probes can opt back into a bounded lane if a provider needs it.
163
+ const XAI_RESPONSES_CACHE_LANE_DEFAULT_MAX_IN_FLIGHT = 0;
164
+ const xaiResponsesCacheLanes = new Map();
165
+
166
+ function parseXaiPositiveInt(value, fallback) {
167
+ if (value == null || value === '') return fallback;
168
+ const text = String(value).trim().toLowerCase();
169
+ if (['0', 'false', 'off', 'none', 'disabled', 'unlimited', 'unbounded', 'auto'].includes(text)) return 0;
170
+ const n = Number(text);
171
+ if (!Number.isFinite(n)) return fallback;
172
+ return Math.max(0, Math.floor(n));
173
+ }
174
+
175
+ function xaiResponsesCacheLaneMaxInFlight(opts, config) {
176
+ return parseXaiPositiveInt(
177
+ opts?.xaiCacheMaxInFlight
178
+ ?? opts?.xaiResponsesCacheMaxInFlight
179
+ ?? opts?.grokCacheMaxInFlight
180
+ ?? opts?.grokResponsesCacheMaxInFlight
181
+ ?? config?.xaiCacheMaxInFlight
182
+ ?? config?.xaiResponsesCacheMaxInFlight
183
+ ?? config?.grokCacheMaxInFlight
184
+ ?? config?.grokResponsesCacheMaxInFlight
185
+ ?? process.env.MIXDOG_XAI_CACHE_MAX_INFLIGHT
186
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_MAX_INFLIGHT
187
+ ?? process.env.MIXDOG_GROK_CACHE_MAX_INFLIGHT
188
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_MAX_INFLIGHT
189
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_MAX_INFLIGHT
190
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_MAX_INFLIGHT,
191
+ XAI_RESPONSES_CACHE_LANE_DEFAULT_MAX_IN_FLIGHT,
192
+ );
193
+ }
194
+
195
+ function xaiResponsesCacheLaneQueueTimeoutMs(opts, config) {
196
+ return parseXaiPositiveInt(
197
+ opts?.xaiCacheQueueTimeoutMs
198
+ ?? opts?.xaiResponsesCacheQueueTimeoutMs
199
+ ?? opts?.grokCacheQueueTimeoutMs
200
+ ?? opts?.grokResponsesCacheQueueTimeoutMs
201
+ ?? config?.xaiCacheQueueTimeoutMs
202
+ ?? config?.xaiResponsesCacheQueueTimeoutMs
203
+ ?? config?.grokCacheQueueTimeoutMs
204
+ ?? config?.grokResponsesCacheQueueTimeoutMs
205
+ ?? process.env.MIXDOG_XAI_CACHE_QUEUE_TIMEOUT_MS
206
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_QUEUE_TIMEOUT_MS
207
+ ?? process.env.MIXDOG_GROK_CACHE_QUEUE_TIMEOUT_MS
208
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_QUEUE_TIMEOUT_MS
209
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_QUEUE_TIMEOUT_MS
210
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_QUEUE_TIMEOUT_MS,
211
+ 0,
212
+ );
213
+ }
214
+
215
+ function xaiResponsesPromptCacheLane(opts, config, cacheRouting) {
216
+ const shardOverride =
217
+ opts?.xaiCacheLaneShards
218
+ ?? opts?.xaiResponsesCacheLaneShards
219
+ ?? opts?.xaiCacheMaxParallel
220
+ ?? opts?.xaiResponsesCacheMaxParallel
221
+ ?? opts?.grokCacheLaneShards
222
+ ?? opts?.grokResponsesCacheLaneShards
223
+ ?? opts?.grokCacheMaxParallel
224
+ ?? opts?.grokResponsesCacheMaxParallel
225
+ ?? config?.xaiCacheLaneShards
226
+ ?? config?.xaiResponsesCacheLaneShards
227
+ ?? config?.xaiCacheMaxParallel
228
+ ?? config?.xaiResponsesCacheMaxParallel
229
+ ?? config?.grokCacheLaneShards
230
+ ?? config?.grokResponsesCacheLaneShards
231
+ ?? config?.grokCacheMaxParallel
232
+ ?? config?.grokResponsesCacheMaxParallel
233
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_MAX_PARALLEL
234
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_LANE_SHARDS
235
+ ?? process.env.MIXDOG_GROK_CACHE_MAX_PARALLEL
236
+ ?? process.env.MIXDOG_GROK_CACHE_LANE_SHARDS
237
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_MAX_PARALLEL
238
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_LANE_SHARDS
239
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_MAX_PARALLEL
240
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_LANE_SHARDS
241
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_MAX_PARALLEL
242
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_LANE_SHARDS;
243
+ const autoOverride =
244
+ opts?.xaiCacheLaneAuto
245
+ ?? opts?.xaiResponsesCacheLaneAuto
246
+ ?? opts?.grokCacheLaneAuto
247
+ ?? opts?.grokResponsesCacheLaneAuto
248
+ ?? config?.xaiCacheLaneAuto
249
+ ?? config?.xaiResponsesCacheLaneAuto
250
+ ?? config?.grokCacheLaneAuto
251
+ ?? config?.grokResponsesCacheLaneAuto
252
+ ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_LANE_AUTO
253
+ ?? process.env.MIXDOG_GROK_CACHE_LANE_AUTO
254
+ ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_LANE_AUTO
255
+ ?? process.env.MIXDOG_GROK_OAUTH_CACHE_LANE_AUTO
256
+ ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_LANE_AUTO;
257
+ const slotOverride =
258
+ opts?.xaiCacheLaneSlot
259
+ ?? opts?.xaiResponsesCacheLaneSlot
260
+ ?? opts?.grokCacheLaneSlot
261
+ ?? opts?.grokResponsesCacheLaneSlot;
262
+ const seed = String(
263
+ opts?.xaiCacheLaneSeed
264
+ ?? opts?.xaiResponsesCacheLaneSeed
265
+ ?? opts?.grokCacheLaneSeed
266
+ ?? opts?.grokResponsesCacheLaneSeed
267
+ ?? opts?.promptCacheLaneSeed
268
+ ?? opts?.sessionId
269
+ ?? opts?.session?.id
270
+ ?? cacheRouting?.ownerSessionHash
271
+ ?? cacheRouting?.key
272
+ ?? '',
273
+ );
274
+ return resolveProviderPromptCacheLane('xai', {
275
+ ...opts,
276
+ ...(shardOverride !== undefined ? { promptCacheLaneShards: shardOverride } : {}),
277
+ ...(autoOverride !== undefined ? { promptCacheLaneAuto: autoOverride } : {}),
278
+ ...(slotOverride !== undefined ? { promptCacheLaneSlot: slotOverride } : {}),
279
+ promptCacheLaneSeed: seed || 'xai-cache-lane',
280
+ }, config);
281
+ }
282
+
283
+ function xaiResponsesCacheLaneKey({ model, cacheRouting, opts, config }) {
284
+ const prefix = cacheRouting?.prefixHash || cacheRouting?.seedHash || cacheRouting?.key || 'unknown-prefix';
285
+ const lane = xaiResponsesPromptCacheLane(opts, config, cacheRouting);
286
+ const shard = Number.isFinite(Number(lane?.slot)) ? Number(lane.slot) : 0;
287
+ return {
288
+ key: `xai-responses:${model || 'default'}:${prefix}:shard-${shard}`,
289
+ shard,
290
+ lane,
291
+ };
292
+ }
293
+
294
+ function getXaiResponsesCacheLaneState(key, maxInFlight) {
295
+ let state = xaiResponsesCacheLanes.get(key);
296
+ if (!state) {
297
+ state = { key, active: 0, queue: [], maxInFlight, nextId: 0 };
298
+ xaiResponsesCacheLanes.set(key, state);
299
+ }
300
+ state.maxInFlight = maxInFlight;
301
+ return state;
302
+ }
303
+
304
+ function cleanupXaiResponsesCacheLane(state) {
305
+ if (state.active === 0 && state.queue.length === 0) {
306
+ xaiResponsesCacheLanes.delete(state.key);
307
+ }
308
+ }
309
+
310
+ function removeQueuedXaiCacheLaneRequest(state, request) {
311
+ const index = state.queue.indexOf(request);
312
+ if (index >= 0) state.queue.splice(index, 1);
313
+ cleanupXaiResponsesCacheLane(state);
314
+ }
315
+
316
+ function makeXaiCacheLaneHandle(state, requestId, enqueuedAt) {
317
+ let released = false;
318
+ return {
319
+ requestId,
320
+ waitedMs: Date.now() - enqueuedAt,
321
+ activeCount: state.active,
322
+ queueDepth: state.queue.length,
323
+ release() {
324
+ if (released) return;
325
+ released = true;
326
+ releaseXaiResponsesCacheLane(state);
327
+ },
328
+ };
329
+ }
330
+
331
+ function releaseXaiResponsesCacheLane(state) {
332
+ state.active = Math.max(0, state.active - 1);
333
+ while (state.queue.length > 0 && state.active < state.maxInFlight) {
334
+ const next = state.queue.shift();
335
+ next.cleanup?.();
336
+ state.active += 1;
337
+ next.resolve(makeXaiCacheLaneHandle(state, next.requestId, next.enqueuedAt));
338
+ }
339
+ cleanupXaiResponsesCacheLane(state);
340
+ }
341
+
342
+ function acquireXaiResponsesCacheLane({ key, maxInFlight, signal, timeoutMs }) {
343
+ const state = getXaiResponsesCacheLaneState(key, maxInFlight);
344
+ const requestId = ++state.nextId;
345
+ const enqueuedAt = Date.now();
346
+ if (state.active < state.maxInFlight) {
347
+ state.active += 1;
348
+ return Promise.resolve(makeXaiCacheLaneHandle(state, requestId, enqueuedAt));
349
+ }
350
+ return new Promise((resolve, reject) => {
351
+ const request = {
352
+ requestId,
353
+ enqueuedAt,
354
+ resolve,
355
+ reject,
356
+ cleanup: null,
357
+ };
358
+ const cleanup = () => {
359
+ if (request.timer) clearTimeout(request.timer);
360
+ if (signal && request.abortListener) signal.removeEventListener('abort', request.abortListener);
361
+ };
362
+ request.cleanup = cleanup;
363
+ request.abortListener = () => {
364
+ cleanup();
365
+ removeQueuedXaiCacheLaneRequest(state, request);
366
+ const reason = signal?.reason;
367
+ reject(reason instanceof Error ? reason : new Error('xAI cache lane wait aborted'));
368
+ };
369
+ if (signal?.aborted) {
370
+ request.abortListener();
371
+ return;
372
+ }
373
+ if (signal) signal.addEventListener('abort', request.abortListener, { once: true });
374
+ if (timeoutMs > 0) {
375
+ request.timer = setTimeout(() => {
376
+ cleanup();
377
+ removeQueuedXaiCacheLaneRequest(state, request);
378
+ reject(new Error(`xAI cache lane wait timed out after ${timeoutMs}ms`));
379
+ }, timeoutMs);
380
+ request.timer.unref?.();
381
+ }
382
+ state.queue.push(request);
383
+ });
384
+ }
385
+
386
+ function traceXaiCacheLane(opts, payload) {
387
+ if (!compatCacheTraceEnabled('xai')) return;
388
+ try {
389
+ appendAgentTrace({
390
+ sessionId: opts?.sessionId || opts?.session?.id || null,
391
+ iteration: Number.isFinite(Number(opts?.iteration)) ? Number(opts.iteration) : null,
392
+ kind: 'cache_lane',
393
+ ...payload,
394
+ payload,
395
+ });
396
+ } catch {}
397
+ }
398
+
399
+ export async function withXaiResponsesCacheLane({ opts, config, cacheRouting, model, transport, previousResponseId, inputCount, signal }, fn) {
400
+ const maxInFlight = xaiResponsesCacheLaneMaxInFlight(opts, config);
401
+ if (maxInFlight <= 0) {
402
+ const laneMeta = { enabled: false, maxInFlight: 0 };
403
+ return { value: await fn(laneMeta), laneMeta };
404
+ }
405
+ const { key: laneKey, shard, lane } = xaiResponsesCacheLaneKey({ model, cacheRouting, opts, config });
406
+ const timeoutMs = xaiResponsesCacheLaneQueueTimeoutMs(opts, config);
407
+ const state = getXaiResponsesCacheLaneState(laneKey, maxInFlight);
408
+ const queued = state.active >= state.maxInFlight;
409
+ if (queued) {
410
+ traceXaiCacheLane(opts, {
411
+ provider: 'xai',
412
+ api: 'responses',
413
+ transport,
414
+ event: 'queued',
415
+ lane_key_hash: traceHash(laneKey),
416
+ lane_shard: shard,
417
+ lane_shards: Number.isFinite(Number(lane?.shards)) ? Number(lane.shards) : null,
418
+ lane_auto: lane?.auto === true,
419
+ lane_seed_hash: lane?.seedHash || null,
420
+ max_in_flight: maxInFlight,
421
+ active: state.active,
422
+ queue_depth: state.queue.length,
423
+ previous_response_used: !!previousResponseId,
424
+ input_count: inputCount,
425
+ });
426
+ }
427
+ const handle = await acquireXaiResponsesCacheLane({ key: laneKey, maxInFlight, signal, timeoutMs });
428
+ const laneMeta = {
429
+ enabled: true,
430
+ laneKeyHash: traceHash(laneKey),
431
+ shard,
432
+ shards: Number.isFinite(Number(lane?.shards)) ? Number(lane.shards) : null,
433
+ auto: lane?.auto === true,
434
+ seedHash: lane?.seedHash || null,
435
+ maxInFlight,
436
+ queued,
437
+ waitMs: handle.waitedMs,
438
+ activeAfterAcquire: handle.activeCount,
439
+ queueDepthAfterAcquire: handle.queueDepth,
440
+ };
441
+ traceXaiCacheLane(opts, {
442
+ provider: 'xai',
443
+ api: 'responses',
444
+ transport,
445
+ event: 'acquired',
446
+ lane_key_hash: laneMeta.laneKeyHash,
447
+ lane_shard: shard,
448
+ lane_shards: laneMeta.shards,
449
+ lane_auto: laneMeta.auto,
450
+ lane_seed_hash: laneMeta.seedHash,
451
+ max_in_flight: maxInFlight,
452
+ wait_ms: laneMeta.waitMs,
453
+ active: laneMeta.activeAfterAcquire,
454
+ queue_depth: laneMeta.queueDepthAfterAcquire,
455
+ previous_response_used: !!previousResponseId,
456
+ input_count: inputCount,
457
+ });
458
+ const startedAt = Date.now();
459
+ try {
460
+ return { value: await fn(laneMeta), laneMeta };
461
+ } finally {
462
+ handle.release();
463
+ traceXaiCacheLane(opts, {
464
+ provider: 'xai',
465
+ api: 'responses',
466
+ transport,
467
+ event: 'released',
468
+ lane_key_hash: laneMeta.laneKeyHash,
469
+ lane_shard: shard,
470
+ lane_shards: laneMeta.shards,
471
+ lane_auto: laneMeta.auto,
472
+ lane_seed_hash: laneMeta.seedHash,
473
+ max_in_flight: maxInFlight,
474
+ held_ms: Date.now() - startedAt,
475
+ previous_response_used: !!previousResponseId,
476
+ input_count: inputCount,
477
+ });
478
+ }
479
+ }
480
+
481
+ export function deterministicUuidFromKey(key) {
482
+ const hex = createHash('sha256').update(String(key ?? '')).digest('hex');
483
+ const variant = ((Number.parseInt(hex[16], 16) & 0x3) | 0x8).toString(16);
484
+ return [
485
+ hex.slice(0, 8),
486
+ hex.slice(8, 12),
487
+ '4' + hex.slice(13, 16),
488
+ variant + hex.slice(17, 20),
489
+ hex.slice(20, 32),
490
+ ].join('-');
491
+ }
492
+
493
+ export function compatCacheTraceEnabled(provider) {
494
+ return process.env.MIXDOG_COMPAT_CACHE_TRACE === '1'
495
+ || process.env.MIXDOG_PROVIDER_CACHE_TRACE === '1'
496
+ || (provider === 'xai' && process.env.MIXDOG_XAI_CACHE_TRACE === '1');
497
+ }
498
+
499
+ export function writeCompatCacheTrace({ provider, model, opts, params, rawTools, response, cacheRoutingKey, cacheRouting }) {
500
+ if (!compatCacheTraceEnabled(provider)) return;
501
+ try {
502
+ const usage = response?.usage || {};
503
+ const inputTokens = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0);
504
+ const cachedTokens = extractCompatCachedTokens(usage);
505
+ const toolShape = summarizeTraceTools(rawTools);
506
+ const traceMessages = Array.isArray(params?.messages) ? params.messages : [];
507
+ const trace = {
508
+ event: 'chat.completions',
509
+ provider,
510
+ model,
511
+ responseModel: response?.model || null,
512
+ owner: opts?.session?.owner || null,
513
+ role: opts?.session?.role || opts?.role || null,
514
+ permission: opts?.session?.permission || null,
515
+ toolPermission: opts?.session?.toolPermission || null,
516
+ profileId: opts?.session?.profileId || null,
517
+ sourceType: opts?.session?.sourceType || null,
518
+ sourceName: opts?.session?.sourceName || null,
519
+ sessionIdHash: opts?.sessionId ? traceHash(opts.sessionId) : null,
520
+ providerCacheKeyHash: opts?.providerCacheKey ? traceHash(opts.providerCacheKey) : null,
521
+ promptCacheKeyHash: opts?.promptCacheKey ? traceHash(opts.promptCacheKey) : null,
522
+ xGrokConvIdHash: provider === 'xai' && cacheRoutingKey ? traceHash(cacheRoutingKey) : null,
523
+ xGrokConvIdSeedHash: provider === 'xai' ? cacheRouting?.seedHash || null : null,
524
+ xGrokPromptPrefixHash: provider === 'xai' ? cacheRouting?.prefixHash || null : null,
525
+ xGrokConvIdMode: provider === 'xai' ? cacheRouting?.mode || null : null,
526
+ xGrokConvIdLaneIndex: provider === 'xai' ? cacheRouting?.laneIndex ?? null : null,
527
+ xGrokConvIdActiveLanes: provider === 'xai' ? cacheRouting?.activeLanes ?? null : null,
528
+ xGrokConvIdIdleLanes: provider === 'xai' ? cacheRouting?.idleLanes ?? null : null,
529
+ xGrokConvIdOwnerSessionHash: provider === 'xai' ? cacheRouting?.ownerSessionHash || null : null,
530
+ xaiReasoningEffort: provider === 'xai' ? params?.reasoning_effort || null : null,
531
+ messageCount: traceMessages.length,
532
+ messageFullHash: traceHash(stableTraceStringify(traceMessages)),
533
+ messagePrefixHash: traceHash(stableTraceStringify(traceMessages.slice(0, -1))),
534
+ lastMessageHash: traceMessages.length ? traceHash(stableTraceStringify(traceMessages.at(-1))) : null,
535
+ messages: summarizeTraceMessages(traceMessages),
536
+ toolCount: Array.isArray(rawTools) ? rawTools.length : 0,
537
+ toolSchemaHash: traceHash(stableTraceStringify(toolShape)),
538
+ usageKeys: Object.keys(usage || {}).sort(),
539
+ promptTokenDetailsKeys: Object.keys(usage?.prompt_tokens_details || {}).sort(),
540
+ inputTokenDetailsKeys: Object.keys(usage?.input_tokens_details || {}).sort(),
541
+ choiceMessageKeys: Object.keys(response?.choices?.[0]?.message || {}).sort(),
542
+ responseReasoningContent: typeof response?.choices?.[0]?.message?.reasoning_content === 'string'
543
+ ? traceTextShape(response.choices[0].message.reasoning_content)
544
+ : null,
545
+ responseReasoningTokens: Number(usage?.completion_tokens_details?.reasoning_tokens ?? 0),
546
+ inputTokens,
547
+ outputTokens: Number(usage.completion_tokens ?? usage.output_tokens ?? 0),
548
+ cachedTokens,
549
+ cacheHitRate: inputTokens > 0 ? Number((cachedTokens / inputTokens).toFixed(6)) : null,
550
+ costInUsdTicks: typeof usage.cost_in_usd_ticks === 'number' ? usage.cost_in_usd_ticks : null,
551
+ };
552
+ process.stderr.write(`[compat-cache-trace] ${JSON.stringify(trace)}\n`);
553
+ } catch (err) {
554
+ process.stderr.write(`[compat-cache-trace] failed: ${err?.message || err}\n`);
555
+ }
556
+ }
557
+
558
+ function summarizeResponsesInput(input) {
559
+ return (input || []).map((item, index) => ({
560
+ index,
561
+ type: item?.type || null,
562
+ role: item?.role || null,
563
+ callIdHash: item?.call_id ? traceHash(item.call_id) : null,
564
+ name: item?.name || null,
565
+ content: typeof item?.content === 'string'
566
+ ? { type: 'text', ...traceTextShape(item.content) }
567
+ : { type: item?.content == null ? 'null' : typeof item.content, hash: traceHash(stableTraceStringify(item?.content ?? null)) },
568
+ output: typeof item?.output === 'string' ? traceTextShape(item.output) : null,
569
+ }));
570
+ }
571
+
572
+ function xaiUsageStats(usage) {
573
+ const inputTokens = Number(usage?.input_tokens ?? usage?.prompt_tokens ?? 0);
574
+ const outputTokens = Number(usage?.output_tokens ?? usage?.completion_tokens ?? 0);
575
+ const cachedTokens = extractCompatCachedTokens(usage);
576
+ const hitRate = inputTokens > 0 ? Number((cachedTokens / inputTokens).toFixed(6)) : null;
577
+ return { inputTokens, outputTokens, cachedTokens, hitRate };
578
+ }
579
+
580
+ function xaiSanitizedRequestSansInput(params) {
581
+ const { input: _input, ...rest } = params || {};
582
+ const out = { ...rest };
583
+ if (out.prompt_cache_key) out.prompt_cache_key = traceHash(out.prompt_cache_key);
584
+ if (out.previous_response_id) out.previous_response_id = traceHash(out.previous_response_id);
585
+ if (typeof out.instructions === 'string') out.instructions = traceHash(out.instructions);
586
+ return out;
587
+ }
588
+
589
+ function xaiResponsesFingerprintPayload({ model, opts, params, rawTools, response, cacheRouting, previousResponseId, inputStartIndex, continuationResetReason, transport, cacheLane }) {
590
+ const usage = response?.usage || {};
591
+ const { inputTokens, outputTokens, cachedTokens, hitRate } = xaiUsageStats(usage);
592
+ const toolShape = summarizeTraceTools(rawTools);
593
+ const instructions = typeof params?.instructions === 'string' ? params.instructions : '';
594
+ const requestSansInput = xaiSanitizedRequestSansInput(params);
595
+ const contextShape = {
596
+ provider: 'xai',
597
+ api: 'responses',
598
+ model: model || null,
599
+ promptCacheKeyHash: params?.prompt_cache_key ? traceHash(params.prompt_cache_key) : null,
600
+ instructions,
601
+ tools: toolShape,
602
+ reasoning: params?.reasoning || null,
603
+ store: params?.store ?? null,
604
+ };
605
+ const previousResponseUsed = Boolean(previousResponseId);
606
+ const midTurnCold = previousResponseUsed
607
+ && inputTokens >= 1024
608
+ && (cachedTokens <= 512 || (hitRate != null && hitRate < 0.1));
609
+ return {
610
+ provider: 'xai',
611
+ api: 'responses',
612
+ transport: transport || null,
613
+ model: model || null,
614
+ response_model: response?.model || null,
615
+ session_id_hash: opts?.sessionId ? traceHash(opts.sessionId) : null,
616
+ provider_cache_key_hash: opts?.providerCacheKey ? traceHash(opts.providerCacheKey) : null,
617
+ prompt_cache_key_option_hash: opts?.promptCacheKey ? traceHash(opts.promptCacheKey) : null,
618
+ prompt_cache_key_hash: params?.prompt_cache_key ? traceHash(params.prompt_cache_key) : null,
619
+ xai_prompt_prefix_hash: cacheRouting?.prefixHash || null,
620
+ xai_cache_mode: cacheRouting?.mode || null,
621
+ xai_cache_seed_hash: cacheRouting?.seedHash || null,
622
+ owner_session_hash: cacheRouting?.ownerSessionHash || null,
623
+ response_id_hash: response?.id ? traceHash(response.id) : null,
624
+ previous_response_id_hash: previousResponseId ? traceHash(previousResponseId) : null,
625
+ previous_response_used: previousResponseUsed,
626
+ continuation_reset_reason: continuationResetReason || null,
627
+ input_start_index: inputStartIndex,
628
+ input_count: Array.isArray(params?.input) ? params.input.length : 0,
629
+ input_hash: traceHash(stableTraceStringify(params?.input || [])),
630
+ request_sans_input_hash: traceHash(stableTraceStringify(requestSansInput)),
631
+ context_prefix_hash: traceHash(stableTraceStringify(contextShape)),
632
+ has_instructions: instructions.length > 0,
633
+ instructions_chars: instructions.length,
634
+ instructions_hash: instructions ? traceHash(instructions) : null,
635
+ reasoning_effort: params?.reasoning?.effort || null,
636
+ tool_count: Array.isArray(rawTools) ? rawTools.length : 0,
637
+ tool_schema_hash: traceHash(stableTraceStringify(toolShape)),
638
+ tool_names_hash: traceHash(stableTraceStringify(toolShape.map(t => t?.name || null))),
639
+ xai_cache_lane_enabled: cacheLane?.enabled === true,
640
+ xai_cache_lane_hash: cacheLane?.laneKeyHash || null,
641
+ xai_cache_lane_shard: Number.isFinite(Number(cacheLane?.shard)) ? Number(cacheLane.shard) : null,
642
+ xai_cache_lane_shards: Number.isFinite(Number(cacheLane?.shards)) ? Number(cacheLane.shards) : null,
643
+ xai_cache_lane_auto: cacheLane?.auto === true,
644
+ xai_cache_lane_seed_hash: cacheLane?.seedHash || null,
645
+ xai_cache_lane_max_in_flight: Number.isFinite(Number(cacheLane?.maxInFlight)) ? Number(cacheLane.maxInFlight) : null,
646
+ xai_cache_lane_wait_ms: Number.isFinite(Number(cacheLane?.waitMs)) ? Number(cacheLane.waitMs) : null,
647
+ xai_cache_lane_queued: cacheLane?.queued === true,
648
+ input_tokens: inputTokens,
649
+ output_tokens: outputTokens,
650
+ cached_tokens: cachedTokens,
651
+ cache_hit_rate: hitRate,
652
+ mid_turn_cold: midTurnCold,
653
+ };
654
+ }
655
+
656
+ export function traceXaiResponsesCacheContext(args) {
657
+ if (!compatCacheTraceEnabled('xai')) return;
658
+ try {
659
+ const payload = xaiResponsesFingerprintPayload(args);
660
+ const sessionId = args?.opts?.sessionId || args?.opts?.session?.id || null;
661
+ const iteration = Number.isFinite(Number(args?.opts?.iteration)) ? Number(args.opts.iteration) : null;
662
+ appendAgentTrace({
663
+ sessionId,
664
+ iteration,
665
+ kind: 'cache_context',
666
+ ...payload,
667
+ payload,
668
+ });
669
+ if (payload.mid_turn_cold) {
670
+ const anomalyPayload = {
671
+ ...payload,
672
+ anomaly: 'xai_mid_turn_cold_cache',
673
+ reason: 'previous_response_id_present_but_cached_tokens_low',
674
+ };
675
+ appendAgentTrace({
676
+ sessionId,
677
+ iteration,
678
+ kind: 'cache_anomaly',
679
+ ...anomalyPayload,
680
+ payload: anomalyPayload,
681
+ });
682
+ }
683
+ } catch (err) {
684
+ process.stderr.write(`[compat-cache-trace] xai context trace failed: ${err?.message || err}\n`);
685
+ }
686
+ }
687
+
688
+ export function writeXaiResponsesCacheTrace({ model, opts, params, rawTools, response, cacheRouting, previousResponseId, inputStartIndex, continuationResetReason, transport, cacheLane }) {
689
+ if (!compatCacheTraceEnabled('xai')) return;
690
+ try {
691
+ const usage = response?.usage || {};
692
+ const fingerprint = xaiResponsesFingerprintPayload({
693
+ model,
694
+ opts,
695
+ params,
696
+ rawTools,
697
+ response,
698
+ cacheRouting,
699
+ previousResponseId,
700
+ inputStartIndex,
701
+ continuationResetReason,
702
+ transport,
703
+ cacheLane,
704
+ });
705
+ const inputTokens = fingerprint.input_tokens;
706
+ const cachedTokens = fingerprint.cached_tokens;
707
+ const toolShape = summarizeTraceTools(rawTools);
708
+ const trace = {
709
+ event: 'responses',
710
+ provider: 'xai',
711
+ transport: transport || null,
712
+ model,
713
+ responseModel: response?.model || null,
714
+ responseIdHash: response?.id ? traceHash(response.id) : null,
715
+ previousResponseIdHash: previousResponseId ? traceHash(previousResponseId) : null,
716
+ owner: opts?.session?.owner || null,
717
+ role: opts?.session?.role || opts?.role || null,
718
+ permission: opts?.session?.permission || null,
719
+ toolPermission: opts?.session?.toolPermission || null,
720
+ profileId: opts?.session?.profileId || null,
721
+ sourceType: opts?.session?.sourceType || null,
722
+ sourceName: opts?.session?.sourceName || null,
723
+ sessionIdHash: opts?.sessionId ? traceHash(opts.sessionId) : null,
724
+ promptCacheKeyHash: params?.prompt_cache_key ? traceHash(params.prompt_cache_key) : null,
725
+ xGrokPromptPrefixHash: cacheRouting?.prefixHash || null,
726
+ xGrokConvIdMode: cacheRouting?.mode || null,
727
+ xaiReasoningEffort: params?.reasoning?.effort || null,
728
+ previousResponseUsed: Boolean(previousResponseId),
729
+ inputStartIndex,
730
+ inputCount: Array.isArray(params?.input) ? params.input.length : 0,
731
+ cacheLaneEnabled: fingerprint.xai_cache_lane_enabled,
732
+ cacheLaneHash: fingerprint.xai_cache_lane_hash,
733
+ cacheLaneShard: fingerprint.xai_cache_lane_shard,
734
+ cacheLaneMaxInFlight: fingerprint.xai_cache_lane_max_in_flight,
735
+ cacheLaneWaitMs: fingerprint.xai_cache_lane_wait_ms,
736
+ cacheLaneQueued: fingerprint.xai_cache_lane_queued,
737
+ input: summarizeResponsesInput(params?.input || []),
738
+ toolCount: Array.isArray(rawTools) ? rawTools.length : 0,
739
+ toolSchemaHash: traceHash(stableTraceStringify(toolShape)),
740
+ toolNamesHash: fingerprint.tool_names_hash,
741
+ requestSansInputHash: fingerprint.request_sans_input_hash,
742
+ contextPrefixHash: fingerprint.context_prefix_hash,
743
+ instructionsHash: fingerprint.instructions_hash,
744
+ instructionsChars: fingerprint.instructions_chars,
745
+ usageKeys: Object.keys(usage || {}).sort(),
746
+ inputTokenDetailsKeys: Object.keys(usage?.input_tokens_details || {}).sort(),
747
+ outputTokenDetailsKeys: Object.keys(usage?.output_tokens_details || {}).sort(),
748
+ outputTypes: (response?.output || []).map(item => item?.type || null),
749
+ inputTokens,
750
+ outputTokens: fingerprint.output_tokens,
751
+ cachedTokens,
752
+ cacheHitRate: fingerprint.cache_hit_rate,
753
+ midTurnCold: fingerprint.mid_turn_cold,
754
+ costInUsdTicks: typeof usage.cost_in_usd_ticks === 'number' ? usage.cost_in_usd_ticks : null,
755
+ };
756
+ process.stderr.write(`[compat-cache-trace] ${JSON.stringify(trace)}\n`);
757
+ } catch (err) {
758
+ process.stderr.write(`[compat-cache-trace] failed: ${err?.message || err}\n`);
759
+ }
760
+ }