@copilotkit/aimock 1.25.0 → 1.26.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 (130) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +9 -0
  4. package/README.md +4 -0
  5. package/dist/aws-event-stream.cjs +2 -1
  6. package/dist/aws-event-stream.cjs.map +1 -1
  7. package/dist/aws-event-stream.d.cts +3 -1
  8. package/dist/aws-event-stream.d.cts.map +1 -1
  9. package/dist/aws-event-stream.d.ts +3 -1
  10. package/dist/aws-event-stream.d.ts.map +1 -1
  11. package/dist/aws-event-stream.js +2 -1
  12. package/dist/aws-event-stream.js.map +1 -1
  13. package/dist/bedrock-converse.cjs +6 -0
  14. package/dist/bedrock-converse.cjs.map +1 -1
  15. package/dist/bedrock-converse.js +6 -0
  16. package/dist/bedrock-converse.js.map +1 -1
  17. package/dist/bedrock.cjs +6 -0
  18. package/dist/bedrock.cjs.map +1 -1
  19. package/dist/bedrock.js +6 -0
  20. package/dist/bedrock.js.map +1 -1
  21. package/dist/cli.cjs +11 -0
  22. package/dist/cli.cjs.map +1 -1
  23. package/dist/cli.js +11 -0
  24. package/dist/cli.js.map +1 -1
  25. package/dist/cohere.cjs +8 -1
  26. package/dist/cohere.cjs.map +1 -1
  27. package/dist/cohere.d.cts.map +1 -1
  28. package/dist/cohere.d.ts.map +1 -1
  29. package/dist/cohere.js +8 -1
  30. package/dist/cohere.js.map +1 -1
  31. package/dist/config-loader.d.cts.map +1 -1
  32. package/dist/fixture-loader.cjs +16 -3
  33. package/dist/fixture-loader.cjs.map +1 -1
  34. package/dist/fixture-loader.d.cts.map +1 -1
  35. package/dist/fixture-loader.d.ts.map +1 -1
  36. package/dist/fixture-loader.js +16 -3
  37. package/dist/fixture-loader.js.map +1 -1
  38. package/dist/gemini-interactions.cjs +9 -1
  39. package/dist/gemini-interactions.cjs.map +1 -1
  40. package/dist/gemini-interactions.d.cts.map +1 -1
  41. package/dist/gemini-interactions.d.ts.map +1 -1
  42. package/dist/gemini-interactions.js +9 -1
  43. package/dist/gemini-interactions.js.map +1 -1
  44. package/dist/gemini.cjs +11 -1
  45. package/dist/gemini.cjs.map +1 -1
  46. package/dist/gemini.d.cts.map +1 -1
  47. package/dist/gemini.d.ts.map +1 -1
  48. package/dist/gemini.js +11 -1
  49. package/dist/gemini.js.map +1 -1
  50. package/dist/llmock.cjs +1 -1
  51. package/dist/llmock.cjs.map +1 -1
  52. package/dist/llmock.js +1 -1
  53. package/dist/llmock.js.map +1 -1
  54. package/dist/messages.cjs +8 -1
  55. package/dist/messages.cjs.map +1 -1
  56. package/dist/messages.d.cts.map +1 -1
  57. package/dist/messages.d.ts.map +1 -1
  58. package/dist/messages.js +8 -1
  59. package/dist/messages.js.map +1 -1
  60. package/dist/ndjson-writer.cjs +2 -1
  61. package/dist/ndjson-writer.cjs.map +1 -1
  62. package/dist/ndjson-writer.d.cts +3 -2
  63. package/dist/ndjson-writer.d.cts.map +1 -1
  64. package/dist/ndjson-writer.d.ts +3 -2
  65. package/dist/ndjson-writer.d.ts.map +1 -1
  66. package/dist/ndjson-writer.js +2 -1
  67. package/dist/ndjson-writer.js.map +1 -1
  68. package/dist/ollama.cjs +8 -0
  69. package/dist/ollama.cjs.map +1 -1
  70. package/dist/ollama.d.cts.map +1 -1
  71. package/dist/ollama.d.ts.map +1 -1
  72. package/dist/ollama.js +8 -0
  73. package/dist/ollama.js.map +1 -1
  74. package/dist/recorder.cjs +38 -1
  75. package/dist/recorder.cjs.map +1 -1
  76. package/dist/recorder.d.cts.map +1 -1
  77. package/dist/recorder.d.ts.map +1 -1
  78. package/dist/recorder.js +38 -1
  79. package/dist/recorder.js.map +1 -1
  80. package/dist/responses.cjs +10 -1
  81. package/dist/responses.cjs.map +1 -1
  82. package/dist/responses.d.cts.map +1 -1
  83. package/dist/responses.d.ts.map +1 -1
  84. package/dist/responses.js +10 -1
  85. package/dist/responses.js.map +1 -1
  86. package/dist/server.cjs +11 -4
  87. package/dist/server.cjs.map +1 -1
  88. package/dist/server.d.cts.map +1 -1
  89. package/dist/server.d.ts.map +1 -1
  90. package/dist/server.js +11 -4
  91. package/dist/server.js.map +1 -1
  92. package/dist/sse-writer.cjs +28 -8
  93. package/dist/sse-writer.cjs.map +1 -1
  94. package/dist/sse-writer.d.cts +4 -2
  95. package/dist/sse-writer.d.cts.map +1 -1
  96. package/dist/sse-writer.d.ts +4 -2
  97. package/dist/sse-writer.d.ts.map +1 -1
  98. package/dist/sse-writer.js +28 -8
  99. package/dist/sse-writer.js.map +1 -1
  100. package/dist/types.d.cts +17 -1
  101. package/dist/types.d.cts.map +1 -1
  102. package/dist/types.d.ts +17 -1
  103. package/dist/types.d.ts.map +1 -1
  104. package/dist/vector-types.d.cts.map +1 -1
  105. package/dist/vector-types.d.ts.map +1 -1
  106. package/dist/ws-gemini-live.cjs +14 -4
  107. package/dist/ws-gemini-live.cjs.map +1 -1
  108. package/dist/ws-gemini-live.d.cts +1 -0
  109. package/dist/ws-gemini-live.d.cts.map +1 -1
  110. package/dist/ws-gemini-live.d.ts +1 -0
  111. package/dist/ws-gemini-live.d.ts.map +1 -1
  112. package/dist/ws-gemini-live.js +15 -5
  113. package/dist/ws-gemini-live.js.map +1 -1
  114. package/dist/ws-realtime.cjs +21 -4
  115. package/dist/ws-realtime.cjs.map +1 -1
  116. package/dist/ws-realtime.d.cts +1 -0
  117. package/dist/ws-realtime.d.cts.map +1 -1
  118. package/dist/ws-realtime.d.ts +1 -0
  119. package/dist/ws-realtime.d.ts.map +1 -1
  120. package/dist/ws-realtime.js +22 -5
  121. package/dist/ws-realtime.js.map +1 -1
  122. package/dist/ws-responses.cjs +8 -5
  123. package/dist/ws-responses.cjs.map +1 -1
  124. package/dist/ws-responses.d.cts +1 -0
  125. package/dist/ws-responses.d.cts.map +1 -1
  126. package/dist/ws-responses.d.ts +1 -0
  127. package/dist/ws-responses.d.ts.map +1 -1
  128. package/dist/ws-responses.js +9 -6
  129. package/dist/ws-responses.js.map +1 -1
  130. package/package.json +1 -1
@@ -10,19 +10,39 @@ function delay(ms, signal) {
10
10
  }, { once: true });
11
11
  });
12
12
  }
13
- function calculateDelay(chunkIndex, profile, fallbackLatency) {
14
- if (!profile) return fallbackLatency ?? 0;
13
+ function calculateDelay(chunkIndex, profile, fallbackLatency, recordedTimings, replaySpeed) {
14
+ const speed = replaySpeed ?? 1;
15
15
  let delayMs;
16
- if (chunkIndex === 0 && profile.ttft !== void 0) delayMs = profile.ttft;
17
- else if (profile.tps !== void 0 && profile.tps > 0) delayMs = 1e3 / profile.tps;
18
- else return fallbackLatency ?? 0;
19
- if (profile.jitter && profile.jitter > 0) delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;
20
- return Math.max(0, delayMs);
16
+ if (profile) {
17
+ let fromProfile = true;
18
+ if (chunkIndex === 0 && profile.ttft !== void 0) delayMs = profile.ttft;
19
+ else if (profile.tps !== void 0 && profile.tps > 0) delayMs = 1e3 / profile.tps;
20
+ else {
21
+ delayMs = fallbackLatency ?? 0;
22
+ fromProfile = false;
23
+ }
24
+ if (fromProfile && profile.jitter && profile.jitter > 0) {
25
+ delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;
26
+ if (delayMs < 0) delayMs = 0;
27
+ }
28
+ } else if (recordedTimings) if (chunkIndex === 0) delayMs = recordedTimings.ttftMs;
29
+ else {
30
+ const idx = chunkIndex - 1;
31
+ if (idx < recordedTimings.interChunkDelaysMs.length) delayMs = recordedTimings.interChunkDelaysMs[idx];
32
+ else {
33
+ const totalInterChunk = recordedTimings.interChunkDelaysMs.reduce((a, b) => a + b, 0);
34
+ delayMs = recordedTimings.interChunkDelaysMs.length > 0 ? totalInterChunk / recordedTimings.interChunkDelaysMs.length : 0;
35
+ }
36
+ }
37
+ else delayMs = fallbackLatency ?? 0;
38
+ delayMs = Math.max(0, delayMs);
39
+ return speed > 0 ? delayMs / speed : delayMs;
21
40
  }
22
41
  async function writeSSEStream(res, chunks, optionsOrLatency) {
23
42
  const opts = typeof optionsOrLatency === "number" ? { latency: optionsOrLatency } : optionsOrLatency ?? {};
24
43
  const latency = opts.latency ?? 0;
25
44
  const profile = opts.streamingProfile;
45
+ const { recordedTimings, replaySpeed } = opts;
26
46
  const signal = opts.signal;
27
47
  const onChunkSent = opts.onChunkSent;
28
48
  if (res.writableEnded) return true;
@@ -31,7 +51,7 @@ async function writeSSEStream(res, chunks, optionsOrLatency) {
31
51
  res.setHeader("Connection", "keep-alive");
32
52
  let chunkIndex = 0;
33
53
  for (const chunk of chunks) {
34
- const chunkDelay = calculateDelay(chunkIndex, profile, latency);
54
+ const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);
35
55
  if (chunkDelay > 0) await delay(chunkDelay, signal);
36
56
  if (signal?.aborted) return false;
37
57
  if (res.writableEnded) return true;
@@ -1 +1 @@
1
- {"version":3,"file":"sse-writer.cjs","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { SSEChunk, StreamingProfile } from \"./types.js\";\n\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0 || signal?.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n\nexport interface StreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n /** When set, emitted as the final chunk before [DONE] (OpenAI stream_options.include_usage). */\n usageChunk?: SSEChunk;\n}\n\nexport function calculateDelay(\n chunkIndex: number,\n profile?: StreamingProfile,\n fallbackLatency?: number,\n): number {\n if (!profile) return fallbackLatency ?? 0;\n\n let delayMs: number;\n if (chunkIndex === 0 && profile.ttft !== undefined) {\n delayMs = profile.ttft;\n } else if (profile.tps !== undefined && profile.tps > 0) {\n delayMs = 1000 / profile.tps;\n } else {\n return fallbackLatency ?? 0;\n }\n\n if (profile.jitter && profile.jitter > 0) {\n delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;\n }\n\n return Math.max(0, delayMs);\n}\n\nexport async function writeSSEStream(\n res: http.ServerResponse,\n chunks: SSEChunk[],\n optionsOrLatency?: number | StreamOptions,\n): Promise<boolean> {\n const opts: StreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const chunk of chunks) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency);\n if (chunkDelay > 0) {\n await delay(chunkDelay, signal);\n }\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n if (opts.usageChunk) {\n res.write(`data: ${JSON.stringify(opts.usageChunk)}\\n\\n`);\n }\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n return true;\n}\n\n/**\n * Default rate-limit response headers matching OpenAI's format.\n * Values are static — aimock doesn't track actual request counts.\n */\nconst RATE_LIMIT_HEADERS: Record<string, string> = {\n \"x-ratelimit-limit-requests\": \"60\",\n \"x-ratelimit-limit-tokens\": \"150000\",\n \"x-ratelimit-remaining-requests\": \"0\",\n \"x-ratelimit-remaining-tokens\": \"0\",\n \"x-ratelimit-reset-requests\": \"1s\",\n \"x-ratelimit-reset-tokens\": \"6m0s\",\n};\n\nexport interface ErrorResponseOptions {\n /** Override the Retry-After header value (seconds). Default: 1. Only applied on 429. */\n retryAfter?: number;\n}\n\nexport function writeErrorResponse(\n res: http.ServerResponse,\n status: number,\n body: string,\n options?: ErrorResponseOptions,\n): void {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (status === 429) {\n headers[\"Retry-After\"] = String(options?.retryAfter ?? 1);\n Object.assign(headers, RATE_LIMIT_HEADERS);\n }\n res.writeHead(status, headers);\n res.end(body);\n}\n"],"mappings":";;AAGA,SAAgB,MAAM,IAAY,QAAqC;AACrE,KAAI,MAAM,KAAK,QAAQ,QAAS,QAAO,QAAQ,SAAS;AACxD,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,QAAQ,WAAW,SAAS,GAAG;AACrC,UAAQ,iBACN,eACM;AACJ,gBAAa,MAAM;AACnB,YAAS;KAEX,EAAE,MAAM,MAAM,CACf;GACD;;AAYJ,SAAgB,eACd,YACA,SACA,iBACQ;AACR,KAAI,CAAC,QAAS,QAAO,mBAAmB;CAExC,IAAI;AACJ,KAAI,eAAe,KAAK,QAAQ,SAAS,OACvC,WAAU,QAAQ;UACT,QAAQ,QAAQ,UAAa,QAAQ,MAAM,EACpD,WAAU,MAAO,QAAQ;KAEzB,QAAO,mBAAmB;AAG5B,KAAI,QAAQ,UAAU,QAAQ,SAAS,EACrC,YAAW,KAAK,KAAK,QAAQ,GAAG,IAAI,KAAK,QAAQ;AAGnD,QAAO,KAAK,IAAI,GAAG,QAAQ;;AAG7B,eAAsB,eACpB,KACA,QACA,kBACkB;CAClB,MAAM,OACJ,OAAO,qBAAqB,WAAW,EAAE,SAAS,kBAAkB,GAAI,oBAAoB,EAAE;CAChG,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,UAAU,KAAK;CACrB,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,KAAK;AAEzB,KAAI,IAAI,cAAe,QAAO;AAC9B,KAAI,UAAU,gBAAgB,oBAAoB;AAClD,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,cAAc,aAAa;CAEzC,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,eAAe,YAAY,SAAS,QAAQ;AAC/D,MAAI,aAAa,EACf,OAAM,MAAM,YAAY,OAAO;AAEjC,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,IAAI,cAAe,QAAO;AAC9B,MAAI,MAAM,SAAS,KAAK,UAAU,MAAM,CAAC,MAAM;AAC/C,iBAAe;AACf,MAAI,QAAQ,QAAS,QAAO;AAC5B;;AAGF,KAAI,CAAC,IAAI,eAAe;AACtB,MAAI,KAAK,WACP,KAAI,MAAM,SAAS,KAAK,UAAU,KAAK,WAAW,CAAC,MAAM;AAE3D,MAAI,MAAM,mBAAmB;AAC7B,MAAI,KAAK;;AAEX,QAAO;;;;;;AAOT,MAAM,qBAA6C;CACjD,8BAA8B;CAC9B,4BAA4B;CAC5B,kCAAkC;CAClC,gCAAgC;CAChC,8BAA8B;CAC9B,4BAA4B;CAC7B;AAOD,SAAgB,mBACd,KACA,QACA,MACA,SACM;CACN,MAAM,UAAkC,EAAE,gBAAgB,oBAAoB;AAC9E,KAAI,WAAW,KAAK;AAClB,UAAQ,iBAAiB,OAAO,SAAS,cAAc,EAAE;AACzD,SAAO,OAAO,SAAS,mBAAmB;;AAE5C,KAAI,UAAU,QAAQ,QAAQ;AAC9B,KAAI,IAAI,KAAK"}
1
+ {"version":3,"file":"sse-writer.cjs","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { SSEChunk, StreamingProfile, RecordedTimings } from \"./types.js\";\n\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0 || signal?.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n\nexport interface StreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n /** When set, emitted as the final chunk before [DONE] (OpenAI stream_options.include_usage). */\n usageChunk?: SSEChunk;\n}\n\nexport function calculateDelay(\n chunkIndex: number,\n profile?: StreamingProfile,\n fallbackLatency?: number,\n recordedTimings?: RecordedTimings,\n replaySpeed?: number,\n): number {\n const speed = replaySpeed ?? 1.0;\n let delayMs: number;\n\n if (profile) {\n // StreamingProfile has highest precedence\n let fromProfile = true;\n if (chunkIndex === 0 && profile.ttft !== undefined) {\n delayMs = profile.ttft;\n } else if (profile.tps !== undefined && profile.tps > 0) {\n delayMs = 1000 / profile.tps;\n } else {\n delayMs = fallbackLatency ?? 0;\n fromProfile = false;\n }\n // Jitter only applies when the delay came from ttft/tps, not fallback\n if (fromProfile && profile.jitter && profile.jitter > 0) {\n delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;\n if (delayMs < 0) delayMs = 0;\n }\n } else if (recordedTimings) {\n // Recorded timings (second precedence)\n if (chunkIndex === 0) {\n delayMs = recordedTimings.ttftMs;\n } else {\n const idx = chunkIndex - 1;\n if (idx < recordedTimings.interChunkDelaysMs.length) {\n delayMs = recordedTimings.interChunkDelaysMs[idx];\n } else {\n // Excess chunks: derive average from recorded inter-chunk delays\n const totalInterChunk = recordedTimings.interChunkDelaysMs.reduce((a, b) => a + b, 0);\n delayMs =\n recordedTimings.interChunkDelaysMs.length > 0\n ? totalInterChunk / recordedTimings.interChunkDelaysMs.length\n : 0;\n }\n }\n } else {\n delayMs = fallbackLatency ?? 0;\n }\n\n delayMs = Math.max(0, delayMs);\n return speed > 0 ? delayMs / speed : delayMs;\n}\n\nexport async function writeSSEStream(\n res: http.ServerResponse,\n chunks: SSEChunk[],\n optionsOrLatency?: number | StreamOptions,\n): Promise<boolean> {\n const opts: StreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const chunk of chunks) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) {\n await delay(chunkDelay, signal);\n }\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n if (opts.usageChunk) {\n res.write(`data: ${JSON.stringify(opts.usageChunk)}\\n\\n`);\n }\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n return true;\n}\n\n/**\n * Default rate-limit response headers matching OpenAI's format.\n * Values are static — aimock doesn't track actual request counts.\n */\nconst RATE_LIMIT_HEADERS: Record<string, string> = {\n \"x-ratelimit-limit-requests\": \"60\",\n \"x-ratelimit-limit-tokens\": \"150000\",\n \"x-ratelimit-remaining-requests\": \"0\",\n \"x-ratelimit-remaining-tokens\": \"0\",\n \"x-ratelimit-reset-requests\": \"1s\",\n \"x-ratelimit-reset-tokens\": \"6m0s\",\n};\n\nexport interface ErrorResponseOptions {\n /** Override the Retry-After header value (seconds). Default: 1. Only applied on 429. */\n retryAfter?: number;\n}\n\nexport function writeErrorResponse(\n res: http.ServerResponse,\n status: number,\n body: string,\n options?: ErrorResponseOptions,\n): void {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (status === 429) {\n headers[\"Retry-After\"] = String(options?.retryAfter ?? 1);\n Object.assign(headers, RATE_LIMIT_HEADERS);\n }\n res.writeHead(status, headers);\n res.end(body);\n}\n"],"mappings":";;AAGA,SAAgB,MAAM,IAAY,QAAqC;AACrE,KAAI,MAAM,KAAK,QAAQ,QAAS,QAAO,QAAQ,SAAS;AACxD,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,QAAQ,WAAW,SAAS,GAAG;AACrC,UAAQ,iBACN,eACM;AACJ,gBAAa,MAAM;AACnB,YAAS;KAEX,EAAE,MAAM,MAAM,CACf;GACD;;AAcJ,SAAgB,eACd,YACA,SACA,iBACA,iBACA,aACQ;CACR,MAAM,QAAQ,eAAe;CAC7B,IAAI;AAEJ,KAAI,SAAS;EAEX,IAAI,cAAc;AAClB,MAAI,eAAe,KAAK,QAAQ,SAAS,OACvC,WAAU,QAAQ;WACT,QAAQ,QAAQ,UAAa,QAAQ,MAAM,EACpD,WAAU,MAAO,QAAQ;OACpB;AACL,aAAU,mBAAmB;AAC7B,iBAAc;;AAGhB,MAAI,eAAe,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACvD,cAAW,KAAK,KAAK,QAAQ,GAAG,IAAI,KAAK,QAAQ;AACjD,OAAI,UAAU,EAAG,WAAU;;YAEpB,gBAET,KAAI,eAAe,EACjB,WAAU,gBAAgB;MACrB;EACL,MAAM,MAAM,aAAa;AACzB,MAAI,MAAM,gBAAgB,mBAAmB,OAC3C,WAAU,gBAAgB,mBAAmB;OACxC;GAEL,MAAM,kBAAkB,gBAAgB,mBAAmB,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE;AACrF,aACE,gBAAgB,mBAAmB,SAAS,IACxC,kBAAkB,gBAAgB,mBAAmB,SACrD;;;KAIV,WAAU,mBAAmB;AAG/B,WAAU,KAAK,IAAI,GAAG,QAAQ;AAC9B,QAAO,QAAQ,IAAI,UAAU,QAAQ;;AAGvC,eAAsB,eACpB,KACA,QACA,kBACkB;CAClB,MAAM,OACJ,OAAO,qBAAqB,WAAW,EAAE,SAAS,kBAAkB,GAAI,oBAAoB,EAAE;CAChG,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,UAAU,KAAK;CACrB,MAAM,EAAE,iBAAiB,gBAAgB;CACzC,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,KAAK;AAEzB,KAAI,IAAI,cAAe,QAAO;AAC9B,KAAI,UAAU,gBAAgB,oBAAoB;AAClD,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,cAAc,aAAa;CAEzC,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,eAAe,YAAY,SAAS,SAAS,iBAAiB,YAAY;AAC7F,MAAI,aAAa,EACf,OAAM,MAAM,YAAY,OAAO;AAEjC,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,IAAI,cAAe,QAAO;AAC9B,MAAI,MAAM,SAAS,KAAK,UAAU,MAAM,CAAC,MAAM;AAC/C,iBAAe;AACf,MAAI,QAAQ,QAAS,QAAO;AAC5B;;AAGF,KAAI,CAAC,IAAI,eAAe;AACtB,MAAI,KAAK,WACP,KAAI,MAAM,SAAS,KAAK,UAAU,KAAK,WAAW,CAAC,MAAM;AAE3D,MAAI,MAAM,mBAAmB;AAC7B,MAAI,KAAK;;AAEX,QAAO;;;;;;AAOT,MAAM,qBAA6C;CACjD,8BAA8B;CAC9B,4BAA4B;CAC5B,kCAAkC;CAClC,gCAAgC;CAChC,8BAA8B;CAC9B,4BAA4B;CAC7B;AAOD,SAAgB,mBACd,KACA,QACA,MACA,SACM;CACN,MAAM,UAAkC,EAAE,gBAAgB,oBAAoB;AAC9E,KAAI,WAAW,KAAK;AAClB,UAAQ,iBAAiB,OAAO,SAAS,cAAc,EAAE;AACzD,SAAO,OAAO,SAAS,mBAAmB;;AAE5C,KAAI,UAAU,QAAQ,QAAQ;AAC9B,KAAI,IAAI,KAAK"}
@@ -1,4 +1,4 @@
1
- import { SSEChunk, StreamingProfile } from "./types.cjs";
1
+ import { RecordedTimings, SSEChunk, StreamingProfile } from "./types.cjs";
2
2
  import * as http$1 from "node:http";
3
3
 
4
4
  //#region src/sse-writer.d.ts
@@ -6,12 +6,14 @@ declare function delay(ms: number, signal?: AbortSignal): Promise<void>;
6
6
  interface StreamOptions {
7
7
  latency?: number;
8
8
  streamingProfile?: StreamingProfile;
9
+ recordedTimings?: RecordedTimings;
10
+ replaySpeed?: number;
9
11
  signal?: AbortSignal;
10
12
  onChunkSent?: () => void;
11
13
  /** When set, emitted as the final chunk before [DONE] (OpenAI stream_options.include_usage). */
12
14
  usageChunk?: SSEChunk;
13
15
  }
14
- declare function calculateDelay(chunkIndex: number, profile?: StreamingProfile, fallbackLatency?: number): number;
16
+ declare function calculateDelay(chunkIndex: number, profile?: StreamingProfile, fallbackLatency?: number, recordedTimings?: RecordedTimings, replaySpeed?: number): number;
15
17
  declare function writeSSEStream(res: http$1.ServerResponse, chunks: SSEChunk[], optionsOrLatency?: number | StreamOptions): Promise<boolean>;
16
18
  interface ErrorResponseOptions {
17
19
  /** Override the Retry-After header value (seconds). Default: 1. Only applied on 429. */
@@ -1 +1 @@
1
- {"version":3,"file":"sse-writer.d.cts","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":[],"mappings":";;;;iBAGgB,KAAA,sBAA2B,cAAc;UAexC,aAAA;EAfD,OAAA,CAAK,EAAA,MAAA;EAAA,gBAAA,CAAA,EAiBA,gBAjBA;QAAsB,CAAA,EAkBhC,WAlBgC;aAAc,CAAA,EAAA,GAAA,GAAA,IAAA;EAAO;EAe/C,UAAA,CAAA,EAMF,QANe;;AAET,iBAOL,cAAA,CAPK,UAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAST,gBATS,EAAA,eAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AACV,iBA6BW,cAAA,CA7BX,GAAA,EA8BJ,MAAA,CAAK,cA9BD,EAAA,MAAA,EA+BD,QA/BC,EAAA,EAAA,gBAAA,CAAA,EAAA,MAAA,GAgCmB,aAhCnB,CAAA,EAiCR,OAjCQ,CAAA,OAAA,CAAA;AAGI,UAgFE,oBAAA,CAhFF;EAAQ;EAGP,UAAA,CAAA,EAAA,MAAc;AAuB9B;AAAoC,iBA2DpB,kBAAA,CA3DoB,GAAA,EA4D7B,MAAA,CAAK,cA5DwB,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EA+DxB,oBA/DwB,CAAA,EAAA,IAAA"}
1
+ {"version":3,"file":"sse-writer.d.cts","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":[],"mappings":";;;;iBAGgB,KAAA,sBAA2B,cAAc;UAexC,aAAA;EAfD,OAAA,CAAK,EAAA,MAAA;EAAA,gBAAA,CAAA,EAiBA,gBAjBA;iBAAsB,CAAA,EAkBvB,eAlBuB;aAAc,CAAA,EAAA,MAAA;EAAO,MAAA,CAAA,EAoBrD,WApBqD;EAe/C,WAAA,CAAA,EAAA,GAAa,GAAA,IAAA;EAAA;YAET,CAAA,EAMN,QANM;;AAGV,iBAMK,cAAA,CANL,UAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAQC,gBARD,EAAA,eAAA,CAAA,EAAA,MAAA,EAAA,eAAA,CAAA,EAUS,eAVT,EAAA,WAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAGI,iBAsDO,cAAA,CAtDP,GAAA,EAuDR,MAAA,CAAK,cAvDG,EAAA,MAAA,EAwDL,QAxDK,EAAA,EAAA,gBAAA,CAAA,EAAA,MAAA,GAyDe,aAzDf,CAAA,EA0DZ,OA1DY,CAAA,OAAA,CAAA;AAAQ,UA6GN,oBAAA,CA7GM;EAGP;EAAc,UAAA,CAAA,EAAA,MAAA;;AAIV,iBA2GJ,kBAAA,CA3GI,GAAA,EA4Gb,MAAA,CAAK,cA5GQ,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EA+GR,oBA/GQ,CAAA,EAAA,IAAA"}
@@ -1,4 +1,4 @@
1
- import { SSEChunk, StreamingProfile } from "./types.js";
1
+ import { RecordedTimings, SSEChunk, StreamingProfile } from "./types.js";
2
2
  import * as http$1 from "node:http";
3
3
 
4
4
  //#region src/sse-writer.d.ts
@@ -6,12 +6,14 @@ declare function delay(ms: number, signal?: AbortSignal): Promise<void>;
6
6
  interface StreamOptions {
7
7
  latency?: number;
8
8
  streamingProfile?: StreamingProfile;
9
+ recordedTimings?: RecordedTimings;
10
+ replaySpeed?: number;
9
11
  signal?: AbortSignal;
10
12
  onChunkSent?: () => void;
11
13
  /** When set, emitted as the final chunk before [DONE] (OpenAI stream_options.include_usage). */
12
14
  usageChunk?: SSEChunk;
13
15
  }
14
- declare function calculateDelay(chunkIndex: number, profile?: StreamingProfile, fallbackLatency?: number): number;
16
+ declare function calculateDelay(chunkIndex: number, profile?: StreamingProfile, fallbackLatency?: number, recordedTimings?: RecordedTimings, replaySpeed?: number): number;
15
17
  declare function writeSSEStream(res: http$1.ServerResponse, chunks: SSEChunk[], optionsOrLatency?: number | StreamOptions): Promise<boolean>;
16
18
  interface ErrorResponseOptions {
17
19
  /** Override the Retry-After header value (seconds). Default: 1. Only applied on 429. */
@@ -1 +1 @@
1
- {"version":3,"file":"sse-writer.d.ts","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":[],"mappings":";;;;iBAGgB,KAAA,sBAA2B,cAAc;UAexC,aAAA;EAfD,OAAA,CAAK,EAAA,MAAA;EAAA,gBAAA,CAAA,EAiBA,gBAjBA;QAAsB,CAAA,EAkBhC,WAlBgC;aAAc,CAAA,EAAA,GAAA,GAAA,IAAA;EAAO;EAe/C,UAAA,CAAA,EAMF,QANe;;AAET,iBAOL,cAAA,CAPK,UAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAST,gBATS,EAAA,eAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AACV,iBA6BW,cAAA,CA7BX,GAAA,EA8BJ,MAAA,CAAK,cA9BD,EAAA,MAAA,EA+BD,QA/BC,EAAA,EAAA,gBAAA,CAAA,EAAA,MAAA,GAgCmB,aAhCnB,CAAA,EAiCR,OAjCQ,CAAA,OAAA,CAAA;AAGI,UAgFE,oBAAA,CAhFF;EAAQ;EAGP,UAAA,CAAA,EAAA,MAAc;AAuB9B;AAAoC,iBA2DpB,kBAAA,CA3DoB,GAAA,EA4D7B,MAAA,CAAK,cA5DwB,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EA+DxB,oBA/DwB,CAAA,EAAA,IAAA"}
1
+ {"version":3,"file":"sse-writer.d.ts","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":[],"mappings":";;;;iBAGgB,KAAA,sBAA2B,cAAc;UAexC,aAAA;EAfD,OAAA,CAAK,EAAA,MAAA;EAAA,gBAAA,CAAA,EAiBA,gBAjBA;iBAAsB,CAAA,EAkBvB,eAlBuB;aAAc,CAAA,EAAA,MAAA;EAAO,MAAA,CAAA,EAoBrD,WApBqD;EAe/C,WAAA,CAAA,EAAA,GAAa,GAAA,IAAA;EAAA;YAET,CAAA,EAMN,QANM;;AAGV,iBAMK,cAAA,CANL,UAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAQC,gBARD,EAAA,eAAA,CAAA,EAAA,MAAA,EAAA,eAAA,CAAA,EAUS,eAVT,EAAA,WAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAGI,iBAsDO,cAAA,CAtDP,GAAA,EAuDR,MAAA,CAAK,cAvDG,EAAA,MAAA,EAwDL,QAxDK,EAAA,EAAA,gBAAA,CAAA,EAAA,MAAA,GAyDe,aAzDf,CAAA,EA0DZ,OA1DY,CAAA,OAAA,CAAA;AAAQ,UA6GN,oBAAA,CA7GM;EAGP;EAAc,UAAA,CAAA,EAAA,MAAA;;AAIV,iBA2GJ,kBAAA,CA3GI,GAAA,EA4Gb,MAAA,CAAK,cA5GQ,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EA+GR,oBA/GQ,CAAA,EAAA,IAAA"}
@@ -9,19 +9,39 @@ function delay(ms, signal) {
9
9
  }, { once: true });
10
10
  });
11
11
  }
12
- function calculateDelay(chunkIndex, profile, fallbackLatency) {
13
- if (!profile) return fallbackLatency ?? 0;
12
+ function calculateDelay(chunkIndex, profile, fallbackLatency, recordedTimings, replaySpeed) {
13
+ const speed = replaySpeed ?? 1;
14
14
  let delayMs;
15
- if (chunkIndex === 0 && profile.ttft !== void 0) delayMs = profile.ttft;
16
- else if (profile.tps !== void 0 && profile.tps > 0) delayMs = 1e3 / profile.tps;
17
- else return fallbackLatency ?? 0;
18
- if (profile.jitter && profile.jitter > 0) delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;
19
- return Math.max(0, delayMs);
15
+ if (profile) {
16
+ let fromProfile = true;
17
+ if (chunkIndex === 0 && profile.ttft !== void 0) delayMs = profile.ttft;
18
+ else if (profile.tps !== void 0 && profile.tps > 0) delayMs = 1e3 / profile.tps;
19
+ else {
20
+ delayMs = fallbackLatency ?? 0;
21
+ fromProfile = false;
22
+ }
23
+ if (fromProfile && profile.jitter && profile.jitter > 0) {
24
+ delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;
25
+ if (delayMs < 0) delayMs = 0;
26
+ }
27
+ } else if (recordedTimings) if (chunkIndex === 0) delayMs = recordedTimings.ttftMs;
28
+ else {
29
+ const idx = chunkIndex - 1;
30
+ if (idx < recordedTimings.interChunkDelaysMs.length) delayMs = recordedTimings.interChunkDelaysMs[idx];
31
+ else {
32
+ const totalInterChunk = recordedTimings.interChunkDelaysMs.reduce((a, b) => a + b, 0);
33
+ delayMs = recordedTimings.interChunkDelaysMs.length > 0 ? totalInterChunk / recordedTimings.interChunkDelaysMs.length : 0;
34
+ }
35
+ }
36
+ else delayMs = fallbackLatency ?? 0;
37
+ delayMs = Math.max(0, delayMs);
38
+ return speed > 0 ? delayMs / speed : delayMs;
20
39
  }
21
40
  async function writeSSEStream(res, chunks, optionsOrLatency) {
22
41
  const opts = typeof optionsOrLatency === "number" ? { latency: optionsOrLatency } : optionsOrLatency ?? {};
23
42
  const latency = opts.latency ?? 0;
24
43
  const profile = opts.streamingProfile;
44
+ const { recordedTimings, replaySpeed } = opts;
25
45
  const signal = opts.signal;
26
46
  const onChunkSent = opts.onChunkSent;
27
47
  if (res.writableEnded) return true;
@@ -30,7 +50,7 @@ async function writeSSEStream(res, chunks, optionsOrLatency) {
30
50
  res.setHeader("Connection", "keep-alive");
31
51
  let chunkIndex = 0;
32
52
  for (const chunk of chunks) {
33
- const chunkDelay = calculateDelay(chunkIndex, profile, latency);
53
+ const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);
34
54
  if (chunkDelay > 0) await delay(chunkDelay, signal);
35
55
  if (signal?.aborted) return false;
36
56
  if (res.writableEnded) return true;
@@ -1 +1 @@
1
- {"version":3,"file":"sse-writer.js","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { SSEChunk, StreamingProfile } from \"./types.js\";\n\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0 || signal?.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n\nexport interface StreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n /** When set, emitted as the final chunk before [DONE] (OpenAI stream_options.include_usage). */\n usageChunk?: SSEChunk;\n}\n\nexport function calculateDelay(\n chunkIndex: number,\n profile?: StreamingProfile,\n fallbackLatency?: number,\n): number {\n if (!profile) return fallbackLatency ?? 0;\n\n let delayMs: number;\n if (chunkIndex === 0 && profile.ttft !== undefined) {\n delayMs = profile.ttft;\n } else if (profile.tps !== undefined && profile.tps > 0) {\n delayMs = 1000 / profile.tps;\n } else {\n return fallbackLatency ?? 0;\n }\n\n if (profile.jitter && profile.jitter > 0) {\n delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;\n }\n\n return Math.max(0, delayMs);\n}\n\nexport async function writeSSEStream(\n res: http.ServerResponse,\n chunks: SSEChunk[],\n optionsOrLatency?: number | StreamOptions,\n): Promise<boolean> {\n const opts: StreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const chunk of chunks) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency);\n if (chunkDelay > 0) {\n await delay(chunkDelay, signal);\n }\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n if (opts.usageChunk) {\n res.write(`data: ${JSON.stringify(opts.usageChunk)}\\n\\n`);\n }\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n return true;\n}\n\n/**\n * Default rate-limit response headers matching OpenAI's format.\n * Values are static — aimock doesn't track actual request counts.\n */\nconst RATE_LIMIT_HEADERS: Record<string, string> = {\n \"x-ratelimit-limit-requests\": \"60\",\n \"x-ratelimit-limit-tokens\": \"150000\",\n \"x-ratelimit-remaining-requests\": \"0\",\n \"x-ratelimit-remaining-tokens\": \"0\",\n \"x-ratelimit-reset-requests\": \"1s\",\n \"x-ratelimit-reset-tokens\": \"6m0s\",\n};\n\nexport interface ErrorResponseOptions {\n /** Override the Retry-After header value (seconds). Default: 1. Only applied on 429. */\n retryAfter?: number;\n}\n\nexport function writeErrorResponse(\n res: http.ServerResponse,\n status: number,\n body: string,\n options?: ErrorResponseOptions,\n): void {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (status === 429) {\n headers[\"Retry-After\"] = String(options?.retryAfter ?? 1);\n Object.assign(headers, RATE_LIMIT_HEADERS);\n }\n res.writeHead(status, headers);\n res.end(body);\n}\n"],"mappings":";AAGA,SAAgB,MAAM,IAAY,QAAqC;AACrE,KAAI,MAAM,KAAK,QAAQ,QAAS,QAAO,QAAQ,SAAS;AACxD,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,QAAQ,WAAW,SAAS,GAAG;AACrC,UAAQ,iBACN,eACM;AACJ,gBAAa,MAAM;AACnB,YAAS;KAEX,EAAE,MAAM,MAAM,CACf;GACD;;AAYJ,SAAgB,eACd,YACA,SACA,iBACQ;AACR,KAAI,CAAC,QAAS,QAAO,mBAAmB;CAExC,IAAI;AACJ,KAAI,eAAe,KAAK,QAAQ,SAAS,OACvC,WAAU,QAAQ;UACT,QAAQ,QAAQ,UAAa,QAAQ,MAAM,EACpD,WAAU,MAAO,QAAQ;KAEzB,QAAO,mBAAmB;AAG5B,KAAI,QAAQ,UAAU,QAAQ,SAAS,EACrC,YAAW,KAAK,KAAK,QAAQ,GAAG,IAAI,KAAK,QAAQ;AAGnD,QAAO,KAAK,IAAI,GAAG,QAAQ;;AAG7B,eAAsB,eACpB,KACA,QACA,kBACkB;CAClB,MAAM,OACJ,OAAO,qBAAqB,WAAW,EAAE,SAAS,kBAAkB,GAAI,oBAAoB,EAAE;CAChG,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,UAAU,KAAK;CACrB,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,KAAK;AAEzB,KAAI,IAAI,cAAe,QAAO;AAC9B,KAAI,UAAU,gBAAgB,oBAAoB;AAClD,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,cAAc,aAAa;CAEzC,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,eAAe,YAAY,SAAS,QAAQ;AAC/D,MAAI,aAAa,EACf,OAAM,MAAM,YAAY,OAAO;AAEjC,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,IAAI,cAAe,QAAO;AAC9B,MAAI,MAAM,SAAS,KAAK,UAAU,MAAM,CAAC,MAAM;AAC/C,iBAAe;AACf,MAAI,QAAQ,QAAS,QAAO;AAC5B;;AAGF,KAAI,CAAC,IAAI,eAAe;AACtB,MAAI,KAAK,WACP,KAAI,MAAM,SAAS,KAAK,UAAU,KAAK,WAAW,CAAC,MAAM;AAE3D,MAAI,MAAM,mBAAmB;AAC7B,MAAI,KAAK;;AAEX,QAAO;;;;;;AAOT,MAAM,qBAA6C;CACjD,8BAA8B;CAC9B,4BAA4B;CAC5B,kCAAkC;CAClC,gCAAgC;CAChC,8BAA8B;CAC9B,4BAA4B;CAC7B;AAOD,SAAgB,mBACd,KACA,QACA,MACA,SACM;CACN,MAAM,UAAkC,EAAE,gBAAgB,oBAAoB;AAC9E,KAAI,WAAW,KAAK;AAClB,UAAQ,iBAAiB,OAAO,SAAS,cAAc,EAAE;AACzD,SAAO,OAAO,SAAS,mBAAmB;;AAE5C,KAAI,UAAU,QAAQ,QAAQ;AAC9B,KAAI,IAAI,KAAK"}
1
+ {"version":3,"file":"sse-writer.js","names":[],"sources":["../src/sse-writer.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { SSEChunk, StreamingProfile, RecordedTimings } from \"./types.js\";\n\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0 || signal?.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n\nexport interface StreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n /** When set, emitted as the final chunk before [DONE] (OpenAI stream_options.include_usage). */\n usageChunk?: SSEChunk;\n}\n\nexport function calculateDelay(\n chunkIndex: number,\n profile?: StreamingProfile,\n fallbackLatency?: number,\n recordedTimings?: RecordedTimings,\n replaySpeed?: number,\n): number {\n const speed = replaySpeed ?? 1.0;\n let delayMs: number;\n\n if (profile) {\n // StreamingProfile has highest precedence\n let fromProfile = true;\n if (chunkIndex === 0 && profile.ttft !== undefined) {\n delayMs = profile.ttft;\n } else if (profile.tps !== undefined && profile.tps > 0) {\n delayMs = 1000 / profile.tps;\n } else {\n delayMs = fallbackLatency ?? 0;\n fromProfile = false;\n }\n // Jitter only applies when the delay came from ttft/tps, not fallback\n if (fromProfile && profile.jitter && profile.jitter > 0) {\n delayMs *= 1 + (Math.random() * 2 - 1) * profile.jitter;\n if (delayMs < 0) delayMs = 0;\n }\n } else if (recordedTimings) {\n // Recorded timings (second precedence)\n if (chunkIndex === 0) {\n delayMs = recordedTimings.ttftMs;\n } else {\n const idx = chunkIndex - 1;\n if (idx < recordedTimings.interChunkDelaysMs.length) {\n delayMs = recordedTimings.interChunkDelaysMs[idx];\n } else {\n // Excess chunks: derive average from recorded inter-chunk delays\n const totalInterChunk = recordedTimings.interChunkDelaysMs.reduce((a, b) => a + b, 0);\n delayMs =\n recordedTimings.interChunkDelaysMs.length > 0\n ? totalInterChunk / recordedTimings.interChunkDelaysMs.length\n : 0;\n }\n }\n } else {\n delayMs = fallbackLatency ?? 0;\n }\n\n delayMs = Math.max(0, delayMs);\n return speed > 0 ? delayMs / speed : delayMs;\n}\n\nexport async function writeSSEStream(\n res: http.ServerResponse,\n chunks: SSEChunk[],\n optionsOrLatency?: number | StreamOptions,\n): Promise<boolean> {\n const opts: StreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const chunk of chunks) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) {\n await delay(chunkDelay, signal);\n }\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n if (opts.usageChunk) {\n res.write(`data: ${JSON.stringify(opts.usageChunk)}\\n\\n`);\n }\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n return true;\n}\n\n/**\n * Default rate-limit response headers matching OpenAI's format.\n * Values are static — aimock doesn't track actual request counts.\n */\nconst RATE_LIMIT_HEADERS: Record<string, string> = {\n \"x-ratelimit-limit-requests\": \"60\",\n \"x-ratelimit-limit-tokens\": \"150000\",\n \"x-ratelimit-remaining-requests\": \"0\",\n \"x-ratelimit-remaining-tokens\": \"0\",\n \"x-ratelimit-reset-requests\": \"1s\",\n \"x-ratelimit-reset-tokens\": \"6m0s\",\n};\n\nexport interface ErrorResponseOptions {\n /** Override the Retry-After header value (seconds). Default: 1. Only applied on 429. */\n retryAfter?: number;\n}\n\nexport function writeErrorResponse(\n res: http.ServerResponse,\n status: number,\n body: string,\n options?: ErrorResponseOptions,\n): void {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (status === 429) {\n headers[\"Retry-After\"] = String(options?.retryAfter ?? 1);\n Object.assign(headers, RATE_LIMIT_HEADERS);\n }\n res.writeHead(status, headers);\n res.end(body);\n}\n"],"mappings":";AAGA,SAAgB,MAAM,IAAY,QAAqC;AACrE,KAAI,MAAM,KAAK,QAAQ,QAAS,QAAO,QAAQ,SAAS;AACxD,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,QAAQ,WAAW,SAAS,GAAG;AACrC,UAAQ,iBACN,eACM;AACJ,gBAAa,MAAM;AACnB,YAAS;KAEX,EAAE,MAAM,MAAM,CACf;GACD;;AAcJ,SAAgB,eACd,YACA,SACA,iBACA,iBACA,aACQ;CACR,MAAM,QAAQ,eAAe;CAC7B,IAAI;AAEJ,KAAI,SAAS;EAEX,IAAI,cAAc;AAClB,MAAI,eAAe,KAAK,QAAQ,SAAS,OACvC,WAAU,QAAQ;WACT,QAAQ,QAAQ,UAAa,QAAQ,MAAM,EACpD,WAAU,MAAO,QAAQ;OACpB;AACL,aAAU,mBAAmB;AAC7B,iBAAc;;AAGhB,MAAI,eAAe,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACvD,cAAW,KAAK,KAAK,QAAQ,GAAG,IAAI,KAAK,QAAQ;AACjD,OAAI,UAAU,EAAG,WAAU;;YAEpB,gBAET,KAAI,eAAe,EACjB,WAAU,gBAAgB;MACrB;EACL,MAAM,MAAM,aAAa;AACzB,MAAI,MAAM,gBAAgB,mBAAmB,OAC3C,WAAU,gBAAgB,mBAAmB;OACxC;GAEL,MAAM,kBAAkB,gBAAgB,mBAAmB,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE;AACrF,aACE,gBAAgB,mBAAmB,SAAS,IACxC,kBAAkB,gBAAgB,mBAAmB,SACrD;;;KAIV,WAAU,mBAAmB;AAG/B,WAAU,KAAK,IAAI,GAAG,QAAQ;AAC9B,QAAO,QAAQ,IAAI,UAAU,QAAQ;;AAGvC,eAAsB,eACpB,KACA,QACA,kBACkB;CAClB,MAAM,OACJ,OAAO,qBAAqB,WAAW,EAAE,SAAS,kBAAkB,GAAI,oBAAoB,EAAE;CAChG,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,UAAU,KAAK;CACrB,MAAM,EAAE,iBAAiB,gBAAgB;CACzC,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,KAAK;AAEzB,KAAI,IAAI,cAAe,QAAO;AAC9B,KAAI,UAAU,gBAAgB,oBAAoB;AAClD,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,cAAc,aAAa;CAEzC,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,eAAe,YAAY,SAAS,SAAS,iBAAiB,YAAY;AAC7F,MAAI,aAAa,EACf,OAAM,MAAM,YAAY,OAAO;AAEjC,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,IAAI,cAAe,QAAO;AAC9B,MAAI,MAAM,SAAS,KAAK,UAAU,MAAM,CAAC,MAAM;AAC/C,iBAAe;AACf,MAAI,QAAQ,QAAS,QAAO;AAC5B;;AAGF,KAAI,CAAC,IAAI,eAAe;AACtB,MAAI,KAAK,WACP,KAAI,MAAM,SAAS,KAAK,UAAU,KAAK,WAAW,CAAC,MAAM;AAE3D,MAAI,MAAM,mBAAmB;AAC7B,MAAI,KAAK;;AAEX,QAAO;;;;;;AAOT,MAAM,qBAA6C;CACjD,8BAA8B;CAC9B,4BAA4B;CAC5B,kCAAkC;CAClC,gCAAgC;CAChC,8BAA8B;CAC9B,4BAA4B;CAC7B;AAOD,SAAgB,mBACd,KACA,QACA,MACA,SACM;CACN,MAAM,UAAkC,EAAE,gBAAgB,oBAAoB;AAC9E,KAAI,WAAW,KAAK;AAClB,UAAQ,iBAAiB,OAAO,SAAS,cAAc,EAAE;AACzD,SAAO,OAAO,SAAS,mBAAmB;;AAE5C,KAAI,UAAU,QAAQ,QAAQ;AAC9B,KAAI,IAAI,KAAK"}
package/dist/types.d.cts CHANGED
@@ -218,6 +218,16 @@ interface StreamingProfile {
218
218
  tps?: number;
219
219
  jitter?: number;
220
220
  }
221
+ /**
222
+ * Per-frame arrival timestamps captured during proxy recording.
223
+ * Used during replay to reproduce real-world streaming timing instead of
224
+ * the synthetic model (StreamingProfile / flat latency).
225
+ */
226
+ interface RecordedTimings {
227
+ ttftMs: number;
228
+ interChunkDelaysMs: number[];
229
+ totalDurationMs: number;
230
+ }
221
231
  /**
222
232
  * Probabilistic chaos injection rates.
223
233
  *
@@ -242,6 +252,8 @@ interface Fixture {
242
252
  truncateAfterChunks?: number;
243
253
  disconnectAfterMs?: number;
244
254
  streamingProfile?: StreamingProfile;
255
+ recordedTimings?: RecordedTimings;
256
+ replaySpeed?: number;
245
257
  chaos?: ChaosConfig;
246
258
  metadata?: {
247
259
  systemHash?: string;
@@ -302,6 +314,8 @@ interface FixtureFileEntry {
302
314
  truncateAfterChunks?: number;
303
315
  disconnectAfterMs?: number;
304
316
  streamingProfile?: StreamingProfile;
317
+ recordedTimings?: RecordedTimings;
318
+ replaySpeed?: number;
305
319
  chaos?: ChaosConfig;
306
320
  metadata?: {
307
321
  systemHash?: string;
@@ -439,6 +453,7 @@ interface MockServerOptions {
439
453
  host?: string;
440
454
  latency?: number;
441
455
  chunkSize?: number;
456
+ replaySpeed?: number;
442
457
  /** Log verbosity. CLI default is "info"; programmatic default (when omitted) is "silent". */
443
458
  logLevel?: "silent" | "warn" | "info" | "debug";
444
459
  chaos?: ChaosConfig;
@@ -513,6 +528,7 @@ interface FalQueueConfig {
513
528
  interface HandlerDefaults {
514
529
  latency: number;
515
530
  chunkSize: number;
531
+ replaySpeed: number;
516
532
  logger: Logger;
517
533
  chaos?: ChaosConfig;
518
534
  registry?: MetricsRegistry;
@@ -523,5 +539,5 @@ interface HandlerDefaults {
523
539
  }
524
540
  //# sourceMappingURL=types.d.ts.map
525
541
  //#endregion
526
- export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
542
+ export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, 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 };
527
543
  //# 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
@@ -218,6 +218,16 @@ interface StreamingProfile {
218
218
  tps?: number;
219
219
  jitter?: number;
220
220
  }
221
+ /**
222
+ * Per-frame arrival timestamps captured during proxy recording.
223
+ * Used during replay to reproduce real-world streaming timing instead of
224
+ * the synthetic model (StreamingProfile / flat latency).
225
+ */
226
+ interface RecordedTimings {
227
+ ttftMs: number;
228
+ interChunkDelaysMs: number[];
229
+ totalDurationMs: number;
230
+ }
221
231
  /**
222
232
  * Probabilistic chaos injection rates.
223
233
  *
@@ -242,6 +252,8 @@ interface Fixture {
242
252
  truncateAfterChunks?: number;
243
253
  disconnectAfterMs?: number;
244
254
  streamingProfile?: StreamingProfile;
255
+ recordedTimings?: RecordedTimings;
256
+ replaySpeed?: number;
245
257
  chaos?: ChaosConfig;
246
258
  metadata?: {
247
259
  systemHash?: string;
@@ -302,6 +314,8 @@ interface FixtureFileEntry {
302
314
  truncateAfterChunks?: number;
303
315
  disconnectAfterMs?: number;
304
316
  streamingProfile?: StreamingProfile;
317
+ recordedTimings?: RecordedTimings;
318
+ replaySpeed?: number;
305
319
  chaos?: ChaosConfig;
306
320
  metadata?: {
307
321
  systemHash?: string;
@@ -439,6 +453,7 @@ interface MockServerOptions {
439
453
  host?: string;
440
454
  latency?: number;
441
455
  chunkSize?: number;
456
+ replaySpeed?: number;
442
457
  /** Log verbosity. CLI default is "info"; programmatic default (when omitted) is "silent". */
443
458
  logLevel?: "silent" | "warn" | "info" | "debug";
444
459
  chaos?: ChaosConfig;
@@ -513,6 +528,7 @@ interface FalQueueConfig {
513
528
  interface HandlerDefaults {
514
529
  latency: number;
515
530
  chunkSize: number;
531
+ replaySpeed: number;
516
532
  logger: Logger;
517
533
  chaos?: ChaosConfig;
518
534
  registry?: MetricsRegistry;
@@ -523,5 +539,5 @@ interface HandlerDefaults {
523
539
  }
524
540
  //# sourceMappingURL=types.d.ts.map
525
541
  //#endregion
526
- export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
542
+ export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, 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 };
527
543
  //# 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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"vector-types.d.cts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMV,CAAM;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
1
+ {"version":3,"file":"vector-types.d.cts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMJ,CAAA;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
@@ -1 +1 @@
1
- {"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMJ,CAAA;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
1
+ {"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMV,CAAM;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
@@ -307,12 +307,15 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
307
307
  const chunkList = [];
308
308
  for (let i = 0; i < content.length; i += chunkSize) chunkList.push(content.slice(i, i + chunkSize));
309
309
  const interruption = require_interruption.createInterruptionSignal(fixture);
310
+ const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
311
+ const { recordedTimings } = fixture;
310
312
  let interrupted = false;
311
313
  if (content.length === 0) {
312
314
  if (!ws.isClosed) ws.send(JSON.stringify({ serverContent: { modelTurn: { parts: [{ text: "" }] } } }));
313
315
  } else for (let i = 0; i < chunkList.length; i++) {
314
316
  if (ws.isClosed) break;
315
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
317
+ const chunkDelay = require_sse_writer.calculateDelay(i, void 0, latency, recordedTimings, replaySpeed);
318
+ if (chunkDelay > 0) await require_sse_writer.delay(chunkDelay, interruption?.signal);
316
319
  if (interruption?.signal.aborted) {
317
320
  interrupted = true;
318
321
  break;
@@ -337,7 +340,8 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
337
340
  resolvedId: tc.id ?? require_helpers.generateToolCallId()
338
341
  }));
339
342
  if (!ws.isClosed) {
340
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
343
+ const tcDelay = require_sse_writer.calculateDelay(chunkList.length, void 0, latency, recordedTimings, replaySpeed);
344
+ if (tcDelay > 0) await require_sse_writer.delay(tcDelay, interruption?.signal);
341
345
  if (interruption?.signal.aborted) {
342
346
  ws.destroy();
343
347
  journalEntry.response.interrupted = true;
@@ -406,10 +410,13 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
406
410
  const chunks = [];
407
411
  for (let i = 0; i < content.length; i += chunkSize) chunks.push(content.slice(i, i + chunkSize));
408
412
  const interruption = require_interruption.createInterruptionSignal(fixture);
413
+ const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
414
+ const { recordedTimings } = fixture;
409
415
  let interrupted = false;
410
416
  for (let i = 0; i < chunks.length; i++) {
411
417
  if (ws.isClosed) break;
412
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
418
+ const chunkDelay = require_sse_writer.calculateDelay(i, void 0, latency, recordedTimings, replaySpeed);
419
+ if (chunkDelay > 0) await require_sse_writer.delay(chunkDelay, interruption?.signal);
413
420
  if (interruption?.signal.aborted) {
414
421
  interrupted = true;
415
422
  break;
@@ -449,11 +456,14 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
449
456
  }
450
457
  });
451
458
  const interruption = require_interruption.createInterruptionSignal(fixture);
459
+ const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
460
+ const { recordedTimings } = fixture;
452
461
  if (ws.isClosed) {
453
462
  interruption?.cleanup();
454
463
  return;
455
464
  }
456
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
465
+ const tcDelay = require_sse_writer.calculateDelay(0, void 0, latency, recordedTimings, replaySpeed);
466
+ if (tcDelay > 0) await require_sse_writer.delay(tcDelay, interruption?.signal);
457
467
  if (interruption?.signal.aborted) {
458
468
  ws.destroy();
459
469
  journalEntry.response.interrupted = true;