@copilotkit/aimock 1.44.0 → 1.45.1

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 (278) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +42 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.cts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +312 -39
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +313 -40
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +1 -0
  25. package/dist/chaos.js +1 -1
  26. package/dist/cli.cjs +152 -5
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +155 -8
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +132 -71
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +133 -72
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.cjs +62 -4
  37. package/dist/config-loader.cjs.map +1 -1
  38. package/dist/config-loader.d.cts +37 -4
  39. package/dist/config-loader.d.cts.map +1 -1
  40. package/dist/config-loader.d.ts +37 -4
  41. package/dist/config-loader.d.ts.map +1 -1
  42. package/dist/config-loader.js +62 -4
  43. package/dist/config-loader.js.map +1 -1
  44. package/dist/fakes-plugin.cjs +131 -0
  45. package/dist/fakes-plugin.cjs.map +1 -0
  46. package/dist/fakes-plugin.d.cts +23 -0
  47. package/dist/fakes-plugin.d.cts.map +1 -0
  48. package/dist/fakes-plugin.d.ts +23 -0
  49. package/dist/fakes-plugin.d.ts.map +1 -0
  50. package/dist/fakes-plugin.js +127 -0
  51. package/dist/fakes-plugin.js.map +1 -0
  52. package/dist/fixture-loader-services.cjs +1 -1
  53. package/dist/fixture-loader-services.cjs.map +1 -1
  54. package/dist/fixture-loader-services.js +1 -1
  55. package/dist/fixture-loader-services.js.map +1 -1
  56. package/dist/fixture-loader.cjs +389 -27
  57. package/dist/fixture-loader.cjs.map +1 -1
  58. package/dist/fixture-loader.d.cts +47 -3
  59. package/dist/fixture-loader.d.cts.map +1 -1
  60. package/dist/fixture-loader.d.ts +47 -3
  61. package/dist/fixture-loader.d.ts.map +1 -1
  62. package/dist/fixture-loader.js +384 -29
  63. package/dist/fixture-loader.js.map +1 -1
  64. package/dist/gemini-interactions.cjs +250 -52
  65. package/dist/gemini-interactions.cjs.map +1 -1
  66. package/dist/gemini-interactions.d.cts.map +1 -1
  67. package/dist/gemini-interactions.d.ts.map +1 -1
  68. package/dist/gemini-interactions.js +251 -53
  69. package/dist/gemini-interactions.js.map +1 -1
  70. package/dist/gemini.cjs +226 -37
  71. package/dist/gemini.cjs.map +1 -1
  72. package/dist/gemini.d.cts.map +1 -1
  73. package/dist/gemini.d.ts.map +1 -1
  74. package/dist/gemini.js +227 -38
  75. package/dist/gemini.js.map +1 -1
  76. package/dist/helpers.cjs +881 -7
  77. package/dist/helpers.cjs.map +1 -1
  78. package/dist/helpers.d.cts +85 -4
  79. package/dist/helpers.d.cts.map +1 -1
  80. package/dist/helpers.d.ts +85 -4
  81. package/dist/helpers.d.ts.map +1 -1
  82. package/dist/helpers.js +839 -8
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/index.cjs +9 -0
  85. package/dist/index.d.cts +7 -5
  86. package/dist/index.d.ts +7 -5
  87. package/dist/index.js +4 -3
  88. package/dist/jest.cjs +31 -7
  89. package/dist/jest.cjs.map +1 -1
  90. package/dist/jest.d.cts +43 -3
  91. package/dist/jest.d.cts.map +1 -1
  92. package/dist/jest.d.ts +43 -3
  93. package/dist/jest.d.ts.map +1 -1
  94. package/dist/jest.js +33 -9
  95. package/dist/jest.js.map +1 -1
  96. package/dist/journal.cjs +135 -13
  97. package/dist/journal.cjs.map +1 -1
  98. package/dist/journal.d.cts +38 -4
  99. package/dist/journal.d.cts.map +1 -1
  100. package/dist/journal.d.ts +38 -4
  101. package/dist/journal.d.ts.map +1 -1
  102. package/dist/journal.js +135 -13
  103. package/dist/journal.js.map +1 -1
  104. package/dist/live-sanitize.cjs +4 -32
  105. package/dist/live-sanitize.cjs.map +1 -1
  106. package/dist/live-sanitize.js +4 -32
  107. package/dist/live-sanitize.js.map +1 -1
  108. package/dist/llmock.cjs +123 -30
  109. package/dist/llmock.cjs.map +1 -1
  110. package/dist/llmock.d.cts +16 -1
  111. package/dist/llmock.d.cts.map +1 -1
  112. package/dist/llmock.d.ts +16 -1
  113. package/dist/llmock.d.ts.map +1 -1
  114. package/dist/llmock.js +125 -32
  115. package/dist/llmock.js.map +1 -1
  116. package/dist/mcp-fakes-mount.cjs +1 -0
  117. package/dist/mcp-fakes-mount.cjs.map +1 -1
  118. package/dist/mcp-fakes-mount.js +1 -0
  119. package/dist/mcp-fakes-mount.js.map +1 -1
  120. package/dist/mcp-fakes-report.cjs +111 -0
  121. package/dist/mcp-fakes-report.cjs.map +1 -0
  122. package/dist/mcp-fakes-report.d.cts +40 -0
  123. package/dist/mcp-fakes-report.d.cts.map +1 -0
  124. package/dist/mcp-fakes-report.d.ts +40 -0
  125. package/dist/mcp-fakes-report.d.ts.map +1 -0
  126. package/dist/mcp-fakes-report.js +107 -0
  127. package/dist/mcp-fakes-report.js.map +1 -0
  128. package/dist/mcp-fakes.cjs +331 -8
  129. package/dist/mcp-fakes.cjs.map +1 -1
  130. package/dist/mcp-fakes.d.cts +406 -3
  131. package/dist/mcp-fakes.d.cts.map +1 -1
  132. package/dist/mcp-fakes.d.ts +406 -3
  133. package/dist/mcp-fakes.d.ts.map +1 -1
  134. package/dist/mcp-fakes.js +331 -8
  135. package/dist/mcp-fakes.js.map +1 -1
  136. package/dist/mcp-handler.cjs +216 -17
  137. package/dist/mcp-handler.cjs.map +1 -1
  138. package/dist/mcp-handler.d.cts +49 -0
  139. package/dist/mcp-handler.d.cts.map +1 -0
  140. package/dist/mcp-handler.d.ts +49 -0
  141. package/dist/mcp-handler.d.ts.map +1 -0
  142. package/dist/mcp-handler.js +214 -18
  143. package/dist/mcp-handler.js.map +1 -1
  144. package/dist/mcp-mock.cjs +112 -1
  145. package/dist/mcp-mock.cjs.map +1 -1
  146. package/dist/mcp-mock.d.cts +33 -2
  147. package/dist/mcp-mock.d.cts.map +1 -1
  148. package/dist/mcp-mock.d.ts +33 -2
  149. package/dist/mcp-mock.d.ts.map +1 -1
  150. package/dist/mcp-mock.js +112 -1
  151. package/dist/mcp-mock.js.map +1 -1
  152. package/dist/mcp-recorder.cjs +1224 -0
  153. package/dist/mcp-recorder.cjs.map +1 -0
  154. package/dist/mcp-recorder.d.cts +108 -0
  155. package/dist/mcp-recorder.d.cts.map +1 -0
  156. package/dist/mcp-recorder.d.ts +108 -0
  157. package/dist/mcp-recorder.d.ts.map +1 -0
  158. package/dist/mcp-recorder.js +1215 -0
  159. package/dist/mcp-recorder.js.map +1 -0
  160. package/dist/messages.cjs +362 -56
  161. package/dist/messages.cjs.map +1 -1
  162. package/dist/messages.d.cts.map +1 -1
  163. package/dist/messages.d.ts.map +1 -1
  164. package/dist/messages.js +363 -58
  165. package/dist/messages.js.map +1 -1
  166. package/dist/misbehavior.cjs +1523 -0
  167. package/dist/misbehavior.cjs.map +1 -0
  168. package/dist/misbehavior.d.cts +43 -0
  169. package/dist/misbehavior.d.cts.map +1 -0
  170. package/dist/misbehavior.d.ts +43 -0
  171. package/dist/misbehavior.d.ts.map +1 -0
  172. package/dist/misbehavior.js +1511 -0
  173. package/dist/misbehavior.js.map +1 -0
  174. package/dist/ollama.cjs +310 -112
  175. package/dist/ollama.cjs.map +1 -1
  176. package/dist/ollama.d.cts.map +1 -1
  177. package/dist/ollama.d.ts.map +1 -1
  178. package/dist/ollama.js +311 -113
  179. package/dist/ollama.js.map +1 -1
  180. package/dist/openrouter-video.cjs +30 -2
  181. package/dist/openrouter-video.cjs.map +1 -1
  182. package/dist/openrouter-video.d.cts.map +1 -1
  183. package/dist/openrouter-video.d.ts.map +1 -1
  184. package/dist/openrouter-video.js +30 -2
  185. package/dist/openrouter-video.js.map +1 -1
  186. package/dist/record-sanitize.cjs +231 -0
  187. package/dist/record-sanitize.cjs.map +1 -0
  188. package/dist/record-sanitize.js +224 -0
  189. package/dist/record-sanitize.js.map +1 -0
  190. package/dist/recorder.cjs +106 -5
  191. package/dist/recorder.cjs.map +1 -1
  192. package/dist/recorder.d.cts +2 -1
  193. package/dist/recorder.d.cts.map +1 -1
  194. package/dist/recorder.d.ts +2 -1
  195. package/dist/recorder.d.ts.map +1 -1
  196. package/dist/recorder.js +107 -7
  197. package/dist/recorder.js.map +1 -1
  198. package/dist/responses.cjs +667 -171
  199. package/dist/responses.cjs.map +1 -1
  200. package/dist/responses.d.cts +5 -13
  201. package/dist/responses.d.cts.map +1 -1
  202. package/dist/responses.d.ts +5 -13
  203. package/dist/responses.d.ts.map +1 -1
  204. package/dist/responses.js +665 -174
  205. package/dist/responses.js.map +1 -1
  206. package/dist/router.cjs +24 -2
  207. package/dist/router.cjs.map +1 -1
  208. package/dist/router.d.cts.map +1 -1
  209. package/dist/router.d.ts.map +1 -1
  210. package/dist/router.js +25 -4
  211. package/dist/router.js.map +1 -1
  212. package/dist/server.cjs +572 -76
  213. package/dist/server.cjs.map +1 -1
  214. package/dist/server.d.cts.map +1 -1
  215. package/dist/server.d.ts.map +1 -1
  216. package/dist/server.js +574 -78
  217. package/dist/server.js.map +1 -1
  218. package/dist/stream-collapse.cjs +236 -34
  219. package/dist/stream-collapse.cjs.map +1 -1
  220. package/dist/stream-collapse.d.cts +39 -4
  221. package/dist/stream-collapse.d.cts.map +1 -1
  222. package/dist/stream-collapse.d.ts +39 -4
  223. package/dist/stream-collapse.d.ts.map +1 -1
  224. package/dist/stream-collapse.js +235 -35
  225. package/dist/stream-collapse.js.map +1 -1
  226. package/dist/types.cjs.map +1 -1
  227. package/dist/types.d.cts +315 -4
  228. package/dist/types.d.cts.map +1 -1
  229. package/dist/types.d.ts +315 -4
  230. package/dist/types.d.ts.map +1 -1
  231. package/dist/types.js.map +1 -1
  232. package/dist/validate-cli.cjs +36 -4
  233. package/dist/validate-cli.cjs.map +1 -1
  234. package/dist/validate-cli.js +37 -5
  235. package/dist/validate-cli.js.map +1 -1
  236. package/dist/vector-types.d.ts.map +1 -1
  237. package/dist/version.cjs +45 -0
  238. package/dist/version.cjs.map +1 -0
  239. package/dist/version.js +44 -0
  240. package/dist/version.js.map +1 -0
  241. package/dist/vitest.cjs +66 -10
  242. package/dist/vitest.cjs.map +1 -1
  243. package/dist/vitest.d.cts +35 -4
  244. package/dist/vitest.d.cts.map +1 -1
  245. package/dist/vitest.d.ts +35 -4
  246. package/dist/vitest.d.ts.map +1 -1
  247. package/dist/vitest.js +67 -11
  248. package/dist/vitest.js.map +1 -1
  249. package/dist/watcher.cjs +6 -2
  250. package/dist/watcher.cjs.map +1 -1
  251. package/dist/watcher.js +6 -2
  252. package/dist/watcher.js.map +1 -1
  253. package/dist/ws-gemini-live.cjs +210 -101
  254. package/dist/ws-gemini-live.cjs.map +1 -1
  255. package/dist/ws-gemini-live.d.cts +9 -3
  256. package/dist/ws-gemini-live.d.cts.map +1 -1
  257. package/dist/ws-gemini-live.d.ts +9 -3
  258. package/dist/ws-gemini-live.d.ts.map +1 -1
  259. package/dist/ws-gemini-live.js +211 -102
  260. package/dist/ws-gemini-live.js.map +1 -1
  261. package/dist/ws-realtime.cjs +175 -62
  262. package/dist/ws-realtime.cjs.map +1 -1
  263. package/dist/ws-realtime.d.cts +8 -3
  264. package/dist/ws-realtime.d.cts.map +1 -1
  265. package/dist/ws-realtime.d.ts +8 -3
  266. package/dist/ws-realtime.d.ts.map +1 -1
  267. package/dist/ws-realtime.js +176 -63
  268. package/dist/ws-realtime.js.map +1 -1
  269. package/dist/ws-responses.cjs +109 -16
  270. package/dist/ws-responses.cjs.map +1 -1
  271. package/dist/ws-responses.d.cts +8 -12
  272. package/dist/ws-responses.d.cts.map +1 -1
  273. package/dist/ws-responses.d.ts +8 -12
  274. package/dist/ws-responses.d.ts.map +1 -1
  275. package/dist/ws-responses.js +111 -18
  276. package/dist/ws-responses.js.map +1 -1
  277. package/package.json +10 -2
  278. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1,5 +1,5 @@
1
1
  import { Logger } from "./logger.cjs";
2
- import { ChatCompletionRequest, Fixture, RecordConfig, RecordProviderKey } from "./types.cjs";
2
+ import { ChatCompletionRequest, Fixture, RecordConfig, RecordProviderKey, ResponsesToolsMode } from "./types.cjs";
3
3
  import * as http$1 from "node:http";
4
4
 
5
5
  //#region src/recorder.d.ts
@@ -72,6 +72,7 @@ declare function proxyAndRecord(req: http$1.IncomingMessage, res: http$1.ServerR
72
72
  record?: RecordConfig;
73
73
  logger: Logger;
74
74
  requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;
75
+ responsesTools?: ResponsesToolsMode;
75
76
  }, rawBody?: string, options?: ProxyOptions): Promise<ProxyOutcome>;
76
77
  /**
77
78
  * Decodes a sequence of byte chunks to UTF-8 text for SSE/NDJSON frame
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.cts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAiOiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA8OU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
1
+ {"version":3,"file":"recorder.d.cts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAsOiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA8OU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;mBAClC;+BAGT,eACT,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  import { Logger } from "./logger.js";
2
- import { ChatCompletionRequest, Fixture, RecordConfig, RecordProviderKey } from "./types.js";
2
+ import { ChatCompletionRequest, Fixture, RecordConfig, RecordProviderKey, ResponsesToolsMode } from "./types.js";
3
3
  import * as http$1 from "node:http";
4
4
 
5
5
  //#region src/recorder.d.ts
@@ -72,6 +72,7 @@ declare function proxyAndRecord(req: http$1.IncomingMessage, res: http$1.ServerR
72
72
  record?: RecordConfig;
73
73
  logger: Logger;
74
74
  requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;
75
+ responsesTools?: ResponsesToolsMode;
75
76
  }, rawBody?: string, options?: ProxyOptions): Promise<ProxyOutcome>;
76
77
  /**
77
78
  * Decodes a sequence of byte chunks to UTF-8 text for SSE/NDJSON frame
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAiOiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA8OU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
1
+ {"version":3,"file":"recorder.d.ts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAsOiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA8OU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;mBAClC;+BAGT,eACT,QAAQ"}
package/dist/recorder.js CHANGED
@@ -4,7 +4,7 @@ import { isAuthenticatedRequest, isRecognizedApiKeyHeader } from "./api-key-auth
4
4
  import { getTestId, hasMintedRequestId, slugifyContext, slugifyTestId } from "./helpers.js";
5
5
  import { writeErrorResponse } from "./sse-writer.js";
6
6
  import { currentTurnHasToolResult, getLastMessageByRole, getTextContent } from "./router.js";
7
- import { capturedRedactedData, collapseStreamingResponse } from "./stream-collapse.js";
7
+ import { capturedRedactedData, collapseStreamingResponseWithResponsesTools, withoutResponsesToolFields } from "./stream-collapse.js";
8
8
  import { resolveUpstreamUrl } from "./url.js";
9
9
  import { applyConfiguredProviderAuth, applyProviderAuth } from "./provider-auth.js";
10
10
  import * as http$1 from "node:http";
@@ -380,7 +380,8 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
380
380
  const contentType = upstreamHeaders["content-type"];
381
381
  const ctString = pickContentType(contentType);
382
382
  const isBinaryStream = ctString.toLowerCase().includes("application/vnd.amazon.eventstream");
383
- const collapsed = collapseStreamingResponse(ctString, providerKey, isBinaryStream ? rawBuffer : upstreamBody, defaults.logger);
383
+ const collapsedRaw = collapseStreamingResponseWithResponsesTools(ctString, providerKey, isBinaryStream ? rawBuffer : upstreamBody, defaults.logger);
384
+ const collapsed = collapsedRaw && defaults.responsesTools !== "extended" ? withoutResponsesToolFields(collapsedRaw) : collapsedRaw;
384
385
  let fixtureResponse;
385
386
  if (ctString.toLowerCase().startsWith("audio/") && upstreamStatus >= 200 && upstreamStatus < 300) {
386
387
  const audioFormat = ctString.toLowerCase().replace("audio/", "").replace("mpeg", "mp3").split(";")[0].trim();
@@ -414,7 +415,7 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
414
415
  ...audioContentSpread,
415
416
  ...audioReasoningSpread
416
417
  };
417
- } else if (collapsed.content === "" && (!collapsed.toolCalls || collapsed.toolCalls.length === 0)) {
418
+ } else if (collapsed.content === "" && (!collapsed.toolCalls || collapsed.toolCalls.length === 0) && !collapsed.customToolCalls?.length) {
418
419
  defaults.logger.warn("Stream collapse produced empty content — fixture may be incomplete");
419
420
  const reasoningSpread = collapsed.reasoning ? { reasoning: collapsed.reasoning } : {};
420
421
  const reasoningSignatureSpread = collapsed.reasoning && collapsed.reasoningSignature ? { reasoningSignature: collapsed.reasoningSignature } : {};
@@ -435,12 +436,27 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
435
436
  logDroppedReasoningSignature(defaults.logger, collapsed.reasoning, collapsed.reasoningSignature);
436
437
  const redactedThinkingSpread = collapsed.redactedThinking?.length ? { redactedThinking: collapsed.redactedThinking } : {};
437
438
  const webSearchesSpread = collapsed.webSearches?.length ? { webSearches: collapsed.webSearches } : {};
438
- if (collapsed.toolCalls && collapsed.toolCalls.length > 0) {
439
- const sanitizedToolCalls = collapsed.toolCalls.map((tc) => ({
439
+ if (collapsed.customToolCalls?.length) {
440
+ const toolCalls = (collapsed.toolCalls ?? []).map(sanitizeRecordedToolCall);
441
+ const customToolCalls = collapsed.customToolCalls.map((tc) => ({
440
442
  ...tc,
441
443
  name: tc.name ?? "",
442
- arguments: tc.arguments ?? "{}"
444
+ input: tc.input ?? ""
443
445
  }));
446
+ const orderSpread = collapsed.responsesBlocks?.length ? { responsesBlocks: collapsed.responsesBlocks } : collapsed.blocks?.length ? { blocks: collapsed.blocks } : {};
447
+ fixtureResponse = {
448
+ ...collapsed.content ? { content: collapsed.content } : {},
449
+ toolCalls,
450
+ customToolCalls,
451
+ ...orderSpread,
452
+ ...reasoningSpread,
453
+ ...reasoningSignatureSpread,
454
+ ...redactedThinkingSpread,
455
+ ...webSearchesSpread,
456
+ ...usageSpread
457
+ };
458
+ } else if (collapsed.toolCalls && collapsed.toolCalls.length > 0) {
459
+ const sanitizedToolCalls = collapsed.toolCalls.map(sanitizeRecordedToolCall);
444
460
  if (collapsed.content) {
445
461
  const blocksSpread = collapsed.blocks?.length ? { blocks: collapsed.blocks } : {};
446
462
  fixtureResponse = {
@@ -803,6 +819,14 @@ function makeUpstreamRequest(target, headers, body, clientRes, method = "POST",
803
819
  function logDroppedReasoningSignature(logger, reasoning, reasoningSignature) {
804
820
  if (reasoningSignature && !reasoning) logger?.warn("Dropping captured reasoningSignature — no plaintext reasoning to attach it to");
805
821
  }
822
+ /** Sanitize a collapsed function call before it is persisted: string `name` and `arguments`. */
823
+ function sanitizeRecordedToolCall(tc) {
824
+ return {
825
+ ...tc,
826
+ name: tc.name ?? "",
827
+ arguments: tc.arguments ?? "{}"
828
+ };
829
+ }
806
830
  /**
807
831
  * Coerce a tool call's `arguments` field into the string the fixture contract
808
832
  * requires (types.ts `ToolCall.arguments: string`). When the upstream omits the
@@ -1267,7 +1291,83 @@ function buildFixtureMetadata(request) {
1267
1291
  if (request.tools && request.tools.length > 0) meta.toolsHash = crypto$1.createHash("sha256").update(JSON.stringify(request.tools)).digest("hex").slice(0, 8);
1268
1292
  return Object.keys(meta).length > 0 ? meta : void 0;
1269
1293
  }
1294
+ /**
1295
+ * MR11: read-merge-validate-write one service fakes file atomically (temp +
1296
+ * rename, 0o600). Synchronous, so writes to one path never interleave in this
1297
+ * process. Keeps unknown top-level keys (fakes:F9). `validate` returns a
1298
+ * problem text, or null when the whole merged file is valid. Logs RL4 on a
1299
+ * write; a failure is returned, never logged here (the caller logs RL1 with
1300
+ * its own context).
1301
+ */
1302
+ function persistServiceFakes(opts) {
1303
+ const { filepath, merge, validate, logger } = opts;
1304
+ let existing = null;
1305
+ let text = null;
1306
+ try {
1307
+ text = fs.readFileSync(filepath, "utf-8");
1308
+ } catch (err) {
1309
+ if (err.code !== "ENOENT") return {
1310
+ kind: "failed",
1311
+ stage: "write",
1312
+ error: err instanceof Error ? err.message : "Unknown filesystem error"
1313
+ };
1314
+ }
1315
+ if (text !== null) {
1316
+ let parsed;
1317
+ try {
1318
+ parsed = JSON.parse(text);
1319
+ } catch {
1320
+ return {
1321
+ kind: "failed",
1322
+ stage: "read",
1323
+ error: `${filepath} is not valid JSON`
1324
+ };
1325
+ }
1326
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {
1327
+ kind: "failed",
1328
+ stage: "read",
1329
+ error: `${filepath} is not a JSON object`
1330
+ };
1331
+ existing = parsed;
1332
+ }
1333
+ const content = merge(existing);
1334
+ const problem = validate(content);
1335
+ if (problem !== null) return {
1336
+ kind: "failed",
1337
+ stage: "validate",
1338
+ error: problem
1339
+ };
1340
+ let tmpPath;
1341
+ try {
1342
+ fs.mkdirSync(path.dirname(filepath), { recursive: true });
1343
+ const bytes = Buffer.from(JSON.stringify(content, null, 2), "utf-8");
1344
+ tmpPath = filepath + ".tmp." + crypto$1.randomUUID();
1345
+ fs.writeFileSync(tmpPath, bytes, {
1346
+ flag: "wx",
1347
+ mode: 384
1348
+ });
1349
+ fs.renameSync(tmpPath, filepath);
1350
+ tmpPath = void 0;
1351
+ logger.warn(`Response recorded → ${filepath}`);
1352
+ return {
1353
+ kind: "written",
1354
+ filepath,
1355
+ sha256: crypto$1.createHash("sha256").update(bytes).digest("hex"),
1356
+ content
1357
+ };
1358
+ } catch (err) {
1359
+ return {
1360
+ kind: "failed",
1361
+ stage: "write",
1362
+ error: err instanceof Error ? err.message : "Unknown filesystem error"
1363
+ };
1364
+ } finally {
1365
+ if (tmpPath) try {
1366
+ fs.unlinkSync(tmpPath);
1367
+ } catch {}
1368
+ }
1369
+ }
1270
1370
 
1271
1371
  //#endregion
1272
- export { DEFAULT_MAX_PROXY_BUFFER_BYTES, DEFAULT_MAX_PROXY_BUFFER_FRAMES, PROXY_BUFFER_HARD_CEILING, buildFixtureMatch, buildForwardHeaders, clampTimeout, persistFixture, prepareEgressHeaders, proxyAndRecord, removeForwardHeader, sanitizeHeaderValue, setForwardHeaderDefault };
1372
+ export { DEFAULT_MAX_PROXY_BUFFER_BYTES, DEFAULT_MAX_PROXY_BUFFER_FRAMES, PROXY_BUFFER_HARD_CEILING, buildFixtureMatch, buildForwardHeaders, clampTimeout, persistFixture, persistServiceFakes, prepareEgressHeaders, proxyAndRecord, removeForwardHeader, sanitizeHeaderValue, setForwardHeaderDefault };
1273
1373
  //# sourceMappingURL=recorder.js.map