mixdog 0.9.147 → 0.9.148

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 (255) hide show
  1. package/package.json +23 -3
  2. package/scripts/build-voice-runtime-unix.sh +101 -0
  3. package/scripts/embedding-quality-probe.mjs +96 -0
  4. package/scripts/generate-voice-runtime-manifest.mjs +300 -0
  5. package/scripts/generate-voice-runtime-manifest.test.mjs +135 -0
  6. package/scripts/native-binary-arch.mjs +30 -13
  7. package/scripts/native-binary-arch.test.mjs +40 -4
  8. package/scripts/plan-voice-runtime-release.mjs +73 -0
  9. package/scripts/prepare-native-assets.mjs +50 -9
  10. package/scripts/prune-embedding-runtime.mjs +3 -3
  11. package/scripts/sync-voice-runtime-manifest.mjs +46 -0
  12. package/scripts/verify-release-assets.mjs +106 -6
  13. package/scripts/verify-voice-runtime-release.mjs +89 -0
  14. package/scripts/voice-runtime-config.json +52 -0
  15. package/src/app.mjs +42 -5
  16. package/src/headless-exec.mjs +58 -32
  17. package/src/headless-exec.test.mjs +74 -13
  18. package/src/rules/lead/01-general.md +2 -0
  19. package/src/rules/shared/10-tool-workflow.md +7 -4
  20. package/src/rules/shared/30-exploration.md +2 -1
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +28 -9
  22. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +6 -1
  23. package/src/runtime/agent/orchestrator/config.mjs +53 -18
  24. package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +139 -0
  25. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +34 -5
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -10
  27. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +98 -0
  29. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +90 -0
  30. package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +67 -16
  31. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +4 -82
  32. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +0 -5
  33. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +62 -121
  34. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +48 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +215 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +44 -48
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +54 -31
  38. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +56 -2
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +34 -2
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +61 -1
  41. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -1
  42. package/src/runtime/agent/orchestrator/providers/gemini.mjs +61 -15
  43. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +120 -1
  44. package/src/runtime/agent/orchestrator/providers/lib/env-utils.mjs +9 -0
  45. package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +0 -3
  46. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +187 -84
  47. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +36 -36
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +16 -6
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +50 -213
  50. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +135 -126
  51. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +17 -11
  52. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +20 -7
  53. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +11 -0
  54. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +132 -42
  55. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
  56. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +28 -10
  57. package/src/runtime/agent/orchestrator/providers/registry.mjs +122 -95
  58. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +58 -3
  59. package/src/runtime/agent/orchestrator/providers/tool-stream-state.mjs +4 -22
  60. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +7 -14
  61. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +128 -0
  62. package/src/runtime/agent/orchestrator/session/context-compaction-policy.mjs +5 -0
  63. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +27 -48
  64. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +19 -14
  65. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +9 -43
  66. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +5 -1
  67. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +15 -2
  68. package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +325 -0
  69. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +599 -195
  70. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +22 -0
  71. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +9 -2
  72. package/src/runtime/agent/orchestrator/session/manager.mjs +3 -0
  73. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +26 -16
  74. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +23 -11
  75. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +118 -3
  76. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +332 -0
  77. package/src/runtime/agent/orchestrator/session/store.mjs +38 -1
  78. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +27 -6
  79. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -20
  80. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +291 -128
  81. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +45 -8
  82. package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +224 -0
  83. package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +53 -3
  84. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +255 -25
  85. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +87 -0
  86. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +1 -1
  87. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +132 -9
  88. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-pattern-fanout.mjs +29 -3
  90. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +178 -29
  92. package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +4 -1
  93. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +32 -5
  94. package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +5 -2
  95. package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +10 -1
  96. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +38 -10
  97. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +31 -1
  99. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +11 -1
  100. package/src/runtime/agent/orchestrator/tools/builtin/read-windows.mjs +22 -4
  101. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +6 -8
  102. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +25 -24
  103. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +152 -133
  104. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +114 -42
  105. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +129 -15
  106. package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +72 -0
  107. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +7 -8
  108. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +4 -4
  109. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +201 -19
  110. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +26 -3
  111. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +10 -1
  112. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +55 -0
  113. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +115 -25
  114. package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +268 -0
  115. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +3 -3
  116. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +296 -46
  117. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +104 -0
  118. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +136 -0
  119. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +127 -38
  120. package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +661 -0
  121. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +350 -9
  122. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +418 -44
  123. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +27 -3
  124. package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +552 -0
  125. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +65 -15
  126. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
  127. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +284 -109
  128. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +51 -21
  129. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +44 -27
  130. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +6 -1
  131. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
  132. package/src/runtime/attachments/store.mjs +11 -3
  133. package/src/runtime/channels/data/voice-runtime-manifest.json +46 -70
  134. package/src/runtime/channels/lib/event-queue.mjs +51 -41
  135. package/src/runtime/channels/lib/scheduler.mjs +23 -28
  136. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -17
  137. package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +17 -0
  138. package/src/runtime/channels/lib/webhook.mjs +39 -20
  139. package/src/runtime/channels/lib/whisper-server.mjs +46 -1
  140. package/src/runtime/channels/lib/worker-main.mjs +3 -1
  141. package/src/runtime/media/adapters/gemini-video.mjs +20 -4
  142. package/src/runtime/media/jobs.mjs +13 -0
  143. package/src/runtime/media/renditions.mjs +7 -1
  144. package/src/runtime/media/store.mjs +42 -22
  145. package/src/runtime/memory/index.mjs +4 -9
  146. package/src/runtime/memory/lib/agent-ipc.mjs +1 -6
  147. package/src/runtime/memory/lib/archive-security.test.mjs +21 -1
  148. package/src/runtime/memory/lib/core-memory-store.mjs +28 -50
  149. package/src/runtime/memory/lib/embedding-model-config.mjs +37 -1
  150. package/src/runtime/memory/lib/embedding-model-config.test.mjs +33 -0
  151. package/src/runtime/memory/lib/embedding-provider.mjs +34 -12
  152. package/src/runtime/memory/lib/embedding-worker.mjs +37 -5
  153. package/src/runtime/memory/lib/ko-morph.mjs +46 -15
  154. package/src/runtime/memory/lib/memory-action-handlers.mjs +18 -1
  155. package/src/runtime/memory/lib/memory-cycle1.mjs +1 -18
  156. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -18
  157. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +98 -45
  158. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +71 -0
  159. package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +78 -0
  160. package/src/runtime/memory/lib/memory-cycle2.mjs +37 -3
  161. package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
  162. package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +50 -0
  163. package/src/runtime/memory/lib/memory-recall-store.mjs +9 -24
  164. package/src/runtime/memory/lib/memory.mjs +50 -12
  165. package/src/runtime/memory/lib/pg/process.mjs +1 -10
  166. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -9
  167. package/src/runtime/memory/lib/query-handlers.mjs +2 -4
  168. package/src/runtime/memory/lib/session-ingest-runtime.mjs +2 -2
  169. package/src/runtime/shared/background-tasks.mjs +15 -0
  170. package/src/runtime/shared/background-tasks.test.mjs +78 -0
  171. package/src/runtime/shared/child-guardian.mjs +2 -10
  172. package/src/runtime/shared/pid-liveness.mjs +27 -0
  173. package/src/runtime/shared/runtime-root.mjs +1 -11
  174. package/src/runtime/shared/service-discovery.mjs +1 -17
  175. package/src/runtime/shared/singleton-owner.mjs +1 -11
  176. package/src/runtime/shared/staged-update.mjs +2 -12
  177. package/src/runtime/shared/tool-status.mjs +5 -1
  178. package/src/runtime/shared/tool-surface.mjs +15 -7
  179. package/src/runtime/shared/turn-snapshot-store.mjs +168 -0
  180. package/src/runtime/shared/turn-snapshot.mjs +137 -13
  181. package/src/runtime/shared/turn-worktree-snapshot.mjs +110 -18
  182. package/src/runtime/shared/webhook-session-run.mjs +16 -2
  183. package/src/runtime/web-search/lib/http-fetch.mjs +34 -4
  184. package/src/runtime/web-search/lib/state.mjs +15 -15
  185. package/src/runtime/web-search/lib/web-tools.mjs +46 -5
  186. package/src/session-runtime/context-status.mjs +4 -12
  187. package/src/session-runtime/runtime-core.mjs +20 -1
  188. package/src/standalone/agent-dispatch-broker.mjs +33 -2
  189. package/src/standalone/agent-tool/job-task-reconcile.mjs +78 -0
  190. package/src/standalone/agent-tool/notify.mjs +3 -1
  191. package/src/standalone/agent-tool/spawn-flow.mjs +48 -66
  192. package/src/standalone/agent-tool/tag-registry.mjs +116 -33
  193. package/src/standalone/agent-tool/tool-def.mjs +2 -2
  194. package/src/standalone/agent-tool/worker-index.mjs +8 -11
  195. package/src/standalone/agent-tool/worker-rows.mjs +4 -1
  196. package/src/standalone/agent-tool.mjs +20 -55
  197. package/src/standalone/agent-watchdog-registry.mjs +28 -4
  198. package/src/standalone/channel-client.mjs +47 -15
  199. package/src/standalone/channel-transport.mjs +44 -25
  200. package/src/standalone/daemon.mjs +31 -2
  201. package/src/standalone/hook-bus/config.mjs +25 -9
  202. package/src/standalone/hook-bus/handlers.mjs +16 -52
  203. package/src/standalone/hook-bus.mjs +29 -23
  204. package/src/standalone/memory-runtime-proxy.mjs +1 -16
  205. package/src/standalone/session-client.mjs +86 -23
  206. package/src/standalone/session-protocol.mjs +0 -2
  207. package/src/standalone/session-runtime-host-health.test.mjs +5 -4
  208. package/src/standalone/session-runtime-host.mjs +101 -6
  209. package/src/standalone/session-runtime-record.mjs +1 -5
  210. package/src/standalone/session-runtime-worker.mjs +52 -57
  211. package/src/standalone/session-service.mjs +4 -1
  212. package/src/standalone/session-transport.mjs +56 -25
  213. package/src/tui/App.jsx +40 -49
  214. package/src/tui/app/app-view.jsx +14 -21
  215. package/src/tui/app/core-memory-picker.mjs +29 -16
  216. package/src/tui/app/create-app-pickers.mjs +15 -36
  217. package/src/tui/app/extension-pickers.mjs +60 -49
  218. package/src/tui/app/maintenance-pickers.mjs +100 -57
  219. package/src/tui/app/message-selector.mjs +6 -5
  220. package/src/tui/app/model-picker.mjs +30 -13
  221. package/src/tui/app/onboarding-steps.mjs +21 -12
  222. package/src/tui/app/panel-epoch.mjs +56 -0
  223. package/src/tui/app/panel-epoch.test.mjs +1009 -0
  224. package/src/tui/app/panel-surface.mjs +98 -0
  225. package/src/tui/app/project-picker.mjs +30 -29
  226. package/src/tui/app/prompt-submit.mjs +192 -97
  227. package/src/tui/app/prompt-submit.test.mjs +206 -0
  228. package/src/tui/app/provider-setup-picker.mjs +74 -43
  229. package/src/tui/app/resume-picker.mjs +11 -8
  230. package/src/tui/app/route-pickers.mjs +45 -28
  231. package/src/tui/app/settings-picker.mjs +69 -18
  232. package/src/tui/app/shell-layout.mjs +1 -3
  233. package/src/tui/app/slash-commands.mjs +0 -2
  234. package/src/tui/app/slash-dispatch.mjs +4 -2
  235. package/src/tui/app/text-entry-policy.mjs +25 -0
  236. package/src/tui/app/theme-effort-pickers.mjs +11 -16
  237. package/src/tui/app/usage-context-panels.mjs +21 -25
  238. package/src/tui/app/use-global-key-input.mjs +3 -2
  239. package/src/tui/app/use-prompt-draft-flow.mjs +6 -18
  240. package/src/tui/app/use-prompt-handlers.mjs +3 -2
  241. package/src/tui/app/use-welcome-prompt-hint.mjs +17 -3
  242. package/src/tui/components/Picker.jsx +1 -1
  243. package/src/tui/components/TextEntryPanel.jsx +7 -2
  244. package/src/tui/dist/index.mjs +652 -561
  245. package/src/tui/lib/voice-setup.mjs +1 -2
  246. package/src/tui/session/agent-job-feed.mjs +73 -11
  247. package/src/tui/session/session-api-ext.mjs +5 -6
  248. package/src/tui/session/session-api.mjs +1 -0
  249. package/src/tui/session/tool-approval.mjs +15 -5
  250. package/src/tui/session/tui-steering-persist.mjs +33 -19
  251. package/src/tui/session/tui-steering-persist.test.mjs +104 -0
  252. package/src/tui/session-local.mjs +0 -22
  253. package/scripts/.tmp-coverage-report.mjs +0 -96
  254. package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.mjs +0 -57
  255. package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.test.mjs +0 -57
@@ -152,11 +152,16 @@ function mergeToolCallDelta(accByIndex, deltaCalls, bucketState) {
152
152
  } else if (tc.function?.name) {
153
153
  const anonId = ++bucketState._nextAnonId;
154
154
  key = `anon:${anonId}`;
155
- bucketState._lastAnonKey = key;
156
155
  } else {
157
156
  key = bucketState._lastAnonKey;
158
157
  if (!key) continue;
159
158
  }
159
+ // Whatever bucket this chunk resolved to becomes the continuation
160
+ // target for later argument-only chunks (no index, no id, no name).
161
+ // Only the anonymous branch used to record it, so a provider that
162
+ // identifies a tool call by id alone and then streams bare argument
163
+ // deltas had every one of those deltas silently discarded.
164
+ bucketState._lastAnonKey = key;
160
165
  let prev = accByIndex.get(key);
161
166
  if (!prev) {
162
167
  prev = {
@@ -210,7 +215,7 @@ function emitCompatToolCallOnce(state, call, onToolCall) {
210
215
  // Fix 2: cross-path name+args dedupe. A synthesized text-leaked call and an
211
216
  // identical native tool_call must fire onToolCall exactly once. state._toolDedupe
212
217
  // is created per stream; when absent (older callers) behavior is unchanged.
213
- if (state._toolDedupe && !state._toolDedupe.shouldDispatch(call.name, call.arguments)) {
218
+ if (state._toolDedupe && !state._toolDedupe.shouldDispatch(call.name, call.arguments, call.id)) {
214
219
  // Still mark the id as emitted so later id-frames for the same native
215
220
  // call don't retry, but do NOT invoke onToolCall (already dispatched).
216
221
  state.emittedToolCallKeys.add(key);
@@ -556,6 +561,33 @@ export async function consumeCompatChatCompletionStream(stream, {
556
561
  };
557
562
  }
558
563
 
564
+ // Reconcile a COMPLETED function_call item into state.toolCalls: fill in the
565
+ // id/name a streamed call may still be missing, or adopt the item as a new
566
+ // call. `response.output_item.done` and the `response.completed` sweep see the
567
+ // same item shape and must land on the same single emit, so both route here.
568
+ // Returns the item id the done-branch still needs for its pendingCalls /
569
+ // tool-tracker bookkeeping.
570
+ function reconcileCompatFunctionCallItem(state, item, label, onToolCall) {
571
+ const itemId = item.id || '';
572
+ const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
573
+ || (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
574
+ if (tc) {
575
+ if (!tc.id && item.call_id) tc.id = item.call_id;
576
+ if (!tc.name && item.name) tc.name = item.name;
577
+ if (tc.id && tc.name) delete tc._pendingItemId;
578
+ emitCompatToolCallOnce(state, tc, onToolCall);
579
+ } else if (item.call_id && item.name) {
580
+ const call = {
581
+ id: item.call_id,
582
+ name: item.name,
583
+ arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
584
+ };
585
+ state.toolCalls.push(call);
586
+ emitCompatToolCallOnce(state, call, onToolCall);
587
+ }
588
+ return itemId;
589
+ }
590
+
559
591
  function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesToolCalls, responseOutputText, onStreamDelta, onToolCall, onTextDelta, relayLeakText }) {
560
592
  if (!event || typeof event.type !== 'string') return;
561
593
  const pushToolSearchCall = (item) => {
@@ -671,23 +703,7 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
671
703
  case 'response.output_item.done': {
672
704
  const item = event.item || {};
673
705
  if (item.type === 'function_call') {
674
- const itemId = item.id || '';
675
- const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
676
- || (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
677
- if (tc) {
678
- if (!tc.id && item.call_id) tc.id = item.call_id;
679
- if (!tc.name && item.name) tc.name = item.name;
680
- if (tc.id && tc.name) delete tc._pendingItemId;
681
- emitCompatToolCallOnce(state, tc, onToolCall);
682
- } else if (item.call_id && item.name) {
683
- const call = {
684
- id: item.call_id,
685
- name: item.name,
686
- arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
687
- };
688
- state.toolCalls.push(call);
689
- emitCompatToolCallOnce(state, call, onToolCall);
690
- }
706
+ const itemId = reconcileCompatFunctionCallItem(state, item, label, onToolCall);
691
707
  // Drop the resolved function item from pendingCalls before
692
708
  // recomputing toolInFlight — otherwise a completed call keeps
693
709
  // pendingCalls.size > 0 and the latch never clears, so a later
@@ -732,23 +748,7 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
732
748
  }
733
749
  for (const item of resp.output || []) {
734
750
  if (item?.type === 'function_call') {
735
- const itemId = item.id || '';
736
- const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
737
- || (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
738
- if (tc) {
739
- if (!tc.id && item.call_id) tc.id = item.call_id;
740
- if (!tc.name && item.name) tc.name = item.name;
741
- if (tc.id && tc.name) delete tc._pendingItemId;
742
- emitCompatToolCallOnce(state, tc, onToolCall);
743
- } else if (item.call_id && item.name) {
744
- const call = {
745
- id: item.call_id,
746
- name: item.name,
747
- arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
748
- };
749
- state.toolCalls.push(call);
750
- emitCompatToolCallOnce(state, call, onToolCall);
751
- }
751
+ reconcileCompatFunctionCallItem(state, item, label, onToolCall);
752
752
  try { onStreamDelta?.('tool'); } catch {}
753
753
  reportedBundleProgress = true;
754
754
  } else if (item?.type === 'tool_search_call') {
@@ -44,13 +44,15 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
44
44
  // strict providers (xai) reject unknown roles/types and would 400 the
45
45
  // request. Documented in v0.1.160 (GPT reasoning replay).
46
46
  //
47
- // DeepSeek thinking models require the prior turn's `reasoning_content`
48
- // string to be echoed back inside the assistant message, otherwise the API
49
- // returns 400. xAI reasoning models also preserve their official multi-turn
50
- // shape and cache prefix stability when prior assistant reasoning_content
51
- // is replayed; reasoning_effort itself remains caller/user-selected.
47
+ // DeepSeek splits by model: thinking-mode models with tools REQUIRE the
48
+ // prior turn's `reasoning_content` echoed back (400 without it), while
49
+ // `deepseek-reasoner` REJECTS it with a 400. The caller decides per model
50
+ // through options.replaysReasoningContent — see
51
+ // deepseekReplaysReasoningContent below. xAI reasoning models preserve
52
+ // their official multi-turn shape and cache prefix stability when prior
53
+ // assistant reasoning_content is replayed; reasoning_effort itself remains
54
+ // caller/user-selected.
52
55
  const replaysReasoningContent = options.replaysReasoningContent === true
53
- || providerName === 'deepseek'
54
56
  || providerName === 'xai';
55
57
  const out = [];
56
58
  const pendingToolMedia = [];
@@ -94,6 +96,14 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
94
96
  return out;
95
97
  }
96
98
 
99
+ // deepseek-reasoner returns 400 when `reasoning_content` appears in the input
100
+ // messages; every other DeepSeek thinking model needs it back once tools are in
101
+ // play. Unknown DeepSeek ids default to replaying: a missing echo breaks the
102
+ // tool loop, while a stray field on a non-thinking model is ignored.
103
+ export function deepseekReplaysReasoningContent(model) {
104
+ return !/reasoner/.test(String(model || '').trim().toLowerCase());
105
+ }
106
+
97
107
  export function toOpenAITools(tools) {
98
108
  return tools.map((t) => ({
99
109
  type: 'function',
@@ -2,10 +2,12 @@
2
2
  * openai-compat-xai.mjs — xAI/Grok Responses-API routing, prompt-cache lanes
3
3
  * and cache tracing for the OpenAI-compat provider.
4
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.
5
+ * Extracted from openai-compat.mjs. Owns the xAI prompt-cache lane RESOLUTION
6
+ * (shard/slot selection) plus cache routing/fingerprint/trace helpers and the
7
+ * compat cache trace writer shared by chat-completions and Responses paths.
8
+ * openai-compat.mjs imports the routing/lane/trace entry points. Admission is
9
+ * owned exclusively by the shared provider scheduler — there is no second
10
+ * cache-lane queue here.
9
11
  */
10
12
  import { createHash } from 'crypto';
11
13
  import { appendAgentTrace } from '../agent-trace.mjs';
@@ -14,6 +16,10 @@ import {
14
16
  resolveProviderPromptCacheLane,
15
17
  } from '../agent-runtime/cache-strategy.mjs';
16
18
  import { shouldFallbackTransport } from './retry-classifier.mjs';
19
+ import { envFlag as _envFlag } from './lib/env-utils.mjs';
20
+ // Same named export as before the shared helper move: importers of this module
21
+ // keep reading `_envFlag` from here.
22
+ export { _envFlag };
17
23
  import { traceHash, stableTraceStringify, summarizeTraceTools, traceTextShape } from './trace-utils.mjs';
18
24
  import { summarizeTraceMessages, extractCompatCachedTokens } from './openai-compat-trace.mjs';
19
25
 
@@ -92,7 +98,7 @@ export function xaiResponsesCacheRouting(opts, params, rawTools, model) {
92
98
  // session per process, where round-robin degenerates to slot 0 for
93
99
  // everyone). Default stays a single shared key (lane disabled) —
94
100
  // identical seed/key to before.
95
- const lane = xaiResponsesPromptCacheLane(opts, null, { prefixHash, ownerSessionHash: sessionId ? traceHash(sessionId) : null });
101
+ const lane = xaiResponsesPromptCacheLane(opts, { prefixHash, ownerSessionHash: sessionId ? traceHash(sessionId) : null });
96
102
  const laneEnabled = lane?.enabled === true;
97
103
  const laneShards = Number.isFinite(Number(lane?.shards)) && Number(lane.shards) > 0 ? Number(lane.shards) : 0;
98
104
  const explicitSlot = Number(opts?.promptCacheLaneSlot ?? opts?.xaiCacheLaneSlot);
@@ -128,6 +134,19 @@ export function normalizeXaiReasoningEffort(value) {
128
134
  return ['low', 'medium', 'high', 'xhigh'].includes(effort) ? effort : null;
129
135
  }
130
136
 
137
+ // grok-3, grok-4 and grok-4-fast REJECT reasoning_effort outright (HTTP 400
138
+ // "does not support parameter reasoningEffort"), so the parameter ships only
139
+ // for the families that document it. An unknown/absent model id keeps the
140
+ // parameter — a custom xAI-compatible deployment that never saw the 400 must
141
+ // not silently lose the caller's effort choice.
142
+ export function xaiModelSupportsReasoningEffort(model) {
143
+ const id = String(model || '').trim().toLowerCase();
144
+ if (!id) return true;
145
+ if (!id.startsWith('grok')) return true;
146
+ // grok-4.5 / grok-4.6 and anything newer in that line.
147
+ return /grok[-_]?4\.(?:[5-9]|\d{2,})/.test(id);
148
+ }
149
+
131
150
  function opencodeGoReasoningEffortValues(modelInfo) {
132
151
  const effort = (modelInfo?.reasoningOptions || []).find((option) => option?.type === 'effort');
133
152
  return Array.isArray(effort?.values)
@@ -170,12 +189,6 @@ export function useXaiResponsesWebSocket(opts, config) {
170
189
  return !['0', 'false', 'off', 'http', 'https', 'responses-http', 'sdk'].includes(transport);
171
190
  }
172
191
 
173
- export function _envFlag(name, fallback = true) {
174
- const raw = process.env[name];
175
- if (raw == null || raw === '') return fallback;
176
- return !['0', 'false', 'off', 'no'].includes(String(raw).toLowerCase());
177
- }
178
-
179
192
  // xAI WS→HTTP transport fallback → shared shouldFallbackTransport
180
193
  // (retry-classifier.mjs). Identical deny-order + allow-list; the per-provider
181
194
  // env flag is computed here and passed via `enabled`.
@@ -186,7 +199,7 @@ export function _shouldFallbackXaiWsToHttp(err, signal) {
186
199
  });
187
200
  }
188
201
 
189
- export function useXaiResponsesWebSocketWarmup(opts, config, { previousResponseId, instructions, rawTools }) {
202
+ export function useXaiResponsesWebSocketWarmup(opts, config, { previousResponseId }) {
190
203
  if (previousResponseId) return false;
191
204
  const raw = opts?.xaiResponsesWarmup
192
205
  ?? opts?.xaiWsWarmup
@@ -204,97 +217,36 @@ export function useXaiResponsesWebSocketWarmup(opts, config, { previousResponseI
204
217
  return false;
205
218
  }
206
219
 
207
- // Codex-aligned default: no compat cache lane/serialization. Keep the override
208
- // knobs so live probes can opt back into a bounded lane if a provider needs it.
209
- const XAI_RESPONSES_CACHE_LANE_DEFAULT_MAX_IN_FLIGHT = 0;
210
- const xaiResponsesCacheLanes = new Map();
211
-
212
- function parseXaiPositiveInt(value, fallback) {
213
- if (value == null || value === '') return fallback;
214
- const text = String(value).trim().toLowerCase();
215
- if (['0', 'false', 'off', 'none', 'disabled', 'unlimited', 'unbounded', 'auto'].includes(text)) return 0;
216
- const n = Number(text);
217
- if (!Number.isFinite(n)) return fallback;
218
- return Math.max(0, Math.floor(n));
219
- }
220
-
221
- function xaiResponsesCacheLaneMaxInFlight(opts, config) {
222
- return parseXaiPositiveInt(
223
- opts?.xaiCacheMaxInFlight
224
- ?? opts?.xaiResponsesCacheMaxInFlight
225
- ?? opts?.grokCacheMaxInFlight
226
- ?? opts?.grokResponsesCacheMaxInFlight
227
- ?? config?.xaiCacheMaxInFlight
228
- ?? config?.xaiResponsesCacheMaxInFlight
229
- ?? config?.grokCacheMaxInFlight
230
- ?? config?.grokResponsesCacheMaxInFlight
231
- ?? process.env.MIXDOG_XAI_CACHE_MAX_INFLIGHT
232
- ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_MAX_INFLIGHT
233
- ?? process.env.MIXDOG_GROK_CACHE_MAX_INFLIGHT
234
- ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_MAX_INFLIGHT
235
- ?? process.env.MIXDOG_GROK_OAUTH_CACHE_MAX_INFLIGHT
236
- ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_MAX_INFLIGHT,
237
- XAI_RESPONSES_CACHE_LANE_DEFAULT_MAX_IN_FLIGHT,
238
- );
239
- }
240
-
241
- function xaiResponsesCacheLaneQueueTimeoutMs(opts, config) {
242
- return parseXaiPositiveInt(
243
- opts?.xaiCacheQueueTimeoutMs
244
- ?? opts?.xaiResponsesCacheQueueTimeoutMs
245
- ?? opts?.grokCacheQueueTimeoutMs
246
- ?? opts?.grokResponsesCacheQueueTimeoutMs
247
- ?? config?.xaiCacheQueueTimeoutMs
248
- ?? config?.xaiResponsesCacheQueueTimeoutMs
249
- ?? config?.grokCacheQueueTimeoutMs
250
- ?? config?.grokResponsesCacheQueueTimeoutMs
251
- ?? process.env.MIXDOG_XAI_CACHE_QUEUE_TIMEOUT_MS
252
- ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_QUEUE_TIMEOUT_MS
253
- ?? process.env.MIXDOG_GROK_CACHE_QUEUE_TIMEOUT_MS
254
- ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_QUEUE_TIMEOUT_MS
255
- ?? process.env.MIXDOG_GROK_OAUTH_CACHE_QUEUE_TIMEOUT_MS
256
- ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_QUEUE_TIMEOUT_MS,
257
- 0,
258
- );
259
- }
260
-
261
- function xaiResponsesPromptCacheLane(opts, config, cacheRouting) {
220
+ // No `config` argument: the single caller (xaiResponsesCacheRouting) never had
221
+ // one to pass, so the provider-config lane aliases this used to read were dead
222
+ // operands. Lane selection on this route is opts + env only.
223
+ function xaiResponsesPromptCacheLane(opts, cacheRouting) {
224
+ // Lane SHARDS only, for xAI/Grok. The `*CacheMaxParallel` /
225
+ // *_CACHE_MAX_PARALLEL knobs that used to bound the lane's in-flight
226
+ // admission were removed with the lane queue itself (admission is the
227
+ // shared provider scheduler's job now). They are deliberately NOT accepted
228
+ // here as shard aliases — on this route they never selected shards, and a
229
+ // setting named "max parallel" silently deciding prompt-cache key fan-out
230
+ // is a different control with different consequences. An xAI operator who
231
+ // set one gets the documented default until they opt into
232
+ // `*CacheLaneShards` / MIXDOG_XAI_CACHE_LANE_SHARDS explicitly.
233
+ // promptCacheLaneIgnoreAliases scopes that refusal to this route only:
234
+ // OpenAI direct/OAuth keep honouring the aliases (cache-strategy.mjs).
262
235
  const shardOverride =
263
236
  opts?.xaiCacheLaneShards
264
237
  ?? opts?.xaiResponsesCacheLaneShards
265
- ?? opts?.xaiCacheMaxParallel
266
- ?? opts?.xaiResponsesCacheMaxParallel
267
238
  ?? opts?.grokCacheLaneShards
268
239
  ?? opts?.grokResponsesCacheLaneShards
269
- ?? opts?.grokCacheMaxParallel
270
- ?? opts?.grokResponsesCacheMaxParallel
271
- ?? config?.xaiCacheLaneShards
272
- ?? config?.xaiResponsesCacheLaneShards
273
- ?? config?.xaiCacheMaxParallel
274
- ?? config?.xaiResponsesCacheMaxParallel
275
- ?? config?.grokCacheLaneShards
276
- ?? config?.grokResponsesCacheLaneShards
277
- ?? config?.grokCacheMaxParallel
278
- ?? config?.grokResponsesCacheMaxParallel
279
- ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_MAX_PARALLEL
280
240
  ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_LANE_SHARDS
281
- ?? process.env.MIXDOG_GROK_CACHE_MAX_PARALLEL
282
241
  ?? process.env.MIXDOG_GROK_CACHE_LANE_SHARDS
283
- ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_MAX_PARALLEL
284
242
  ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_LANE_SHARDS
285
- ?? process.env.MIXDOG_GROK_OAUTH_CACHE_MAX_PARALLEL
286
243
  ?? process.env.MIXDOG_GROK_OAUTH_CACHE_LANE_SHARDS
287
- ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_MAX_PARALLEL
288
244
  ?? process.env.MIXDOG_GROK_OAUTH_RESPONSES_CACHE_LANE_SHARDS;
289
245
  const autoOverride =
290
246
  opts?.xaiCacheLaneAuto
291
247
  ?? opts?.xaiResponsesCacheLaneAuto
292
248
  ?? opts?.grokCacheLaneAuto
293
249
  ?? opts?.grokResponsesCacheLaneAuto
294
- ?? config?.xaiCacheLaneAuto
295
- ?? config?.xaiResponsesCacheLaneAuto
296
- ?? config?.grokCacheLaneAuto
297
- ?? config?.grokResponsesCacheLaneAuto
298
250
  ?? process.env.MIXDOG_XAI_RESPONSES_CACHE_LANE_AUTO
299
251
  ?? process.env.MIXDOG_GROK_CACHE_LANE_AUTO
300
252
  ?? process.env.MIXDOG_GROK_RESPONSES_CACHE_LANE_AUTO
@@ -319,137 +271,22 @@ function xaiResponsesPromptCacheLane(opts, config, cacheRouting) {
319
271
  );
320
272
  return resolveProviderPromptCacheLane('xai', {
321
273
  ...opts,
274
+ promptCacheLaneIgnoreAliases: true,
322
275
  ...(shardOverride !== undefined ? { promptCacheLaneShards: shardOverride } : {}),
323
276
  ...(autoOverride !== undefined ? { promptCacheLaneAuto: autoOverride } : {}),
324
277
  ...(slotOverride !== undefined ? { promptCacheLaneSlot: slotOverride } : {}),
325
278
  promptCacheLaneSeed: seed || 'xai-cache-lane',
326
- }, config);
327
- }
328
-
329
- function xaiResponsesCacheLaneKey({ model, cacheRouting, opts, config }) {
330
- const prefix = cacheRouting?.prefixHash || cacheRouting?.seedHash || cacheRouting?.key || 'unknown-prefix';
331
- const lane = xaiResponsesPromptCacheLane(opts, config, cacheRouting);
332
- const shard = Number.isFinite(Number(lane?.slot)) ? Number(lane.slot) : 0;
333
- return {
334
- key: `xai-responses:${model || 'default'}:${prefix}:shard-${shard}`,
335
- shard,
336
- lane,
337
- };
338
- }
339
-
340
- function getXaiResponsesCacheLaneState(key, maxInFlight) {
341
- let state = xaiResponsesCacheLanes.get(key);
342
- if (!state) {
343
- state = { key, active: 0, queue: [], maxInFlight, nextId: 0 };
344
- xaiResponsesCacheLanes.set(key, state);
345
- }
346
- state.maxInFlight = maxInFlight;
347
- return state;
348
- }
349
-
350
- function cleanupXaiResponsesCacheLane(state) {
351
- if (state.active === 0 && state.queue.length === 0) {
352
- xaiResponsesCacheLanes.delete(state.key);
353
- }
354
- }
355
-
356
- function removeQueuedXaiCacheLaneRequest(state, request) {
357
- const index = state.queue.indexOf(request);
358
- if (index >= 0) state.queue.splice(index, 1);
359
- cleanupXaiResponsesCacheLane(state);
279
+ }, null);
360
280
  }
361
281
 
362
- function makeXaiCacheLaneHandle(state, requestId, enqueuedAt) {
363
- let released = false;
364
- return {
365
- requestId,
366
- waitedMs: Date.now() - enqueuedAt,
367
- activeCount: state.active,
368
- queueDepth: state.queue.length,
369
- release() {
370
- if (released) return;
371
- released = true;
372
- releaseXaiResponsesCacheLane(state);
373
- },
374
- };
375
- }
376
-
377
- function releaseXaiResponsesCacheLane(state) {
378
- state.active = Math.max(0, state.active - 1);
379
- while (state.queue.length > 0 && state.active < state.maxInFlight) {
380
- const next = state.queue.shift();
381
- next.cleanup?.();
382
- state.active += 1;
383
- next.resolve(makeXaiCacheLaneHandle(state, next.requestId, next.enqueuedAt));
384
- }
385
- cleanupXaiResponsesCacheLane(state);
386
- }
387
-
388
- function acquireXaiResponsesCacheLane({ key, maxInFlight, signal, timeoutMs }) {
389
- const state = getXaiResponsesCacheLaneState(key, maxInFlight);
390
- const requestId = ++state.nextId;
391
- const enqueuedAt = Date.now();
392
- if (state.active < state.maxInFlight) {
393
- state.active += 1;
394
- return Promise.resolve(makeXaiCacheLaneHandle(state, requestId, enqueuedAt));
395
- }
396
- return new Promise((resolve, reject) => {
397
- const request = {
398
- requestId,
399
- enqueuedAt,
400
- resolve,
401
- reject,
402
- cleanup: null,
403
- };
404
- const cleanup = () => {
405
- if (request.timer) clearTimeout(request.timer);
406
- if (signal && request.abortListener) signal.removeEventListener('abort', request.abortListener);
407
- };
408
- request.cleanup = cleanup;
409
- request.abortListener = () => {
410
- cleanup();
411
- removeQueuedXaiCacheLaneRequest(state, request);
412
- const reason = signal?.reason;
413
- reject(reason instanceof Error ? reason : new Error('xAI cache lane wait aborted'));
414
- };
415
- if (signal?.aborted) {
416
- request.abortListener();
417
- return;
418
- }
419
- if (signal) signal.addEventListener('abort', request.abortListener, { once: true });
420
- if (timeoutMs > 0) {
421
- request.timer = setTimeout(() => {
422
- cleanup();
423
- removeQueuedXaiCacheLaneRequest(state, request);
424
- reject(new Error(`xAI cache lane wait timed out after ${timeoutMs}ms`));
425
- }, timeoutMs);
426
- request.timer.unref?.();
427
- }
428
- state.queue.push(request);
429
- });
430
- }
431
-
432
- function traceXaiCacheLane(opts, payload) {
433
- if (!compatCacheTraceEnabled('xai')) return;
434
- try {
435
- appendAgentTrace({
436
- sessionId: opts?.sessionId || opts?.session?.id || null,
437
- iteration: Number.isFinite(Number(opts?.iteration)) ? Number(opts.iteration) : null,
438
- kind: 'cache_lane',
439
- ...payload,
440
- payload,
441
- });
442
- } catch {}
443
- }
444
-
445
- export async function withXaiResponsesCacheLane({ opts, config, cacheRouting, model, transport, previousResponseId, inputCount, signal }, fn) {
446
- // Historical prompt-cache lanes formed a second admission queue and could
447
- // time out while waiting. xAI is now governed exclusively by the common
448
- // fixed-64 provider/account scheduler, regardless of legacy env/option
449
- // knobs. Keep this wrapper only as a call-shape compatibility boundary.
450
- const laneMeta = { enabled: false, maxInFlight: 0 };
451
- return { value: await fn(laneMeta), laneMeta };
452
- }
282
+ // Historical prompt-cache lanes formed a second admission queue and could time
283
+ // out while waiting. xAI is now governed exclusively by the common fixed-64
284
+ // provider/account scheduler, so no lane is ever taken: the queue/handle
285
+ // machinery and its max-in-flight / queue-timeout knobs were dead code and have
286
+ // been removed rather than left as settings that silently do nothing. The
287
+ // cache-trace payload still reports the lane shape, so this frozen "no lane"
288
+ // record is what the xAI Responses trace writers receive.
289
+ export const XAI_CACHE_LANE_META = Object.freeze({ enabled: false, maxInFlight: 0 });
453
290
 
454
291
  function deterministicUuidFromKey(key) {
455
292
  const hex = createHash('sha256').update(String(key ?? '')).digest('hex');