mixdog 0.9.2 → 0.9.4

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 (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  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/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. 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
+ }