@copilotkit/aimock 1.40.0 → 1.42.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 (251) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +28 -1
  4. package/README.md +5 -3
  5. package/dist/a2a-mock.cjs +18 -11
  6. package/dist/a2a-mock.cjs.map +1 -1
  7. package/dist/a2a-mock.d.cts +1 -0
  8. package/dist/a2a-mock.d.cts.map +1 -1
  9. package/dist/a2a-mock.d.ts +1 -0
  10. package/dist/a2a-mock.d.ts.map +1 -1
  11. package/dist/a2a-mock.js +18 -11
  12. package/dist/a2a-mock.js.map +1 -1
  13. package/dist/agui-handler.d.cts.map +1 -1
  14. package/dist/agui-handler.d.ts.map +1 -1
  15. package/dist/agui-mock.cjs +2 -0
  16. package/dist/agui-mock.cjs.map +1 -1
  17. package/dist/agui-mock.d.cts.map +1 -1
  18. package/dist/agui-mock.d.ts.map +1 -1
  19. package/dist/agui-mock.js +2 -0
  20. package/dist/agui-mock.js.map +1 -1
  21. package/dist/bedrock-converse.cjs +36 -2
  22. package/dist/bedrock-converse.cjs.map +1 -1
  23. package/dist/bedrock-converse.d.cts.map +1 -1
  24. package/dist/bedrock-converse.d.ts.map +1 -1
  25. package/dist/bedrock-converse.js +37 -3
  26. package/dist/bedrock-converse.js.map +1 -1
  27. package/dist/bedrock.cjs +50 -13
  28. package/dist/bedrock.cjs.map +1 -1
  29. package/dist/bedrock.d.cts.map +1 -1
  30. package/dist/bedrock.d.ts.map +1 -1
  31. package/dist/bedrock.js +51 -14
  32. package/dist/bedrock.js.map +1 -1
  33. package/dist/byteplus-video.cjs +954 -0
  34. package/dist/byteplus-video.cjs.map +1 -0
  35. package/dist/byteplus-video.d.cts +176 -0
  36. package/dist/byteplus-video.d.cts.map +1 -0
  37. package/dist/byteplus-video.d.ts +176 -0
  38. package/dist/byteplus-video.d.ts.map +1 -0
  39. package/dist/byteplus-video.js +947 -0
  40. package/dist/byteplus-video.js.map +1 -0
  41. package/dist/chaos.cjs +36 -7
  42. package/dist/chaos.cjs.map +1 -1
  43. package/dist/chaos.d.cts +8 -3
  44. package/dist/chaos.d.cts.map +1 -1
  45. package/dist/chaos.d.ts +8 -3
  46. package/dist/chaos.d.ts.map +1 -1
  47. package/dist/chaos.js +36 -8
  48. package/dist/chaos.js.map +1 -1
  49. package/dist/cli.cjs +5 -1
  50. package/dist/cli.cjs.map +1 -1
  51. package/dist/cli.js +5 -1
  52. package/dist/cli.js.map +1 -1
  53. package/dist/cohere.cjs +58 -5
  54. package/dist/cohere.cjs.map +1 -1
  55. package/dist/cohere.d.cts.map +1 -1
  56. package/dist/cohere.d.ts.map +1 -1
  57. package/dist/cohere.js +59 -6
  58. package/dist/cohere.js.map +1 -1
  59. package/dist/config-loader.d.cts.map +1 -1
  60. package/dist/elevenlabs-audio.cjs +36 -2
  61. package/dist/elevenlabs-audio.cjs.map +1 -1
  62. package/dist/elevenlabs-audio.d.cts.map +1 -1
  63. package/dist/elevenlabs-audio.d.ts.map +1 -1
  64. package/dist/elevenlabs-audio.js +37 -3
  65. package/dist/elevenlabs-audio.js.map +1 -1
  66. package/dist/embeddings.cjs +58 -3
  67. package/dist/embeddings.cjs.map +1 -1
  68. package/dist/embeddings.d.cts.map +1 -1
  69. package/dist/embeddings.d.ts.map +1 -1
  70. package/dist/embeddings.js +59 -4
  71. package/dist/embeddings.js.map +1 -1
  72. package/dist/fal-audio.cjs +38 -2
  73. package/dist/fal-audio.cjs.map +1 -1
  74. package/dist/fal-audio.d.cts.map +1 -1
  75. package/dist/fal-audio.d.ts.map +1 -1
  76. package/dist/fal-audio.js +39 -3
  77. package/dist/fal-audio.js.map +1 -1
  78. package/dist/fixture-loader.cjs +0 -0
  79. package/dist/fixture-loader.cjs.map +1 -1
  80. package/dist/fixture-loader.d.cts +9 -1
  81. package/dist/fixture-loader.d.cts.map +1 -1
  82. package/dist/fixture-loader.d.ts +9 -1
  83. package/dist/fixture-loader.d.ts.map +1 -1
  84. package/dist/fixture-loader.js +0 -0
  85. package/dist/fixture-loader.js.map +1 -1
  86. package/dist/gemini-embeddings.cjs +19 -1
  87. package/dist/gemini-embeddings.cjs.map +1 -1
  88. package/dist/gemini-embeddings.js +20 -2
  89. package/dist/gemini-embeddings.js.map +1 -1
  90. package/dist/gemini-interactions.cjs +15 -1
  91. package/dist/gemini-interactions.cjs.map +1 -1
  92. package/dist/gemini-interactions.d.cts.map +1 -1
  93. package/dist/gemini-interactions.d.ts.map +1 -1
  94. package/dist/gemini-interactions.js +16 -2
  95. package/dist/gemini-interactions.js.map +1 -1
  96. package/dist/gemini.cjs +70 -6
  97. package/dist/gemini.cjs.map +1 -1
  98. package/dist/gemini.d.cts.map +1 -1
  99. package/dist/gemini.d.ts.map +1 -1
  100. package/dist/gemini.js +71 -7
  101. package/dist/gemini.js.map +1 -1
  102. package/dist/grok-video.cjs +2 -2
  103. package/dist/grok-video.cjs.map +1 -1
  104. package/dist/grok-video.d.cts.map +1 -1
  105. package/dist/grok-video.d.ts.map +1 -1
  106. package/dist/grok-video.js +2 -2
  107. package/dist/grok-video.js.map +1 -1
  108. package/dist/helpers.cjs +160 -5
  109. package/dist/helpers.cjs.map +1 -1
  110. package/dist/helpers.d.cts.map +1 -1
  111. package/dist/helpers.d.ts.map +1 -1
  112. package/dist/helpers.js +152 -6
  113. package/dist/helpers.js.map +1 -1
  114. package/dist/images.cjs +24 -6
  115. package/dist/images.cjs.map +1 -1
  116. package/dist/images.d.cts +11 -3
  117. package/dist/images.d.cts.map +1 -1
  118. package/dist/images.d.ts +11 -3
  119. package/dist/images.d.ts.map +1 -1
  120. package/dist/images.js +25 -7
  121. package/dist/images.js.map +1 -1
  122. package/dist/index.cjs +7 -0
  123. package/dist/index.d.cts +2 -1
  124. package/dist/index.d.ts +2 -1
  125. package/dist/index.js +2 -1
  126. package/dist/llmock.cjs +15 -0
  127. package/dist/llmock.cjs.map +1 -1
  128. package/dist/llmock.d.cts +12 -0
  129. package/dist/llmock.d.cts.map +1 -1
  130. package/dist/llmock.d.ts +12 -0
  131. package/dist/llmock.d.ts.map +1 -1
  132. package/dist/llmock.js +16 -1
  133. package/dist/llmock.js.map +1 -1
  134. package/dist/mcp-mock.cjs +11 -0
  135. package/dist/mcp-mock.cjs.map +1 -1
  136. package/dist/mcp-mock.d.cts.map +1 -1
  137. package/dist/mcp-mock.d.ts.map +1 -1
  138. package/dist/mcp-mock.js +11 -0
  139. package/dist/mcp-mock.js.map +1 -1
  140. package/dist/messages.cjs +18 -1
  141. package/dist/messages.cjs.map +1 -1
  142. package/dist/messages.d.cts.map +1 -1
  143. package/dist/messages.d.ts.map +1 -1
  144. package/dist/messages.js +19 -2
  145. package/dist/messages.js.map +1 -1
  146. package/dist/metrics.cjs +20 -0
  147. package/dist/metrics.cjs.map +1 -1
  148. package/dist/metrics.d.cts.map +1 -1
  149. package/dist/metrics.d.ts.map +1 -1
  150. package/dist/metrics.js +19 -1
  151. package/dist/metrics.js.map +1 -1
  152. package/dist/moderation.cjs +67 -3
  153. package/dist/moderation.cjs.map +1 -1
  154. package/dist/moderation.d.cts +1 -0
  155. package/dist/moderation.d.cts.map +1 -1
  156. package/dist/moderation.d.ts +1 -0
  157. package/dist/moderation.d.ts.map +1 -1
  158. package/dist/moderation.js +68 -4
  159. package/dist/moderation.js.map +1 -1
  160. package/dist/ollama.cjs +75 -5
  161. package/dist/ollama.cjs.map +1 -1
  162. package/dist/ollama.d.cts.map +1 -1
  163. package/dist/ollama.d.ts.map +1 -1
  164. package/dist/ollama.js +76 -6
  165. package/dist/ollama.js.map +1 -1
  166. package/dist/openrouter-video.cjs +4 -4
  167. package/dist/openrouter-video.cjs.map +1 -1
  168. package/dist/openrouter-video.d.cts.map +1 -1
  169. package/dist/openrouter-video.d.ts.map +1 -1
  170. package/dist/openrouter-video.js +4 -4
  171. package/dist/openrouter-video.js.map +1 -1
  172. package/dist/provider-auth.cjs +2 -0
  173. package/dist/provider-auth.cjs.map +1 -1
  174. package/dist/provider-auth.js +2 -0
  175. package/dist/provider-auth.js.map +1 -1
  176. package/dist/rerank.cjs +65 -2
  177. package/dist/rerank.cjs.map +1 -1
  178. package/dist/rerank.d.cts +1 -1
  179. package/dist/rerank.d.cts.map +1 -1
  180. package/dist/rerank.d.ts +1 -1
  181. package/dist/rerank.d.ts.map +1 -1
  182. package/dist/rerank.js +66 -3
  183. package/dist/rerank.js.map +1 -1
  184. package/dist/responses.cjs +18 -1
  185. package/dist/responses.cjs.map +1 -1
  186. package/dist/responses.d.cts.map +1 -1
  187. package/dist/responses.d.ts.map +1 -1
  188. package/dist/responses.js +19 -2
  189. package/dist/responses.js.map +1 -1
  190. package/dist/router.cjs +1 -0
  191. package/dist/router.cjs.map +1 -1
  192. package/dist/router.d.cts.map +1 -1
  193. package/dist/router.d.ts.map +1 -1
  194. package/dist/router.js +1 -0
  195. package/dist/router.js.map +1 -1
  196. package/dist/search.cjs +67 -3
  197. package/dist/search.cjs.map +1 -1
  198. package/dist/search.d.cts +1 -0
  199. package/dist/search.d.cts.map +1 -1
  200. package/dist/search.d.ts +1 -0
  201. package/dist/search.d.ts.map +1 -1
  202. package/dist/search.js +68 -4
  203. package/dist/search.js.map +1 -1
  204. package/dist/server.cjs +406 -17
  205. package/dist/server.cjs.map +1 -1
  206. package/dist/server.d.cts +2 -0
  207. package/dist/server.d.cts.map +1 -1
  208. package/dist/server.d.ts +2 -0
  209. package/dist/server.d.ts.map +1 -1
  210. package/dist/server.js +410 -21
  211. package/dist/server.js.map +1 -1
  212. package/dist/speech.cjs +18 -1
  213. package/dist/speech.cjs.map +1 -1
  214. package/dist/speech.d.cts.map +1 -1
  215. package/dist/speech.d.ts.map +1 -1
  216. package/dist/speech.js +19 -2
  217. package/dist/speech.js.map +1 -1
  218. package/dist/stream-collapse.cjs +2 -1
  219. package/dist/stream-collapse.cjs.map +1 -1
  220. package/dist/stream-collapse.js +2 -1
  221. package/dist/stream-collapse.js.map +1 -1
  222. package/dist/transcription.cjs +21 -2
  223. package/dist/transcription.cjs.map +1 -1
  224. package/dist/transcription.d.cts.map +1 -1
  225. package/dist/transcription.d.ts.map +1 -1
  226. package/dist/transcription.js +21 -2
  227. package/dist/transcription.js.map +1 -1
  228. package/dist/types.d.cts +58 -5
  229. package/dist/types.d.cts.map +1 -1
  230. package/dist/types.d.ts +58 -5
  231. package/dist/types.d.ts.map +1 -1
  232. package/dist/vector-mock.cjs +88 -0
  233. package/dist/vector-mock.cjs.map +1 -1
  234. package/dist/vector-mock.d.cts.map +1 -1
  235. package/dist/vector-mock.d.ts.map +1 -1
  236. package/dist/vector-mock.js +89 -1
  237. package/dist/vector-mock.js.map +1 -1
  238. package/dist/vector-types.d.cts.map +1 -1
  239. package/dist/veo-video.cjs +2 -2
  240. package/dist/veo-video.cjs.map +1 -1
  241. package/dist/veo-video.d.cts.map +1 -1
  242. package/dist/veo-video.d.ts.map +1 -1
  243. package/dist/veo-video.js +2 -2
  244. package/dist/veo-video.js.map +1 -1
  245. package/dist/video.cjs +19 -2
  246. package/dist/video.cjs.map +1 -1
  247. package/dist/video.d.cts.map +1 -1
  248. package/dist/video.d.ts.map +1 -1
  249. package/dist/video.js +20 -3
  250. package/dist/video.js.map +1 -1
  251. package/package.json +2 -2
@@ -8,10 +8,29 @@ const require_recorder = require('./recorder.cjs');
8
8
  //#region src/transcription.ts
9
9
  /**
10
10
  * Extract the multipart boundary string from a Content-Type header.
11
+ *
12
+ * RFC 2046 §5.1.1 defines the boundary parameter as either a bare token
13
+ * (`boundary=abc123`) or a quoted-string (`boundary="abc123"`), and its
14
+ * `bchars` production INCLUDES a space — which is exactly the case the quoted
15
+ * form exists for, and the one a capture that stops at whitespace can never
16
+ * read. So the quotes are consumed BY the match rather than stripped after it:
17
+ * a post-strip runs on an already-truncated value and leaves `boundary="a b c"`
18
+ * as the useless `"a`, and the delimiter then never matches, so every form
19
+ * field silently falls back to its default (`whisper-1`, `dall-e-2`, …).
20
+ *
21
+ * Only DQUOTE quotes. An apostrophe is a legal RFC 2045 token character and a
22
+ * legal RFC 2046 `bchar`, so `boundary='abc'` is a BARE token whose value
23
+ * literally includes the quotes, and stripping them would break a working
24
+ * request.
25
+ *
26
+ * The `(?:^|[;\s])` prefix keeps a decoy parameter such as `myboundary=` from
27
+ * matching, and `\s*=\s*` tolerates the LWSP some clients put around the `=`.
11
28
  */
12
29
  function extractBoundary(contentType) {
13
30
  if (!contentType) return void 0;
14
- return contentType.match(/boundary=([^\s;]+)/i)?.[1];
31
+ const match = contentType.match(/(?:^|[;\s])boundary\s*=\s*(?:"([^"]*)"|([^\s;]+))/i);
32
+ if (!match) return void 0;
33
+ return (match[1] !== void 0 ? match[1] : match[2]) || void 0;
15
34
  }
16
35
  /**
17
36
  * Extract a text field from multipart form data using boundary-based parsing.
@@ -60,7 +79,7 @@ async function handleTranscription(req, res, raw, fixtures, journal, defaults, s
60
79
  journal.incrementFixtureMatchCount(fixture, fixtures, testId);
61
80
  defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
62
81
  } else defaults.logger.debug(`No fixture matched for request`);
63
- if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
82
+ if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, req.url, journal, {
64
83
  method,
65
84
  path,
66
85
  headers: require_helpers.flattenHeaders(req.headers),
@@ -1 +1 @@
1
- {"version":3,"file":"transcription.cjs","names":["getContext","getTestId","matchFixtureDiagnostic","applyChaos","flattenHeaders","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isTranscriptionResponse","createInterruptionSignal","calculateDelay","delay"],"sources":["../src/transcription.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isTranscriptionResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { calculateDelay, delay, writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\n\n/**\n * Extract the multipart boundary string from a Content-Type header.\n */\nexport function extractBoundary(contentType: string | undefined): string | undefined {\n if (!contentType) return undefined;\n const match = contentType.match(/boundary=([^\\s;]+)/i);\n return match?.[1];\n}\n\n/**\n * Extract a text field from multipart form data using boundary-based parsing.\n * Splits the body by the multipart boundary so each part is isolated, then\n * checks each part's Content-Disposition header for the target field name.\n * This avoids false matches from binary audio data that might contain\n * header-like byte sequences.\n */\nexport function extractFormField(\n raw: string,\n fieldName: string,\n boundary: string | undefined,\n): string | undefined {\n if (!boundary) {\n // Fallback: no boundary available, use simple regex (best-effort)\n console.warn(\"extractFormField: no multipart boundary found, using best-effort regex fallback\");\n const escaped = fieldName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(\n `Content-Disposition:\\\\s*form-data;[^\\\\r\\\\n]*name=\"${escaped}\"[^\\\\r\\\\n]*\\\\r\\\\n\\\\r\\\\n([^\\\\r\\\\n]*)`,\n \"i\",\n );\n const match = raw.match(pattern);\n return match?.[1];\n }\n\n // Split by boundary delimiter — each chunk is one part\n const delimiter = `--${boundary}`;\n const parts = raw.split(delimiter);\n\n for (const part of parts) {\n // Skip the preamble (before first boundary) and epilogue (after closing boundary)\n if (!part || part.trimStart().startsWith(\"--\")) continue;\n\n // Split part into headers and body at the first blank line (\\r\\n\\r\\n)\n const headerEnd = part.indexOf(\"\\r\\n\\r\\n\");\n if (headerEnd === -1) continue;\n\n const headers = part.slice(0, headerEnd);\n const body = part.slice(headerEnd + 4);\n\n // Check if this part's Content-Disposition names the target field\n const cdMatch = headers.match(/Content-Disposition:\\s*form-data;[^\\r\\n]*name=\"([^\"]+)\"/i);\n if (cdMatch && cdMatch[1] === fieldName) {\n // Return the body value, trimming trailing \\r\\n from the part boundary\n return body.replace(/\\r\\n$/, \"\");\n }\n }\n return undefined;\n}\n\nexport async function handleTranscription(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n endpointType: \"transcription\" | \"translation\" = \"transcription\",\n): Promise<void> {\n setCorsHeaders(res);\n const defaultPath =\n endpointType === \"translation\" ? \"/v1/audio/translations\" : \"/v1/audio/transcriptions\";\n const path = req.url ?? defaultPath;\n const method = req.method ?? \"POST\";\n\n const contentType = Array.isArray(req.headers[\"content-type\"])\n ? req.headers[\"content-type\"][0]\n : req.headers[\"content-type\"];\n const boundary = extractBoundary(contentType);\n\n const model = extractFormField(raw, \"model\", boundary) ?? \"whisper-1\";\n const responseFormat = extractFormField(raw, \"response_format\", boundary) ?? \"json\";\n const stream = extractFormField(raw, \"stream\", boundary) === \"true\";\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [],\n _endpointType: endpointType,\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? defaultPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n if (!isTranscriptionResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a transcription type\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n const journalEntry = journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const t = response.transcription;\n\n // Only the transcription endpoint streams modern models. Whisper-1 ignores\n // `stream=true`, and translations continue to return their JSON response.\n if (endpointType === \"transcription\" && stream && model !== \"whisper-1\") {\n const done = {\n type: \"transcript.text.done\",\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n };\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n let chunkIndex = 0;\n const interruption = createInterruptionSignal(fixture);\n for (let index = 0; index < t.text.length; index += chunkSize) {\n const chunkDelay = calculateDelay(\n chunkIndex,\n fixture.streamingProfile,\n latency,\n fixture.recordedTimings,\n replaySpeed,\n );\n if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);\n if (interruption?.signal.aborted) break;\n res.write(\n `data: ${JSON.stringify({ type: \"transcript.text.delta\", delta: t.text.slice(index, index + chunkSize) })}\\n\\n`,\n );\n interruption?.tick();\n chunkIndex++;\n }\n if (interruption?.signal.aborted) {\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption.reason();\n interruption.cleanup();\n res.destroy();\n return;\n }\n res.write(`data: ${JSON.stringify(done)}\\n\\n`);\n // The live `gpt-transcribe&stream=true` stream ends with the `[DONE]`\n // sentinel after `transcript.text.done`. Omitting it leaves clients that\n // loop until the sentinel waiting on a stream that never terminates.\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n interruption?.cleanup();\n return;\n }\n\n const useVerbose = responseFormat === \"verbose_json\" || t.words != null || t.segments != null;\n\n if (useVerbose) {\n const verboseBody: Record<string, unknown> = {\n task: endpointType === \"translation\" ? \"translate\" : \"transcribe\",\n language: t.language ?? \"english\",\n duration: t.duration ?? 0,\n text: t.text,\n };\n if (t.words && t.words.length > 0) {\n verboseBody.words = t.words;\n }\n if (t.segments && t.segments.length > 0) {\n verboseBody.segments = t.segments;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(verboseBody));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n }),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transcription.cjs","names":["getContext","getTestId","matchFixtureDiagnostic","applyChaos","flattenHeaders","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isTranscriptionResponse","createInterruptionSignal","calculateDelay","delay"],"sources":["../src/transcription.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isTranscriptionResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { calculateDelay, delay, writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\n\n/**\n * Extract the multipart boundary string from a Content-Type header.\n *\n * RFC 2046 §5.1.1 defines the boundary parameter as either a bare token\n * (`boundary=abc123`) or a quoted-string (`boundary=\"abc123\"`), and its\n * `bchars` production INCLUDES a space — which is exactly the case the quoted\n * form exists for, and the one a capture that stops at whitespace can never\n * read. So the quotes are consumed BY the match rather than stripped after it:\n * a post-strip runs on an already-truncated value and leaves `boundary=\"a b c\"`\n * as the useless `\"a`, and the delimiter then never matches, so every form\n * field silently falls back to its default (`whisper-1`, `dall-e-2`, …).\n *\n * Only DQUOTE quotes. An apostrophe is a legal RFC 2045 token character and a\n * legal RFC 2046 `bchar`, so `boundary='abc'` is a BARE token whose value\n * literally includes the quotes, and stripping them would break a working\n * request.\n *\n * The `(?:^|[;\\s])` prefix keeps a decoy parameter such as `myboundary=` from\n * matching, and `\\s*=\\s*` tolerates the LWSP some clients put around the `=`.\n */\nexport function extractBoundary(contentType: string | undefined): string | undefined {\n if (!contentType) return undefined;\n const match = contentType.match(/(?:^|[;\\s])boundary\\s*=\\s*(?:\"([^\"]*)\"|([^\\s;]+))/i);\n if (!match) return undefined;\n // Group 1 is the quoted form (possibly the empty string), group 2 the bare\n // token; an empty boundary is meaningless, so it reads as absent.\n const boundary = match[1] !== undefined ? match[1] : match[2];\n return boundary || undefined;\n}\n\n/**\n * Extract a text field from multipart form data using boundary-based parsing.\n * Splits the body by the multipart boundary so each part is isolated, then\n * checks each part's Content-Disposition header for the target field name.\n * This avoids false matches from binary audio data that might contain\n * header-like byte sequences.\n */\nexport function extractFormField(\n raw: string,\n fieldName: string,\n boundary: string | undefined,\n): string | undefined {\n if (!boundary) {\n // Fallback: no boundary available, use simple regex (best-effort)\n console.warn(\"extractFormField: no multipart boundary found, using best-effort regex fallback\");\n const escaped = fieldName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(\n `Content-Disposition:\\\\s*form-data;[^\\\\r\\\\n]*name=\"${escaped}\"[^\\\\r\\\\n]*\\\\r\\\\n\\\\r\\\\n([^\\\\r\\\\n]*)`,\n \"i\",\n );\n const match = raw.match(pattern);\n return match?.[1];\n }\n\n // Split by boundary delimiter — each chunk is one part\n const delimiter = `--${boundary}`;\n const parts = raw.split(delimiter);\n\n for (const part of parts) {\n // Skip the preamble (before first boundary) and epilogue (after closing boundary)\n if (!part || part.trimStart().startsWith(\"--\")) continue;\n\n // Split part into headers and body at the first blank line (\\r\\n\\r\\n)\n const headerEnd = part.indexOf(\"\\r\\n\\r\\n\");\n if (headerEnd === -1) continue;\n\n const headers = part.slice(0, headerEnd);\n const body = part.slice(headerEnd + 4);\n\n // Check if this part's Content-Disposition names the target field\n const cdMatch = headers.match(/Content-Disposition:\\s*form-data;[^\\r\\n]*name=\"([^\"]+)\"/i);\n if (cdMatch && cdMatch[1] === fieldName) {\n // Return the body value, trimming trailing \\r\\n from the part boundary\n return body.replace(/\\r\\n$/, \"\");\n }\n }\n return undefined;\n}\n\nexport async function handleTranscription(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n endpointType: \"transcription\" | \"translation\" = \"transcription\",\n): Promise<void> {\n setCorsHeaders(res);\n const defaultPath =\n endpointType === \"translation\" ? \"/v1/audio/translations\" : \"/v1/audio/transcriptions\";\n const path = req.url ?? defaultPath;\n const method = req.method ?? \"POST\";\n\n const contentType = Array.isArray(req.headers[\"content-type\"])\n ? req.headers[\"content-type\"][0]\n : req.headers[\"content-type\"];\n const boundary = extractBoundary(contentType);\n\n const model = extractFormField(raw, \"model\", boundary) ?? \"whisper-1\";\n const responseFormat = extractFormField(raw, \"response_format\", boundary) ?? \"json\";\n const stream = extractFormField(raw, \"stream\", boundary) === \"true\";\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [],\n _endpointType: endpointType,\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? defaultPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n if (!isTranscriptionResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a transcription type\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n const journalEntry = journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const t = response.transcription;\n\n // Only the transcription endpoint streams modern models. Whisper-1 ignores\n // `stream=true`, and translations continue to return their JSON response.\n if (endpointType === \"transcription\" && stream && model !== \"whisper-1\") {\n const done = {\n type: \"transcript.text.done\",\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n };\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n let chunkIndex = 0;\n const interruption = createInterruptionSignal(fixture);\n for (let index = 0; index < t.text.length; index += chunkSize) {\n const chunkDelay = calculateDelay(\n chunkIndex,\n fixture.streamingProfile,\n latency,\n fixture.recordedTimings,\n replaySpeed,\n );\n if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);\n if (interruption?.signal.aborted) break;\n res.write(\n `data: ${JSON.stringify({ type: \"transcript.text.delta\", delta: t.text.slice(index, index + chunkSize) })}\\n\\n`,\n );\n interruption?.tick();\n chunkIndex++;\n }\n if (interruption?.signal.aborted) {\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption.reason();\n interruption.cleanup();\n res.destroy();\n return;\n }\n res.write(`data: ${JSON.stringify(done)}\\n\\n`);\n // The live `gpt-transcribe&stream=true` stream ends with the `[DONE]`\n // sentinel after `transcript.text.done`. Omitting it leaves clients that\n // loop until the sentinel waiting on a stream that never terminates.\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n interruption?.cleanup();\n return;\n }\n\n const useVerbose = responseFormat === \"verbose_json\" || t.words != null || t.segments != null;\n\n if (useVerbose) {\n const verboseBody: Record<string, unknown> = {\n task: endpointType === \"translation\" ? \"translate\" : \"transcribe\",\n language: t.language ?? \"english\",\n duration: t.duration ?? 0,\n text: t.text,\n };\n if (t.words && t.words.length > 0) {\n verboseBody.words = t.words;\n }\n if (t.segments && t.segments.length > 0) {\n verboseBody.segments = t.segments;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(verboseBody));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n }),\n );\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"transcription.d.cts","names":[],"sources":["../src/transcription.ts"],"sourcesContent":[],"mappings":";;;;;;iBAgFsB,mBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0EAE1B"}
1
+ {"version":3,"file":"transcription.d.cts","names":[],"sources":["../src/transcription.ts"],"sourcesContent":[],"mappings":";;;;;;iBAqGsB,mBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0EAE1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"transcription.d.ts","names":[],"sources":["../src/transcription.ts"],"sourcesContent":[],"mappings":";;;;;;iBAgFsB,mBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0EAE1B"}
1
+ {"version":3,"file":"transcription.d.ts","names":[],"sources":["../src/transcription.ts"],"sourcesContent":[],"mappings":";;;;;;iBAqGsB,mBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0EAE1B"}
@@ -8,10 +8,29 @@ import { proxyAndRecord } from "./recorder.js";
8
8
  //#region src/transcription.ts
9
9
  /**
10
10
  * Extract the multipart boundary string from a Content-Type header.
11
+ *
12
+ * RFC 2046 §5.1.1 defines the boundary parameter as either a bare token
13
+ * (`boundary=abc123`) or a quoted-string (`boundary="abc123"`), and its
14
+ * `bchars` production INCLUDES a space — which is exactly the case the quoted
15
+ * form exists for, and the one a capture that stops at whitespace can never
16
+ * read. So the quotes are consumed BY the match rather than stripped after it:
17
+ * a post-strip runs on an already-truncated value and leaves `boundary="a b c"`
18
+ * as the useless `"a`, and the delimiter then never matches, so every form
19
+ * field silently falls back to its default (`whisper-1`, `dall-e-2`, …).
20
+ *
21
+ * Only DQUOTE quotes. An apostrophe is a legal RFC 2045 token character and a
22
+ * legal RFC 2046 `bchar`, so `boundary='abc'` is a BARE token whose value
23
+ * literally includes the quotes, and stripping them would break a working
24
+ * request.
25
+ *
26
+ * The `(?:^|[;\s])` prefix keeps a decoy parameter such as `myboundary=` from
27
+ * matching, and `\s*=\s*` tolerates the LWSP some clients put around the `=`.
11
28
  */
12
29
  function extractBoundary(contentType) {
13
30
  if (!contentType) return void 0;
14
- return contentType.match(/boundary=([^\s;]+)/i)?.[1];
31
+ const match = contentType.match(/(?:^|[;\s])boundary\s*=\s*(?:"([^"]*)"|([^\s;]+))/i);
32
+ if (!match) return void 0;
33
+ return (match[1] !== void 0 ? match[1] : match[2]) || void 0;
15
34
  }
16
35
  /**
17
36
  * Extract a text field from multipart form data using boundary-based parsing.
@@ -60,7 +79,7 @@ async function handleTranscription(req, res, raw, fixtures, journal, defaults, s
60
79
  journal.incrementFixtureMatchCount(fixture, fixtures, testId);
61
80
  defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
62
81
  } else defaults.logger.debug(`No fixture matched for request`);
63
- if (applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
82
+ if (applyChaos(res, fixture, defaults.chaos, req.headers, req.url, journal, {
64
83
  method,
65
84
  path,
66
85
  headers: flattenHeaders(req.headers),
@@ -1 +1 @@
1
- {"version":3,"file":"transcription.js","names":[],"sources":["../src/transcription.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isTranscriptionResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { calculateDelay, delay, writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\n\n/**\n * Extract the multipart boundary string from a Content-Type header.\n */\nexport function extractBoundary(contentType: string | undefined): string | undefined {\n if (!contentType) return undefined;\n const match = contentType.match(/boundary=([^\\s;]+)/i);\n return match?.[1];\n}\n\n/**\n * Extract a text field from multipart form data using boundary-based parsing.\n * Splits the body by the multipart boundary so each part is isolated, then\n * checks each part's Content-Disposition header for the target field name.\n * This avoids false matches from binary audio data that might contain\n * header-like byte sequences.\n */\nexport function extractFormField(\n raw: string,\n fieldName: string,\n boundary: string | undefined,\n): string | undefined {\n if (!boundary) {\n // Fallback: no boundary available, use simple regex (best-effort)\n console.warn(\"extractFormField: no multipart boundary found, using best-effort regex fallback\");\n const escaped = fieldName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(\n `Content-Disposition:\\\\s*form-data;[^\\\\r\\\\n]*name=\"${escaped}\"[^\\\\r\\\\n]*\\\\r\\\\n\\\\r\\\\n([^\\\\r\\\\n]*)`,\n \"i\",\n );\n const match = raw.match(pattern);\n return match?.[1];\n }\n\n // Split by boundary delimiter — each chunk is one part\n const delimiter = `--${boundary}`;\n const parts = raw.split(delimiter);\n\n for (const part of parts) {\n // Skip the preamble (before first boundary) and epilogue (after closing boundary)\n if (!part || part.trimStart().startsWith(\"--\")) continue;\n\n // Split part into headers and body at the first blank line (\\r\\n\\r\\n)\n const headerEnd = part.indexOf(\"\\r\\n\\r\\n\");\n if (headerEnd === -1) continue;\n\n const headers = part.slice(0, headerEnd);\n const body = part.slice(headerEnd + 4);\n\n // Check if this part's Content-Disposition names the target field\n const cdMatch = headers.match(/Content-Disposition:\\s*form-data;[^\\r\\n]*name=\"([^\"]+)\"/i);\n if (cdMatch && cdMatch[1] === fieldName) {\n // Return the body value, trimming trailing \\r\\n from the part boundary\n return body.replace(/\\r\\n$/, \"\");\n }\n }\n return undefined;\n}\n\nexport async function handleTranscription(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n endpointType: \"transcription\" | \"translation\" = \"transcription\",\n): Promise<void> {\n setCorsHeaders(res);\n const defaultPath =\n endpointType === \"translation\" ? \"/v1/audio/translations\" : \"/v1/audio/transcriptions\";\n const path = req.url ?? defaultPath;\n const method = req.method ?? \"POST\";\n\n const contentType = Array.isArray(req.headers[\"content-type\"])\n ? req.headers[\"content-type\"][0]\n : req.headers[\"content-type\"];\n const boundary = extractBoundary(contentType);\n\n const model = extractFormField(raw, \"model\", boundary) ?? \"whisper-1\";\n const responseFormat = extractFormField(raw, \"response_format\", boundary) ?? \"json\";\n const stream = extractFormField(raw, \"stream\", boundary) === \"true\";\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [],\n _endpointType: endpointType,\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? defaultPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n if (!isTranscriptionResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a transcription type\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n const journalEntry = journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const t = response.transcription;\n\n // Only the transcription endpoint streams modern models. Whisper-1 ignores\n // `stream=true`, and translations continue to return their JSON response.\n if (endpointType === \"transcription\" && stream && model !== \"whisper-1\") {\n const done = {\n type: \"transcript.text.done\",\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n };\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n let chunkIndex = 0;\n const interruption = createInterruptionSignal(fixture);\n for (let index = 0; index < t.text.length; index += chunkSize) {\n const chunkDelay = calculateDelay(\n chunkIndex,\n fixture.streamingProfile,\n latency,\n fixture.recordedTimings,\n replaySpeed,\n );\n if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);\n if (interruption?.signal.aborted) break;\n res.write(\n `data: ${JSON.stringify({ type: \"transcript.text.delta\", delta: t.text.slice(index, index + chunkSize) })}\\n\\n`,\n );\n interruption?.tick();\n chunkIndex++;\n }\n if (interruption?.signal.aborted) {\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption.reason();\n interruption.cleanup();\n res.destroy();\n return;\n }\n res.write(`data: ${JSON.stringify(done)}\\n\\n`);\n // The live `gpt-transcribe&stream=true` stream ends with the `[DONE]`\n // sentinel after `transcript.text.done`. Omitting it leaves clients that\n // loop until the sentinel waiting on a stream that never terminates.\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n interruption?.cleanup();\n return;\n }\n\n const useVerbose = responseFormat === \"verbose_json\" || t.words != null || t.segments != null;\n\n if (useVerbose) {\n const verboseBody: Record<string, unknown> = {\n task: endpointType === \"translation\" ? \"translate\" : \"transcribe\",\n language: t.language ?? \"english\",\n duration: t.duration ?? 0,\n text: t.text,\n };\n if (t.words && t.words.length > 0) {\n verboseBody.words = t.words;\n }\n if (t.segments && t.segments.length > 0) {\n verboseBody.segments = t.segments;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(verboseBody));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n }),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transcription.js","names":[],"sources":["../src/transcription.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isTranscriptionResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { calculateDelay, delay, writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\n\n/**\n * Extract the multipart boundary string from a Content-Type header.\n *\n * RFC 2046 §5.1.1 defines the boundary parameter as either a bare token\n * (`boundary=abc123`) or a quoted-string (`boundary=\"abc123\"`), and its\n * `bchars` production INCLUDES a space — which is exactly the case the quoted\n * form exists for, and the one a capture that stops at whitespace can never\n * read. So the quotes are consumed BY the match rather than stripped after it:\n * a post-strip runs on an already-truncated value and leaves `boundary=\"a b c\"`\n * as the useless `\"a`, and the delimiter then never matches, so every form\n * field silently falls back to its default (`whisper-1`, `dall-e-2`, …).\n *\n * Only DQUOTE quotes. An apostrophe is a legal RFC 2045 token character and a\n * legal RFC 2046 `bchar`, so `boundary='abc'` is a BARE token whose value\n * literally includes the quotes, and stripping them would break a working\n * request.\n *\n * The `(?:^|[;\\s])` prefix keeps a decoy parameter such as `myboundary=` from\n * matching, and `\\s*=\\s*` tolerates the LWSP some clients put around the `=`.\n */\nexport function extractBoundary(contentType: string | undefined): string | undefined {\n if (!contentType) return undefined;\n const match = contentType.match(/(?:^|[;\\s])boundary\\s*=\\s*(?:\"([^\"]*)\"|([^\\s;]+))/i);\n if (!match) return undefined;\n // Group 1 is the quoted form (possibly the empty string), group 2 the bare\n // token; an empty boundary is meaningless, so it reads as absent.\n const boundary = match[1] !== undefined ? match[1] : match[2];\n return boundary || undefined;\n}\n\n/**\n * Extract a text field from multipart form data using boundary-based parsing.\n * Splits the body by the multipart boundary so each part is isolated, then\n * checks each part's Content-Disposition header for the target field name.\n * This avoids false matches from binary audio data that might contain\n * header-like byte sequences.\n */\nexport function extractFormField(\n raw: string,\n fieldName: string,\n boundary: string | undefined,\n): string | undefined {\n if (!boundary) {\n // Fallback: no boundary available, use simple regex (best-effort)\n console.warn(\"extractFormField: no multipart boundary found, using best-effort regex fallback\");\n const escaped = fieldName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(\n `Content-Disposition:\\\\s*form-data;[^\\\\r\\\\n]*name=\"${escaped}\"[^\\\\r\\\\n]*\\\\r\\\\n\\\\r\\\\n([^\\\\r\\\\n]*)`,\n \"i\",\n );\n const match = raw.match(pattern);\n return match?.[1];\n }\n\n // Split by boundary delimiter — each chunk is one part\n const delimiter = `--${boundary}`;\n const parts = raw.split(delimiter);\n\n for (const part of parts) {\n // Skip the preamble (before first boundary) and epilogue (after closing boundary)\n if (!part || part.trimStart().startsWith(\"--\")) continue;\n\n // Split part into headers and body at the first blank line (\\r\\n\\r\\n)\n const headerEnd = part.indexOf(\"\\r\\n\\r\\n\");\n if (headerEnd === -1) continue;\n\n const headers = part.slice(0, headerEnd);\n const body = part.slice(headerEnd + 4);\n\n // Check if this part's Content-Disposition names the target field\n const cdMatch = headers.match(/Content-Disposition:\\s*form-data;[^\\r\\n]*name=\"([^\"]+)\"/i);\n if (cdMatch && cdMatch[1] === fieldName) {\n // Return the body value, trimming trailing \\r\\n from the part boundary\n return body.replace(/\\r\\n$/, \"\");\n }\n }\n return undefined;\n}\n\nexport async function handleTranscription(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n endpointType: \"transcription\" | \"translation\" = \"transcription\",\n): Promise<void> {\n setCorsHeaders(res);\n const defaultPath =\n endpointType === \"translation\" ? \"/v1/audio/translations\" : \"/v1/audio/transcriptions\";\n const path = req.url ?? defaultPath;\n const method = req.method ?? \"POST\";\n\n const contentType = Array.isArray(req.headers[\"content-type\"])\n ? req.headers[\"content-type\"][0]\n : req.headers[\"content-type\"];\n const boundary = extractBoundary(contentType);\n\n const model = extractFormField(raw, \"model\", boundary) ?? \"whisper-1\";\n const responseFormat = extractFormField(raw, \"response_format\", boundary) ?? \"json\";\n const stream = extractFormField(raw, \"stream\", boundary) === \"true\";\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [],\n _endpointType: endpointType,\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? defaultPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n if (!isTranscriptionResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a transcription type\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n const journalEntry = journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const t = response.transcription;\n\n // Only the transcription endpoint streams modern models. Whisper-1 ignores\n // `stream=true`, and translations continue to return their JSON response.\n if (endpointType === \"transcription\" && stream && model !== \"whisper-1\") {\n const done = {\n type: \"transcript.text.done\",\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n };\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n let chunkIndex = 0;\n const interruption = createInterruptionSignal(fixture);\n for (let index = 0; index < t.text.length; index += chunkSize) {\n const chunkDelay = calculateDelay(\n chunkIndex,\n fixture.streamingProfile,\n latency,\n fixture.recordedTimings,\n replaySpeed,\n );\n if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);\n if (interruption?.signal.aborted) break;\n res.write(\n `data: ${JSON.stringify({ type: \"transcript.text.delta\", delta: t.text.slice(index, index + chunkSize) })}\\n\\n`,\n );\n interruption?.tick();\n chunkIndex++;\n }\n if (interruption?.signal.aborted) {\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption.reason();\n interruption.cleanup();\n res.destroy();\n return;\n }\n res.write(`data: ${JSON.stringify(done)}\\n\\n`);\n // The live `gpt-transcribe&stream=true` stream ends with the `[DONE]`\n // sentinel after `transcript.text.done`. Omitting it leaves clients that\n // loop until the sentinel waiting on a stream that never terminates.\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n interruption?.cleanup();\n return;\n }\n\n const useVerbose = responseFormat === \"verbose_json\" || t.words != null || t.segments != null;\n\n if (useVerbose) {\n const verboseBody: Record<string, unknown> = {\n task: endpointType === \"translation\" ? \"translate\" : \"transcribe\",\n language: t.language ?? \"english\",\n duration: t.duration ?? 0,\n text: t.text,\n };\n if (t.words && t.words.length > 0) {\n verboseBody.words = t.words;\n }\n if (t.segments && t.segments.length > 0) {\n verboseBody.segments = t.segments;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(verboseBody));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n text: t.text,\n ...(t.languages !== undefined ? { languages: t.languages } : {}),\n ...(t.usage !== undefined ? { usage: t.usage } : {}),\n }),\n );\n }\n}\n"],"mappings":"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"}
package/dist/types.d.cts CHANGED
@@ -98,7 +98,7 @@ interface ChatCompletionRequest {
98
98
  * model string is the provider disambiguator (veo-* / grok-imagine-* /
99
99
  * openrouter ids do not overlap).
100
100
  */
101
- _videoProvider?: "openrouter" | "veo" | "grok";
101
+ _videoProvider?: "openrouter" | "veo" | "grok" | "byteplus";
102
102
  [key: string]: unknown;
103
103
  }
104
104
  interface ToolDefinition {
@@ -490,6 +490,34 @@ interface ChaosConfig {
490
490
  malformedRate?: number;
491
491
  disconnectRate?: number;
492
492
  }
493
+ /**
494
+ * Server-level chaos as the handlers see it: a baseline plus per-`X-Test-Id`
495
+ * overrides installed at runtime via `POST /__aimock/chaos`.
496
+ *
497
+ * Chaos is the LAST link in the precedence chain (request headers > fixture >
498
+ * server), and this makes that last link test-scoped, the way every other
499
+ * mutable axis in aimock is (fixture match-counts, video job maps). Under the
500
+ * shipped topology — one shared `aimock` process serving a parallel suite — a
501
+ * purely global switch would mean one test's chaos failing every other test.
502
+ *
503
+ * Scoping is by testId on BOTH sides: the traffic being evaluated and the
504
+ * control request that installed the override. Both resolve the tag the way
505
+ * `getTestId` does — the `X-Test-Id` header, else `?testId=` in the query
506
+ * string — so a harness that can only tag one of those two ways still lands in
507
+ * the same scope on both sides, and the two can never silently disagree.
508
+ */
509
+ interface ChaosScope {
510
+ /** Server-wide baseline: the construction config, or the untagged override. */
511
+ base?: ChaosConfig;
512
+ /** Per-testId overrides, consulted before `base`. */
513
+ byTestId?: ReadonlyMap<string, ChaosConfig>;
514
+ }
515
+ /**
516
+ * What `evaluateChaos` / `applyChaos` accept as server defaults. A plain
517
+ * `ChaosConfig` still works (it is what external callers pass); the server
518
+ * itself passes a `ChaosScope`.
519
+ */
520
+ type ChaosDefaults = ChaosConfig | ChaosScope;
493
521
  type ChaosAction = "drop" | "malformed" | "disconnect";
494
522
  type ResponseFactory = (req: ChatCompletionRequest) => FixtureResponse | Promise<FixtureResponse>;
495
523
  interface Fixture {
@@ -796,7 +824,7 @@ interface ChatCompletionMessage {
796
824
  reasoning?: string | null;
797
825
  tool_calls?: ToolCallMessage[];
798
826
  }
799
- type RecordProviderKey = "openai" | "anthropic" | "gemini" | "gemini-interactions" | "vertexai" | "bedrock" | "azure" | "ollama" | "cohere" | "elevenlabs" | "fal" | "openrouter" | "veo" | "grok";
827
+ type RecordProviderKey = "openai" | "anthropic" | "gemini" | "gemini-interactions" | "vertexai" | "bedrock" | "azure" | "ollama" | "cohere" | "elevenlabs" | "fal" | "openrouter" | "veo" | "grok" | "byteplus";
800
828
  interface RecordConfig {
801
829
  providers: Partial<Record<RecordProviderKey, string>>;
802
830
  /**
@@ -804,7 +832,7 @@ interface RecordConfig {
804
832
  * backward-compatible: when set for a provider, aimock injects the key on a
805
833
  * fixture-miss passthrough IF the caller sent no credential or a dummy
806
834
  * placeholder (see `applyProviderAuth`); a real caller key always overrides.
807
- * Only static-key providers are eligible: OpenAI/OpenRouter/Cohere/Grok/Ollama
835
+ * Only static-key providers are eligible: OpenAI/OpenRouter/Cohere/Grok/BytePlus/Ollama
808
836
  * (bearer), Anthropic (x-api-key), Gemini/Gemini-Interactions/Veo
809
837
  * (x-goog-api-key), Azure OpenAI (api-key), ElevenLabs (xi-api-key), and fal
810
838
  * (Authorization: Key). Signed/OAuth providers (Bedrock SigV4, Vertex AI
@@ -994,6 +1022,14 @@ interface MockServerOptions {
994
1022
  * poll count.
995
1023
  */
996
1024
  grokVideo?: FalQueueConfig;
1025
+ /**
1026
+ * Configure BytePlus Ark (Seedance) async video task polling progression
1027
+ * (`queued → running → <recorded terminal status>` on
1028
+ * `GET /api/v3/contents/generations/tasks/{id}`). Same threshold semantics as
1029
+ * `grokVideo`; unlike the others the TERMINAL status is not synthesized — it
1030
+ * is whatever the recorded/authored envelope carries.
1031
+ */
1032
+ bytePlusVideo?: FalQueueConfig;
997
1033
  }
998
1034
  interface ApiKeyAuthConfig {
999
1035
  apiKeys: readonly string[];
@@ -1034,7 +1070,16 @@ interface HandlerDefaults {
1034
1070
  chunkSize: number;
1035
1071
  replaySpeed: number;
1036
1072
  logger: Logger;
1037
- chaos?: ChaosConfig;
1073
+ /**
1074
+ * Reads resolve to a `ChaosScope` on a real server (baseline + per-testId
1075
+ * overrides); assigning `undefined` drops every runtime override.
1076
+ */
1077
+ chaos?: ChaosDefaults;
1078
+ /**
1079
+ * Live per-testId chaos overrides, owned by the server instance so the
1080
+ * control API can install one without reaching through the getter.
1081
+ */
1082
+ chaosByTestId?: Map<string, ChaosConfig>;
1038
1083
  registry?: MetricsRegistry;
1039
1084
  record?: RecordConfig;
1040
1085
  strict?: boolean;
@@ -1043,8 +1088,16 @@ interface HandlerDefaults {
1043
1088
  openRouterVideo?: FalQueueConfig;
1044
1089
  veoVideo?: FalQueueConfig;
1045
1090
  grokVideo?: FalQueueConfig;
1091
+ /**
1092
+ * Configure BytePlus Ark (Seedance) async video task polling progression
1093
+ * (`queued → running → <recorded terminal status>` on
1094
+ * `GET /api/v3/contents/generations/tasks/{id}`). Same threshold semantics as
1095
+ * `grokVideo`; unlike the others the TERMINAL status is not synthesized — it
1096
+ * is whatever the recorded/authored envelope carries.
1097
+ */
1098
+ bytePlusVideo?: FalQueueConfig;
1046
1099
  }
1047
1100
  //# sourceMappingURL=types.d.ts.map
1048
1101
  //#endregion
1049
- export { ApiKeyAuthConfig, AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, FalQueueOpts, Fixture, FixtureBlock, FixtureFile, FixtureFileBlock, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, RecordedTimings, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
1102
+ export { ApiKeyAuthConfig, AudioResponse, ChaosAction, ChaosConfig, ChaosDefaults, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, FalQueueOpts, Fixture, FixtureBlock, FixtureFile, FixtureFileBlock, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, RecordedTimings, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
1050
1103
  //# sourceMappingURL=types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -98,7 +98,7 @@ interface ChatCompletionRequest {
98
98
  * model string is the provider disambiguator (veo-* / grok-imagine-* /
99
99
  * openrouter ids do not overlap).
100
100
  */
101
- _videoProvider?: "openrouter" | "veo" | "grok";
101
+ _videoProvider?: "openrouter" | "veo" | "grok" | "byteplus";
102
102
  [key: string]: unknown;
103
103
  }
104
104
  interface ToolDefinition {
@@ -490,6 +490,34 @@ interface ChaosConfig {
490
490
  malformedRate?: number;
491
491
  disconnectRate?: number;
492
492
  }
493
+ /**
494
+ * Server-level chaos as the handlers see it: a baseline plus per-`X-Test-Id`
495
+ * overrides installed at runtime via `POST /__aimock/chaos`.
496
+ *
497
+ * Chaos is the LAST link in the precedence chain (request headers > fixture >
498
+ * server), and this makes that last link test-scoped, the way every other
499
+ * mutable axis in aimock is (fixture match-counts, video job maps). Under the
500
+ * shipped topology — one shared `aimock` process serving a parallel suite — a
501
+ * purely global switch would mean one test's chaos failing every other test.
502
+ *
503
+ * Scoping is by testId on BOTH sides: the traffic being evaluated and the
504
+ * control request that installed the override. Both resolve the tag the way
505
+ * `getTestId` does — the `X-Test-Id` header, else `?testId=` in the query
506
+ * string — so a harness that can only tag one of those two ways still lands in
507
+ * the same scope on both sides, and the two can never silently disagree.
508
+ */
509
+ interface ChaosScope {
510
+ /** Server-wide baseline: the construction config, or the untagged override. */
511
+ base?: ChaosConfig;
512
+ /** Per-testId overrides, consulted before `base`. */
513
+ byTestId?: ReadonlyMap<string, ChaosConfig>;
514
+ }
515
+ /**
516
+ * What `evaluateChaos` / `applyChaos` accept as server defaults. A plain
517
+ * `ChaosConfig` still works (it is what external callers pass); the server
518
+ * itself passes a `ChaosScope`.
519
+ */
520
+ type ChaosDefaults = ChaosConfig | ChaosScope;
493
521
  type ChaosAction = "drop" | "malformed" | "disconnect";
494
522
  type ResponseFactory = (req: ChatCompletionRequest) => FixtureResponse | Promise<FixtureResponse>;
495
523
  interface Fixture {
@@ -796,7 +824,7 @@ interface ChatCompletionMessage {
796
824
  reasoning?: string | null;
797
825
  tool_calls?: ToolCallMessage[];
798
826
  }
799
- type RecordProviderKey = "openai" | "anthropic" | "gemini" | "gemini-interactions" | "vertexai" | "bedrock" | "azure" | "ollama" | "cohere" | "elevenlabs" | "fal" | "openrouter" | "veo" | "grok";
827
+ type RecordProviderKey = "openai" | "anthropic" | "gemini" | "gemini-interactions" | "vertexai" | "bedrock" | "azure" | "ollama" | "cohere" | "elevenlabs" | "fal" | "openrouter" | "veo" | "grok" | "byteplus";
800
828
  interface RecordConfig {
801
829
  providers: Partial<Record<RecordProviderKey, string>>;
802
830
  /**
@@ -804,7 +832,7 @@ interface RecordConfig {
804
832
  * backward-compatible: when set for a provider, aimock injects the key on a
805
833
  * fixture-miss passthrough IF the caller sent no credential or a dummy
806
834
  * placeholder (see `applyProviderAuth`); a real caller key always overrides.
807
- * Only static-key providers are eligible: OpenAI/OpenRouter/Cohere/Grok/Ollama
835
+ * Only static-key providers are eligible: OpenAI/OpenRouter/Cohere/Grok/BytePlus/Ollama
808
836
  * (bearer), Anthropic (x-api-key), Gemini/Gemini-Interactions/Veo
809
837
  * (x-goog-api-key), Azure OpenAI (api-key), ElevenLabs (xi-api-key), and fal
810
838
  * (Authorization: Key). Signed/OAuth providers (Bedrock SigV4, Vertex AI
@@ -994,6 +1022,14 @@ interface MockServerOptions {
994
1022
  * poll count.
995
1023
  */
996
1024
  grokVideo?: FalQueueConfig;
1025
+ /**
1026
+ * Configure BytePlus Ark (Seedance) async video task polling progression
1027
+ * (`queued → running → <recorded terminal status>` on
1028
+ * `GET /api/v3/contents/generations/tasks/{id}`). Same threshold semantics as
1029
+ * `grokVideo`; unlike the others the TERMINAL status is not synthesized — it
1030
+ * is whatever the recorded/authored envelope carries.
1031
+ */
1032
+ bytePlusVideo?: FalQueueConfig;
997
1033
  }
998
1034
  interface ApiKeyAuthConfig {
999
1035
  apiKeys: readonly string[];
@@ -1034,7 +1070,16 @@ interface HandlerDefaults {
1034
1070
  chunkSize: number;
1035
1071
  replaySpeed: number;
1036
1072
  logger: Logger;
1037
- chaos?: ChaosConfig;
1073
+ /**
1074
+ * Reads resolve to a `ChaosScope` on a real server (baseline + per-testId
1075
+ * overrides); assigning `undefined` drops every runtime override.
1076
+ */
1077
+ chaos?: ChaosDefaults;
1078
+ /**
1079
+ * Live per-testId chaos overrides, owned by the server instance so the
1080
+ * control API can install one without reaching through the getter.
1081
+ */
1082
+ chaosByTestId?: Map<string, ChaosConfig>;
1038
1083
  registry?: MetricsRegistry;
1039
1084
  record?: RecordConfig;
1040
1085
  strict?: boolean;
@@ -1043,8 +1088,16 @@ interface HandlerDefaults {
1043
1088
  openRouterVideo?: FalQueueConfig;
1044
1089
  veoVideo?: FalQueueConfig;
1045
1090
  grokVideo?: FalQueueConfig;
1091
+ /**
1092
+ * Configure BytePlus Ark (Seedance) async video task polling progression
1093
+ * (`queued → running → <recorded terminal status>` on
1094
+ * `GET /api/v3/contents/generations/tasks/{id}`). Same threshold semantics as
1095
+ * `grokVideo`; unlike the others the TERMINAL status is not synthesized — it
1096
+ * is whatever the recorded/authored envelope carries.
1097
+ */
1098
+ bytePlusVideo?: FalQueueConfig;
1046
1099
  }
1047
1100
  //# sourceMappingURL=types.d.ts.map
1048
1101
  //#endregion
1049
- export { ApiKeyAuthConfig, AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, FalQueueOpts, Fixture, FixtureBlock, FixtureFile, FixtureFileBlock, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, RecordedTimings, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
1102
+ export { ApiKeyAuthConfig, AudioResponse, ChaosAction, ChaosConfig, ChaosDefaults, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, FalQueueOpts, Fixture, FixtureBlock, FixtureFile, FixtureFileBlock, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, RecordedTimings, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
1050
1103
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}