@copilotkit/aimock 1.21.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +41 -0
  3. package/README.md +1 -0
  4. package/dist/a2a-mock.cjs +1 -1
  5. package/dist/a2a-mock.cjs.map +1 -1
  6. package/dist/a2a-mock.d.cts.map +1 -1
  7. package/dist/a2a-mock.d.ts.map +1 -1
  8. package/dist/a2a-mock.js +1 -1
  9. package/dist/a2a-mock.js.map +1 -1
  10. package/dist/agui-recorder.cjs +25 -12
  11. package/dist/agui-recorder.cjs.map +1 -1
  12. package/dist/agui-recorder.js +25 -12
  13. package/dist/agui-recorder.js.map +1 -1
  14. package/dist/agui-types.d.ts.map +1 -1
  15. package/dist/bedrock-converse.cjs +18 -12
  16. package/dist/bedrock-converse.cjs.map +1 -1
  17. package/dist/bedrock-converse.d.cts.map +1 -1
  18. package/dist/bedrock-converse.d.ts.map +1 -1
  19. package/dist/bedrock-converse.js +19 -13
  20. package/dist/bedrock-converse.js.map +1 -1
  21. package/dist/bedrock.cjs +18 -12
  22. package/dist/bedrock.cjs.map +1 -1
  23. package/dist/bedrock.d.cts.map +1 -1
  24. package/dist/bedrock.d.ts.map +1 -1
  25. package/dist/bedrock.js +19 -13
  26. package/dist/bedrock.js.map +1 -1
  27. package/dist/cli.cjs +1 -1
  28. package/dist/cli.cjs.map +1 -1
  29. package/dist/cli.js +1 -1
  30. package/dist/cli.js.map +1 -1
  31. package/dist/cohere.cjs +9 -6
  32. package/dist/cohere.cjs.map +1 -1
  33. package/dist/cohere.d.cts.map +1 -1
  34. package/dist/cohere.d.ts.map +1 -1
  35. package/dist/cohere.js +10 -7
  36. package/dist/cohere.js.map +1 -1
  37. package/dist/config-loader.d.cts.map +1 -1
  38. package/dist/config-loader.d.ts.map +1 -1
  39. package/dist/elevenlabs-audio.cjs +8 -5
  40. package/dist/elevenlabs-audio.cjs.map +1 -1
  41. package/dist/elevenlabs-audio.d.cts.map +1 -1
  42. package/dist/elevenlabs-audio.d.ts.map +1 -1
  43. package/dist/elevenlabs-audio.js +9 -6
  44. package/dist/elevenlabs-audio.js.map +1 -1
  45. package/dist/embeddings.cjs +6 -4
  46. package/dist/embeddings.cjs.map +1 -1
  47. package/dist/embeddings.d.cts.map +1 -1
  48. package/dist/embeddings.d.ts.map +1 -1
  49. package/dist/embeddings.js +7 -5
  50. package/dist/embeddings.js.map +1 -1
  51. package/dist/fal-audio.cjs +16 -10
  52. package/dist/fal-audio.cjs.map +1 -1
  53. package/dist/fal-audio.d.cts.map +1 -1
  54. package/dist/fal-audio.d.ts.map +1 -1
  55. package/dist/fal-audio.js +17 -11
  56. package/dist/fal-audio.js.map +1 -1
  57. package/dist/fal.cjs +5 -3
  58. package/dist/fal.cjs.map +1 -1
  59. package/dist/fal.d.cts.map +1 -1
  60. package/dist/fal.d.ts.map +1 -1
  61. package/dist/fal.js +6 -4
  62. package/dist/fal.js.map +1 -1
  63. package/dist/gemini-interactions.cjs +10 -7
  64. package/dist/gemini-interactions.cjs.map +1 -1
  65. package/dist/gemini-interactions.d.cts.map +1 -1
  66. package/dist/gemini-interactions.d.ts.map +1 -1
  67. package/dist/gemini-interactions.js +11 -8
  68. package/dist/gemini-interactions.js.map +1 -1
  69. package/dist/gemini.cjs +10 -7
  70. package/dist/gemini.cjs.map +1 -1
  71. package/dist/gemini.d.cts.map +1 -1
  72. package/dist/gemini.d.ts.map +1 -1
  73. package/dist/gemini.js +11 -8
  74. package/dist/gemini.js.map +1 -1
  75. package/dist/helpers.cjs +31 -0
  76. package/dist/helpers.cjs.map +1 -1
  77. package/dist/helpers.d.cts +1 -0
  78. package/dist/helpers.d.cts.map +1 -1
  79. package/dist/helpers.d.ts +1 -0
  80. package/dist/helpers.d.ts.map +1 -1
  81. package/dist/helpers.js +30 -1
  82. package/dist/helpers.js.map +1 -1
  83. package/dist/images.cjs +8 -5
  84. package/dist/images.cjs.map +1 -1
  85. package/dist/images.d.cts.map +1 -1
  86. package/dist/images.d.ts.map +1 -1
  87. package/dist/images.js +9 -6
  88. package/dist/images.js.map +1 -1
  89. package/dist/mcp-mock.cjs +1 -1
  90. package/dist/mcp-mock.cjs.map +1 -1
  91. package/dist/mcp-mock.d.cts.map +1 -1
  92. package/dist/mcp-mock.d.ts.map +1 -1
  93. package/dist/mcp-mock.js +1 -1
  94. package/dist/mcp-mock.js.map +1 -1
  95. package/dist/messages.cjs +9 -6
  96. package/dist/messages.cjs.map +1 -1
  97. package/dist/messages.d.cts.map +1 -1
  98. package/dist/messages.d.ts.map +1 -1
  99. package/dist/messages.js +10 -7
  100. package/dist/messages.js.map +1 -1
  101. package/dist/moderation.cjs +3 -2
  102. package/dist/moderation.cjs.map +1 -1
  103. package/dist/moderation.js +3 -2
  104. package/dist/moderation.js.map +1 -1
  105. package/dist/ollama.cjs +18 -12
  106. package/dist/ollama.cjs.map +1 -1
  107. package/dist/ollama.d.cts.map +1 -1
  108. package/dist/ollama.d.ts.map +1 -1
  109. package/dist/ollama.js +19 -13
  110. package/dist/ollama.js.map +1 -1
  111. package/dist/recorder.cjs +82 -38
  112. package/dist/recorder.cjs.map +1 -1
  113. package/dist/recorder.d.cts +3 -2
  114. package/dist/recorder.d.cts.map +1 -1
  115. package/dist/recorder.d.ts +3 -2
  116. package/dist/recorder.d.ts.map +1 -1
  117. package/dist/recorder.js +82 -38
  118. package/dist/recorder.js.map +1 -1
  119. package/dist/rerank.cjs +3 -2
  120. package/dist/rerank.cjs.map +1 -1
  121. package/dist/rerank.js +3 -2
  122. package/dist/rerank.js.map +1 -1
  123. package/dist/responses.cjs +9 -6
  124. package/dist/responses.cjs.map +1 -1
  125. package/dist/responses.d.cts.map +1 -1
  126. package/dist/responses.d.ts.map +1 -1
  127. package/dist/responses.js +10 -7
  128. package/dist/responses.js.map +1 -1
  129. package/dist/search.cjs +3 -2
  130. package/dist/search.cjs.map +1 -1
  131. package/dist/search.js +3 -2
  132. package/dist/search.js.map +1 -1
  133. package/dist/server.cjs +135 -73
  134. package/dist/server.cjs.map +1 -1
  135. package/dist/server.d.cts.map +1 -1
  136. package/dist/server.d.ts.map +1 -1
  137. package/dist/server.js +136 -74
  138. package/dist/server.js.map +1 -1
  139. package/dist/speech.cjs +8 -5
  140. package/dist/speech.cjs.map +1 -1
  141. package/dist/speech.d.cts.map +1 -1
  142. package/dist/speech.d.ts.map +1 -1
  143. package/dist/speech.js +9 -6
  144. package/dist/speech.js.map +1 -1
  145. package/dist/stream-collapse.cjs +51 -21
  146. package/dist/stream-collapse.cjs.map +1 -1
  147. package/dist/stream-collapse.d.cts +1 -0
  148. package/dist/stream-collapse.d.cts.map +1 -1
  149. package/dist/stream-collapse.d.ts +1 -0
  150. package/dist/stream-collapse.d.ts.map +1 -1
  151. package/dist/stream-collapse.js +51 -21
  152. package/dist/stream-collapse.js.map +1 -1
  153. package/dist/transcription.cjs +5 -3
  154. package/dist/transcription.cjs.map +1 -1
  155. package/dist/transcription.d.cts.map +1 -1
  156. package/dist/transcription.d.ts.map +1 -1
  157. package/dist/transcription.js +6 -4
  158. package/dist/transcription.js.map +1 -1
  159. package/dist/types.d.cts +2 -0
  160. package/dist/types.d.cts.map +1 -1
  161. package/dist/types.d.ts +2 -0
  162. package/dist/types.d.ts.map +1 -1
  163. package/dist/vector-mock.cjs +10 -8
  164. package/dist/vector-mock.cjs.map +1 -1
  165. package/dist/vector-mock.d.cts.map +1 -1
  166. package/dist/vector-mock.d.ts.map +1 -1
  167. package/dist/vector-mock.js +10 -8
  168. package/dist/vector-mock.js.map +1 -1
  169. package/dist/video.cjs +8 -5
  170. package/dist/video.cjs.map +1 -1
  171. package/dist/video.d.cts.map +1 -1
  172. package/dist/video.d.ts.map +1 -1
  173. package/dist/video.js +9 -6
  174. package/dist/video.js.map +1 -1
  175. package/dist/ws-gemini-live.cjs +6 -4
  176. package/dist/ws-gemini-live.cjs.map +1 -1
  177. package/dist/ws-gemini-live.d.cts +2 -0
  178. package/dist/ws-gemini-live.d.cts.map +1 -1
  179. package/dist/ws-gemini-live.d.ts +2 -0
  180. package/dist/ws-gemini-live.d.ts.map +1 -1
  181. package/dist/ws-gemini-live.js +7 -5
  182. package/dist/ws-gemini-live.js.map +1 -1
  183. package/dist/ws-realtime.cjs +6 -4
  184. package/dist/ws-realtime.cjs.map +1 -1
  185. package/dist/ws-realtime.d.cts +2 -0
  186. package/dist/ws-realtime.d.cts.map +1 -1
  187. package/dist/ws-realtime.d.ts +2 -0
  188. package/dist/ws-realtime.d.ts.map +1 -1
  189. package/dist/ws-realtime.js +7 -5
  190. package/dist/ws-realtime.js.map +1 -1
  191. package/dist/ws-responses.cjs +6 -4
  192. package/dist/ws-responses.cjs.map +1 -1
  193. package/dist/ws-responses.d.cts +2 -0
  194. package/dist/ws-responses.d.cts.map +1 -1
  195. package/dist/ws-responses.d.ts +2 -0
  196. package/dist/ws-responses.d.ts.map +1 -1
  197. package/dist/ws-responses.js +7 -5
  198. package/dist/ws-responses.js.map +1 -1
  199. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import { buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, extractOverrides, flattenHeaders, getTestId, isAudioResponse, isContentWithToolCallsResponse, isErrorResponse, isTextResponse, isToolCallResponse, resolveResponse } from "./helpers.js";
1
+ import { buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, extractOverrides, flattenHeaders, getTestId, isAudioResponse, isContentWithToolCallsResponse, isErrorResponse, isTextResponse, isToolCallResponse, resolveResponse, resolveStrictMode, strictOverrideField } from "./helpers.js";
2
2
  import { Logger } from "./logger.js";
3
3
  import { Journal } from "./journal.js";
4
4
  import { matchFixture } from "./router.js";
@@ -252,12 +252,17 @@ async function handleControlAPI(req, res, pathname, fixtures, journal, videoStat
252
252
  }
253
253
  };
254
254
  fixtures.unshift(errorFixture);
255
+ let consumed = false;
255
256
  const original = errorFixture.match.predicate;
256
257
  errorFixture.match.predicate = (req) => {
258
+ if (consumed) return false;
257
259
  const result = original(req);
258
260
  if (result) {
259
- const idx = fixtures.indexOf(errorFixture);
260
- if (idx !== -1) fixtures.splice(idx, 1);
261
+ consumed = true;
262
+ queueMicrotask(() => {
263
+ const idx = fixtures.indexOf(errorFixture);
264
+ if (idx !== -1) fixtures.splice(idx, 1);
265
+ });
261
266
  }
262
267
  return result;
263
268
  };
@@ -295,7 +300,8 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
295
300
  try {
296
301
  body = JSON.parse(raw);
297
302
  if (modelFallback && !body.model) body.model = modelFallback;
298
- } catch {
303
+ } catch (parseErr) {
304
+ const detail = parseErr instanceof Error ? parseErr.message : "unknown parse error";
299
305
  journal.add({
300
306
  method: req.method ?? "POST",
301
307
  path: req.url ?? COMPLETIONS_PATH,
@@ -307,7 +313,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
307
313
  }
308
314
  });
309
315
  writeErrorResponse(res, 400, JSON.stringify({ error: {
310
- message: "Malformed JSON",
316
+ message: `Malformed JSON: ${detail}`,
311
317
  type: "invalid_request_error",
312
318
  param: null,
313
319
  code: "invalid_json"
@@ -370,7 +376,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
370
376
  return true;
371
377
  },
372
378
  onHookBypassed: (reason) => {
373
- defaults.logger.warn(`[chaos] malformed bypassed on proxy: upstream returned SSE (${reason})`);
379
+ defaults.logger.warn(`[chaos] malformed bypassed on proxy: upstream returned streaming response (${reason})`);
374
380
  defaults.registry?.incrementCounter("aimock_chaos_bypassed_total", {
375
381
  action: "malformed",
376
382
  source: "proxy",
@@ -395,9 +401,10 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
395
401
  return;
396
402
  }
397
403
  }
398
- const strictStatus = defaults.strict ? 503 : 404;
399
- const strictMessage = defaults.strict ? "Strict mode: no fixture matched" : "No fixture matched";
400
- if (defaults.strict) defaults.logger.error(`STRICT: No fixture matched for ${req.method ?? "POST"} ${req.url ?? COMPLETIONS_PATH}`);
404
+ const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
405
+ const strictStatus = effectiveStrict ? 503 : 404;
406
+ const strictMessage = effectiveStrict ? "Strict mode: no fixture matched" : "No fixture matched";
407
+ if (effectiveStrict) defaults.logger.error(`STRICT: No fixture matched for ${req.method ?? "POST"} ${req.url ?? COMPLETIONS_PATH}`);
401
408
  journal.add({
402
409
  method: req.method ?? "POST",
403
410
  path: req.url ?? COMPLETIONS_PATH,
@@ -405,7 +412,8 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
405
412
  body,
406
413
  response: {
407
414
  status: strictStatus,
408
- fixture: null
415
+ fixture: null,
416
+ ...strictOverrideField(defaults.strict, req.headers)
409
417
  }
410
418
  });
411
419
  writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
@@ -634,7 +642,7 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
634
642
  message: msg,
635
643
  type: "server_error"
636
644
  } }));
637
- }
645
+ } else if (!res.writableEnded) res.end();
638
646
  });
639
647
  });
640
648
  async function handleHttpRequest(req, res) {
@@ -775,13 +783,11 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
775
783
  message: msg,
776
784
  type: "server_error"
777
785
  } }));
778
- else if (!res.writableEnded) {
779
- try {
780
- res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
781
- } catch (writeErr) {
782
- logger.debug("Failed to write error recovery response:", writeErr);
783
- }
786
+ else if (!res.writableEnded) try {
787
+ res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
784
788
  res.end();
789
+ } catch (writeErr) {
790
+ logger.debug("Failed to write error recovery response:", writeErr);
785
791
  }
786
792
  }
787
793
  return;
@@ -795,13 +801,11 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
795
801
  message: msg,
796
802
  type: "server_error"
797
803
  } }));
798
- else if (!res.writableEnded) {
799
- try {
800
- res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
801
- } catch (writeErr) {
802
- logger.debug("Failed to write error recovery response:", writeErr);
803
- }
804
+ else if (!res.writableEnded) try {
805
+ res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
804
806
  res.end();
807
+ } catch (writeErr) {
808
+ logger.debug("Failed to write error recovery response:", writeErr);
805
809
  }
806
810
  }
807
811
  return;
@@ -815,13 +819,11 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
815
819
  message: msg,
816
820
  type: "server_error"
817
821
  } }));
818
- else if (!res.writableEnded) {
819
- try {
820
- res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
821
- } catch (writeErr) {
822
- logger.debug("Failed to write error recovery response:", writeErr);
823
- }
822
+ else if (!res.writableEnded) try {
823
+ res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
824
824
  res.end();
825
+ } catch (writeErr) {
826
+ logger.debug("Failed to write error recovery response:", writeErr);
825
827
  }
826
828
  }
827
829
  return;
@@ -837,7 +839,9 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
837
839
  parsed.model = deploymentId;
838
840
  raw = JSON.stringify(parsed);
839
841
  }
840
- } catch {}
842
+ } catch (err) {
843
+ if (!(err instanceof SyntaxError)) defaults.logger.error(`Unexpected error in Azure model injection: ${err instanceof Error ? err.message : String(err)}`);
844
+ }
841
845
  await handleEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders, embeddingsProvider);
842
846
  } catch (err) {
843
847
  const msg = err instanceof Error ? err.message : "Internal error";
@@ -931,13 +935,11 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
931
935
  message: msg,
932
936
  type: "server_error"
933
937
  } }));
934
- else if (!res.writableEnded) {
935
- try {
936
- res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
937
- } catch (writeErr) {
938
- logger.debug("Failed to write error recovery response:", writeErr);
939
- }
938
+ else if (!res.writableEnded) try {
939
+ res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
940
940
  res.end();
941
+ } catch (writeErr) {
942
+ logger.debug("Failed to write error recovery response:", writeErr);
941
943
  }
942
944
  }
943
945
  return;
@@ -954,13 +956,11 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
954
956
  message: msg,
955
957
  type: "server_error"
956
958
  } }));
957
- else if (!res.writableEnded) {
958
- try {
959
- res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
960
- } catch (writeErr) {
961
- logger.debug("Failed to write error recovery response:", writeErr);
962
- }
959
+ else if (!res.writableEnded) try {
960
+ res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
963
961
  res.end();
962
+ } catch (writeErr) {
963
+ logger.debug("Failed to write error recovery response:", writeErr);
964
964
  }
965
965
  }
966
966
  return;
@@ -977,13 +977,11 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
977
977
  message: msg,
978
978
  type: "server_error"
979
979
  } }));
980
- else if (!res.writableEnded) {
981
- try {
982
- res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
983
- } catch (writeErr) {
984
- logger.debug("Failed to write error recovery response:", writeErr);
985
- }
980
+ else if (!res.writableEnded) try {
981
+ res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
986
982
  res.end();
983
+ } catch (writeErr) {
984
+ logger.debug("Failed to write error recovery response:", writeErr);
987
985
  }
988
986
  }
989
987
  return;
@@ -1133,9 +1131,23 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1133
1131
  setCorsHeaders(res);
1134
1132
  try {
1135
1133
  const raw = await readBody(req);
1136
- const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);
1134
+ let elSoundFixture = null;
1135
+ try {
1136
+ const parsed = JSON.parse(raw);
1137
+ const syntheticReq = {
1138
+ model: parsed.model_id ?? "eleven_text_to_sound_v2",
1139
+ messages: [{
1140
+ role: "user",
1141
+ content: parsed.text ?? ""
1142
+ }],
1143
+ _endpointType: "audio-gen"
1144
+ };
1145
+ const testId = getTestId(req);
1146
+ elSoundFixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
1147
+ } catch {}
1148
+ const chaosAction = evaluateChaos(elSoundFixture, defaults.chaos, req.headers, defaults.logger);
1137
1149
  if (chaosAction) {
1138
- applyChaosAction(chaosAction, res, null, journal, {
1150
+ applyChaosAction(chaosAction, res, elSoundFixture, journal, {
1139
1151
  method: req.method ?? "POST",
1140
1152
  path: pathname,
1141
1153
  headers: flattenHeaders(req.headers),
@@ -1163,9 +1175,24 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1163
1175
  const musicSubType = musicMatch[1] ?? "music";
1164
1176
  try {
1165
1177
  const raw = await readBody(req);
1166
- const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);
1178
+ let elMusicFixture = null;
1179
+ try {
1180
+ const parsed = JSON.parse(raw);
1181
+ const prompt = (typeof parsed.prompt === "string" ? parsed.prompt : null) ?? (parsed.composition_plan != null ? typeof parsed.composition_plan === "string" ? parsed.composition_plan : JSON.stringify(parsed.composition_plan) : "");
1182
+ const syntheticReq = {
1183
+ model: parsed.model_id ?? "music_v1",
1184
+ messages: [{
1185
+ role: "user",
1186
+ content: prompt
1187
+ }],
1188
+ _endpointType: "audio-gen"
1189
+ };
1190
+ const testId = getTestId(req);
1191
+ elMusicFixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
1192
+ } catch {}
1193
+ const chaosAction = evaluateChaos(elMusicFixture, defaults.chaos, req.headers, defaults.logger);
1167
1194
  if (chaosAction) {
1168
- applyChaosAction(chaosAction, res, null, journal, {
1195
+ applyChaosAction(chaosAction, res, elMusicFixture, journal, {
1169
1196
  method: req.method ?? "POST",
1170
1197
  path: pathname,
1171
1198
  headers: flattenHeaders(req.headers),
@@ -1187,10 +1214,12 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1187
1214
  }
1188
1215
  return;
1189
1216
  }
1217
+ let falBody;
1190
1218
  if (FAL_PREFIX_RE.test(pathname) && req.headers["x-fal-target-host"]) {
1191
1219
  setCorsHeaders(res);
1192
1220
  try {
1193
- const raw = req.method === "POST" || req.method === "PUT" ? await readBody(req) : "";
1221
+ falBody = req.method === "POST" || req.method === "PUT" ? await readBody(req) : "";
1222
+ const raw = falBody;
1194
1223
  const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);
1195
1224
  if (chaosAction) {
1196
1225
  applyChaosAction(chaosAction, res, null, journal, {
@@ -1215,13 +1244,29 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1215
1244
  return;
1216
1245
  }
1217
1246
  }
1218
- if (pathname.match(FAL_QUEUE_SUBMIT_RE) && req.method === "POST") {
1247
+ const falQueueSubmitMatch = pathname.match(FAL_QUEUE_SUBMIT_RE);
1248
+ if (falQueueSubmitMatch && req.method === "POST") {
1219
1249
  setCorsHeaders(res);
1220
1250
  try {
1221
- const raw = await readBody(req);
1222
- const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);
1251
+ const raw = falBody ?? await readBody(req);
1252
+ let falSubmitFixture = null;
1253
+ try {
1254
+ const parsed = raw.trim() ? JSON.parse(raw) : {};
1255
+ const prompt = (typeof parsed.prompt === "string" ? parsed.prompt : null) ?? (typeof parsed.text === "string" ? parsed.text : null) ?? "";
1256
+ const syntheticReq = {
1257
+ model: falQueueSubmitMatch[1],
1258
+ messages: [{
1259
+ role: "user",
1260
+ content: prompt
1261
+ }],
1262
+ _endpointType: "fal-audio"
1263
+ };
1264
+ const testId = getTestId(req);
1265
+ falSubmitFixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
1266
+ } catch {}
1267
+ const chaosAction = evaluateChaos(falSubmitFixture, defaults.chaos, req.headers, defaults.logger);
1223
1268
  if (chaosAction) {
1224
- applyChaosAction(chaosAction, res, null, journal, {
1269
+ applyChaosAction(chaosAction, res, falSubmitFixture, journal, {
1225
1270
  method: req.method ?? "POST",
1226
1271
  path: pathname,
1227
1272
  headers: flattenHeaders(req.headers),
@@ -1246,7 +1291,7 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1246
1291
  if (pathname.match(FAL_QUEUE_REQUESTS_RE) && (req.method === "GET" || req.method === "POST" || req.method === "PUT")) {
1247
1292
  setCorsHeaders(res);
1248
1293
  try {
1249
- const raw = req.method === "POST" ? await readBody(req) : "{}";
1294
+ const raw = req.method === "POST" || req.method === "PUT" ? falBody ?? await readBody(req) : "{}";
1250
1295
  const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);
1251
1296
  if (chaosAction) {
1252
1297
  applyChaosAction(chaosAction, res, null, journal, {
@@ -1271,13 +1316,29 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1271
1316
  }
1272
1317
  return;
1273
1318
  }
1274
- if (pathname.match(FAL_RUN_RE) && req.method === "POST") {
1319
+ const falRunMatch = pathname.match(FAL_RUN_RE);
1320
+ if (falRunMatch && req.method === "POST") {
1275
1321
  setCorsHeaders(res);
1276
1322
  try {
1277
- const raw = await readBody(req);
1278
- const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);
1323
+ const raw = falBody ?? await readBody(req);
1324
+ let falRunFixture = null;
1325
+ try {
1326
+ const parsed = raw.trim() ? JSON.parse(raw) : {};
1327
+ const prompt = (typeof parsed.prompt === "string" ? parsed.prompt : null) ?? (typeof parsed.text === "string" ? parsed.text : null) ?? "";
1328
+ const syntheticReq = {
1329
+ model: falRunMatch[1],
1330
+ messages: [{
1331
+ role: "user",
1332
+ content: prompt
1333
+ }],
1334
+ _endpointType: "fal-audio"
1335
+ };
1336
+ const testId = getTestId(req);
1337
+ falRunFixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
1338
+ } catch {}
1339
+ const chaosAction = evaluateChaos(falRunFixture, defaults.chaos, req.headers, defaults.logger);
1279
1340
  if (chaosAction) {
1280
- applyChaosAction(chaosAction, res, null, journal, {
1341
+ applyChaosAction(chaosAction, res, falRunFixture, journal, {
1281
1342
  method: req.method ?? "POST",
1282
1343
  path: pathname,
1283
1344
  headers: flattenHeaders(req.headers),
@@ -1316,16 +1377,14 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1316
1377
  message: msg,
1317
1378
  type: "server_error"
1318
1379
  } }));
1319
- else if (!res.writableEnded) {
1320
- try {
1321
- res.write(`data: ${JSON.stringify({ error: {
1322
- message: msg,
1323
- type: "server_error"
1324
- } })}\n\n`);
1325
- } catch (writeErr) {
1326
- logger.debug("Failed to write error recovery response:", writeErr);
1327
- }
1380
+ else if (!res.writableEnded) try {
1381
+ res.write(`data: ${JSON.stringify({ error: {
1382
+ message: msg,
1383
+ type: "server_error"
1384
+ } })}\n\n`);
1328
1385
  res.end();
1386
+ } catch (writeErr) {
1387
+ logger.debug("Failed to write error recovery response:", writeErr);
1329
1388
  }
1330
1389
  }
1331
1390
  }
@@ -1374,19 +1433,22 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1374
1433
  if (pathname === RESPONSES_PATH) handleWebSocketResponses(ws, fixtures, journal, {
1375
1434
  ...defaults,
1376
1435
  model: "gpt-4",
1377
- testId: wsTestId
1436
+ testId: wsTestId,
1437
+ upgradeHeaders: req.headers
1378
1438
  });
1379
1439
  else if (pathname === REALTIME_PATH) {
1380
1440
  const model = parsedUrl.searchParams.get("model") ?? "gpt-4o-realtime";
1381
1441
  handleWebSocketRealtime(ws, fixtures, journal, {
1382
1442
  ...defaults,
1383
1443
  model,
1384
- testId: wsTestId
1444
+ testId: wsTestId,
1445
+ upgradeHeaders: req.headers
1385
1446
  });
1386
1447
  } else if (pathname === GEMINI_LIVE_PATH) handleWebSocketGeminiLive(ws, fixtures, journal, {
1387
1448
  ...defaults,
1388
1449
  model: "gemini-2.0-flash",
1389
- testId: wsTestId
1450
+ testId: wsTestId,
1451
+ upgradeHeaders: req.headers
1390
1452
  });
1391
1453
  }
1392
1454
  const originalClose = server.close.bind(server);