@copilotkit/aimock 1.44.0 → 1.45.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 (272) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +31 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.ts.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 +209 -16
  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 +207 -17
  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/record-sanitize.cjs +231 -0
  181. package/dist/record-sanitize.cjs.map +1 -0
  182. package/dist/record-sanitize.js +224 -0
  183. package/dist/record-sanitize.js.map +1 -0
  184. package/dist/recorder.cjs +106 -5
  185. package/dist/recorder.cjs.map +1 -1
  186. package/dist/recorder.d.cts +2 -1
  187. package/dist/recorder.d.cts.map +1 -1
  188. package/dist/recorder.d.ts +2 -1
  189. package/dist/recorder.d.ts.map +1 -1
  190. package/dist/recorder.js +107 -7
  191. package/dist/recorder.js.map +1 -1
  192. package/dist/responses.cjs +667 -171
  193. package/dist/responses.cjs.map +1 -1
  194. package/dist/responses.d.cts +5 -13
  195. package/dist/responses.d.cts.map +1 -1
  196. package/dist/responses.d.ts +5 -13
  197. package/dist/responses.d.ts.map +1 -1
  198. package/dist/responses.js +665 -174
  199. package/dist/responses.js.map +1 -1
  200. package/dist/router.cjs +24 -2
  201. package/dist/router.cjs.map +1 -1
  202. package/dist/router.d.cts.map +1 -1
  203. package/dist/router.d.ts.map +1 -1
  204. package/dist/router.js +25 -4
  205. package/dist/router.js.map +1 -1
  206. package/dist/server.cjs +572 -76
  207. package/dist/server.cjs.map +1 -1
  208. package/dist/server.d.cts.map +1 -1
  209. package/dist/server.d.ts.map +1 -1
  210. package/dist/server.js +574 -78
  211. package/dist/server.js.map +1 -1
  212. package/dist/stream-collapse.cjs +236 -34
  213. package/dist/stream-collapse.cjs.map +1 -1
  214. package/dist/stream-collapse.d.cts +39 -4
  215. package/dist/stream-collapse.d.cts.map +1 -1
  216. package/dist/stream-collapse.d.ts +39 -4
  217. package/dist/stream-collapse.d.ts.map +1 -1
  218. package/dist/stream-collapse.js +235 -35
  219. package/dist/stream-collapse.js.map +1 -1
  220. package/dist/types.cjs.map +1 -1
  221. package/dist/types.d.cts +315 -4
  222. package/dist/types.d.cts.map +1 -1
  223. package/dist/types.d.ts +315 -4
  224. package/dist/types.d.ts.map +1 -1
  225. package/dist/types.js.map +1 -1
  226. package/dist/validate-cli.cjs +36 -4
  227. package/dist/validate-cli.cjs.map +1 -1
  228. package/dist/validate-cli.js +37 -5
  229. package/dist/validate-cli.js.map +1 -1
  230. package/dist/vector-types.d.ts.map +1 -1
  231. package/dist/version.cjs +45 -0
  232. package/dist/version.cjs.map +1 -0
  233. package/dist/version.js +44 -0
  234. package/dist/version.js.map +1 -0
  235. package/dist/vitest.cjs +66 -10
  236. package/dist/vitest.cjs.map +1 -1
  237. package/dist/vitest.d.cts +35 -4
  238. package/dist/vitest.d.cts.map +1 -1
  239. package/dist/vitest.d.ts +35 -4
  240. package/dist/vitest.d.ts.map +1 -1
  241. package/dist/vitest.js +67 -11
  242. package/dist/vitest.js.map +1 -1
  243. package/dist/watcher.cjs +6 -2
  244. package/dist/watcher.cjs.map +1 -1
  245. package/dist/watcher.js +6 -2
  246. package/dist/watcher.js.map +1 -1
  247. package/dist/ws-gemini-live.cjs +210 -101
  248. package/dist/ws-gemini-live.cjs.map +1 -1
  249. package/dist/ws-gemini-live.d.cts +9 -3
  250. package/dist/ws-gemini-live.d.cts.map +1 -1
  251. package/dist/ws-gemini-live.d.ts +9 -3
  252. package/dist/ws-gemini-live.d.ts.map +1 -1
  253. package/dist/ws-gemini-live.js +211 -102
  254. package/dist/ws-gemini-live.js.map +1 -1
  255. package/dist/ws-realtime.cjs +175 -62
  256. package/dist/ws-realtime.cjs.map +1 -1
  257. package/dist/ws-realtime.d.cts +8 -3
  258. package/dist/ws-realtime.d.cts.map +1 -1
  259. package/dist/ws-realtime.d.ts +8 -3
  260. package/dist/ws-realtime.d.ts.map +1 -1
  261. package/dist/ws-realtime.js +176 -63
  262. package/dist/ws-realtime.js.map +1 -1
  263. package/dist/ws-responses.cjs +109 -16
  264. package/dist/ws-responses.cjs.map +1 -1
  265. package/dist/ws-responses.d.cts +8 -12
  266. package/dist/ws-responses.d.cts.map +1 -1
  267. package/dist/ws-responses.d.ts +8 -12
  268. package/dist/ws-responses.d.ts.map +1 -1
  269. package/dist/ws-responses.js +111 -18
  270. package/dist/ws-responses.js.map +1 -1
  271. package/package.json +10 -2
  272. package/skills/write-fixtures/SKILL.md +179 -21
@@ -80,6 +80,10 @@ function guardCollapseBody(body) {
80
80
  function isCollapseInputTruncated(body) {
81
81
  return body.length > effectiveCollapseStringLimit();
82
82
  }
83
+ /** A Responses `namespace` field when it is a non-empty string, else undefined. */
84
+ function responsesNamespace(item) {
85
+ return typeof item.namespace === "string" && item.namespace !== "" ? item.namespace : void 0;
86
+ }
83
87
  /**
84
88
  * Normalize a tool call's accumulated `arguments` into valid JSON exactly like
85
89
  * the flat-`toolCalls` recorder path: an empty / whitespace-only / missing
@@ -101,7 +105,40 @@ function toToolCallBlock(ref) {
101
105
  type: "toolCall",
102
106
  name: ref.name,
103
107
  arguments: normalizeToolArguments(ref.arguments),
104
- ...ref.id ? { id: ref.id } : {}
108
+ ...ref.id ? { id: ref.id } : {},
109
+ ...ref.namespace ? { namespace: ref.namespace } : {}
110
+ };
111
+ }
112
+ /**
113
+ * Build a `customToolCall` block from a custom-call accumulator. The `input` is
114
+ * free text: it is kept as is, never normalized to `"{}"`.
115
+ */
116
+ function toCustomToolCallBlock(ref) {
117
+ return {
118
+ type: "customToolCall",
119
+ name: ref.name,
120
+ input: ref.input,
121
+ ...ref.id ? { id: ref.id } : {},
122
+ ...ref.namespace ? { namespace: ref.namespace } : {}
123
+ };
124
+ }
125
+ /** Project a function-call accumulator to a flat fixture tool call. */
126
+ function toFunctionToolCall(ref) {
127
+ return {
128
+ name: ref.name,
129
+ arguments: normalizeToolArguments(ref.arguments),
130
+ ...ref.id ? { id: ref.id } : {},
131
+ ...ref.namespace ? { namespace: ref.namespace } : {}
132
+ };
133
+ }
134
+ /** Project a custom-call accumulator to a flat fixture custom tool call. */
135
+ function toCustomToolCall(ref) {
136
+ return {
137
+ type: "custom",
138
+ name: ref.name,
139
+ input: ref.input,
140
+ ...ref.id ? { id: ref.id } : {},
141
+ ...ref.namespace ? { namespace: ref.namespace } : {}
105
142
  };
106
143
  }
107
144
  /**
@@ -111,19 +148,31 @@ function toToolCallBlock(ref) {
111
148
  * `CollapseResult.blocks` unset and the recorder keeps the legacy shape.
112
149
  *
113
150
  * Interleaved ⇔ (a tool atom appears strictly before the first text atom) OR
114
- * (a text atom appears after any tool atom). A stream with no tool atoms, or
151
+ * (a text atom appears after any tool atom). Tool atoms are `toolCall` and
152
+ * `customToolCall` atoms. A stream with no tool atoms, or
115
153
  * with no text atoms, is never interleaved. Text-first-then-tools is the common
116
154
  * legacy case and is explicitly NOT interleaved.
117
155
  *
118
- * CONSISTENCY (#274): each toolCall block is derived from the SAME accumulator
119
- * object referenced by its atom and normalized identically to the flat
120
- * `toolCalls` path ({@link toToolCallBlock} / {@link normalizeToolArguments}).
121
- * Because the atom `ref` is the very object the flat list is built from, the
122
- * block and its flat counterpart describe the same call by identity — even when
123
- * upstream tool-call indices do not match stream-arrival order. Empty/missing
124
- * arguments normalize to `"{}"` in BOTH representations, never `""`.
156
+ * CONSISTENCY (#274): each tool block is derived from the SAME accumulator
157
+ * object referenced by its atom. Because the atom `ref` is the very object the
158
+ * flat list is built from, the block and its flat counterpart describe the same
159
+ * call by identity — even when upstream tool-call indices do not match
160
+ * stream-arrival order. A `toolCall` block is normalized identically to the
161
+ * flat `toolCalls` path ({@link toToolCallBlock} / {@link normalizeToolArguments}):
162
+ * empty/missing arguments become `"{}"` in BOTH representations, never `""`. A
163
+ * `customToolCall` block ({@link toCustomToolCallBlock}) keeps `input` verbatim,
164
+ * the same as the flat custom tool call ({@link toCustomToolCall}); it is never
165
+ * normalized to `"{}"`.
125
166
  */
126
167
  function buildOrderedBlocks(atoms) {
168
+ return orderedBlocksFrom(atoms.filter((a) => a.kind !== "customToolCall"))?.filter((block) => block.type !== "customToolCall");
169
+ }
170
+ /**
171
+ * {@link buildOrderedBlocks} over every atom, custom calls included, for
172
+ * `CollapseResult.responsesBlocks`. With `force`, the blocks are built even
173
+ * when text and tools are not interleaved.
174
+ */
175
+ function orderedBlocksFrom(atoms, force = false) {
127
176
  let firstTextIndex = -1;
128
177
  let firstToolIndex = -1;
129
178
  let textAfterTool = false;
@@ -137,8 +186,10 @@ function buildOrderedBlocks(atoms) {
137
186
  sawTool = true;
138
187
  if (firstToolIndex === -1) firstToolIndex = i;
139
188
  }
140
- if (!sawTool || !sawText) return void 0;
141
- if (!(firstToolIndex < firstTextIndex) && !textAfterTool) return void 0;
189
+ if (!force) {
190
+ if (!sawTool || !sawText) return void 0;
191
+ if (!(firstToolIndex < firstTextIndex) && !textAfterTool) return void 0;
192
+ }
142
193
  const blocks = [];
143
194
  let pendingText = "";
144
195
  let hasPendingText = false;
@@ -157,7 +208,7 @@ function buildOrderedBlocks(atoms) {
157
208
  hasPendingText = true;
158
209
  } else {
159
210
  flushText();
160
- blocks.push(toToolCallBlock(a.ref));
211
+ blocks.push(a.kind === "customToolCall" ? toCustomToolCallBlock(a.ref) : toToolCallBlock(a.ref));
161
212
  }
162
213
  flushText();
163
214
  return blocks;
@@ -234,8 +285,41 @@ function extractSSEData(lines) {
234
285
  * Format:
235
286
  * data: {"id":"chatcmpl-123","choices":[{"delta":{"content":"Hello"}}]}\n\n
236
287
  * data: [DONE]\n\n
288
+ *
289
+ * Public, with the 1.44.0 result: an OpenAI Responses `namespace` and custom
290
+ * tool calls are dropped. The recorder uses {@link collapseOpenAISSEWithResponsesTools}.
237
291
  */
238
292
  function collapseOpenAISSE(rawBody) {
293
+ return withoutResponsesToolFields(collapseOpenAISSEWithResponsesTools(rawBody));
294
+ }
295
+ /**
296
+ * A collapse result as 1.44.0 returned and recorded it: no `namespace` on a
297
+ * function call or `toolCall` block, and no custom tool calls.
298
+ */
299
+ function withoutResponsesToolFields(collapsed) {
300
+ if (collapsed.customToolCalls === void 0 && collapsed.responsesBlocks === void 0 && !collapsed.toolCalls?.some((tc) => tc.namespace !== void 0) && !collapsed.blocks?.some((block) => block.type !== "text" && block.namespace !== void 0)) return collapsed;
301
+ const result = { ...collapsed };
302
+ delete result.customToolCalls;
303
+ delete result.responsesBlocks;
304
+ if (result.toolCalls) result.toolCalls = result.toolCalls.map((tc) => {
305
+ if (tc.namespace === void 0) return tc;
306
+ const copy = { ...tc };
307
+ delete copy.namespace;
308
+ return copy;
309
+ });
310
+ if (result.blocks) result.blocks = result.blocks.map((block) => {
311
+ if (block.type === "text" || block.namespace === void 0) return block;
312
+ const copy = { ...block };
313
+ delete copy.namespace;
314
+ return copy;
315
+ });
316
+ return result;
317
+ }
318
+ /**
319
+ * @internal {@link collapseOpenAISSE} keeping an OpenAI Responses `namespace`
320
+ * and custom tool calls, for the recorder with `responsesTools: "extended"`.
321
+ */
322
+ function collapseOpenAISSEWithResponsesTools(rawBody) {
239
323
  const inputTruncated = isCollapseInputTruncated(rawBody);
240
324
  const lines = splitSSEEvents(guardCollapseBody(rawBody));
241
325
  let content = "";
@@ -296,14 +380,19 @@ function collapseOpenAISSE(rawBody) {
296
380
  if (item?.type === "function_call" && typeof parsed.output_index === "number") {
297
381
  const entry = toolCallMap.get(parsed.output_index);
298
382
  if (entry) {
299
- if (!entry.id && typeof item.call_id === "string") entry.id = item.call_id;
300
- if (!entry.name && typeof item.name === "string") entry.name = item.name;
301
- if (entry.arguments === "" && typeof item.arguments === "string") entry.arguments = item.arguments;
383
+ if (entry.kind === "function") {
384
+ if (!entry.id && typeof item.call_id === "string") entry.id = item.call_id;
385
+ if (!entry.name && typeof item.name === "string") entry.name = item.name;
386
+ if (!entry.namespace) entry.namespace = responsesNamespace(item);
387
+ if (entry.arguments === "" && typeof item.arguments === "string") entry.arguments = item.arguments;
388
+ }
302
389
  } else {
303
390
  const created = {
391
+ kind: "function",
304
392
  id: typeof item.call_id === "string" ? item.call_id : "",
305
393
  name: typeof item.name === "string" ? item.name : "",
306
- arguments: typeof item.arguments === "string" ? item.arguments : ""
394
+ arguments: typeof item.arguments === "string" ? item.arguments : "",
395
+ namespace: responsesNamespace(item)
307
396
  };
308
397
  toolCallMap.set(parsed.output_index, created);
309
398
  orderAtoms.push({
@@ -313,15 +402,42 @@ function collapseOpenAISSE(rawBody) {
313
402
  }
314
403
  continue;
315
404
  }
405
+ if (item?.type === "custom_tool_call" && typeof parsed.output_index === "number") {
406
+ const entry = toolCallMap.get(parsed.output_index);
407
+ if (entry) {
408
+ if (entry.kind === "custom") {
409
+ if (!entry.id && typeof item.call_id === "string") entry.id = item.call_id;
410
+ if (!entry.name && typeof item.name === "string") entry.name = item.name;
411
+ if (!entry.namespace) entry.namespace = responsesNamespace(item);
412
+ if (entry.input === "" && typeof item.input === "string") entry.input = item.input;
413
+ }
414
+ } else {
415
+ const created = {
416
+ kind: "custom",
417
+ id: typeof item.call_id === "string" ? item.call_id : "",
418
+ name: typeof item.name === "string" ? item.name : "",
419
+ input: typeof item.input === "string" ? item.input : "",
420
+ namespace: responsesNamespace(item)
421
+ };
422
+ toolCallMap.set(parsed.output_index, created);
423
+ orderAtoms.push({
424
+ kind: "customToolCall",
425
+ ref: created
426
+ });
427
+ }
428
+ continue;
429
+ }
316
430
  }
317
431
  if (parsed.type === "response.output_item.added") {
318
432
  const item = parsed.item;
319
433
  if (item?.type === "function_call" && typeof parsed.output_index === "number") {
320
434
  if (!toolCallMap.has(parsed.output_index)) {
321
435
  const created = {
436
+ kind: "function",
322
437
  id: typeof item.call_id === "string" ? item.call_id : "",
323
438
  name: typeof item.name === "string" ? item.name : "",
324
- arguments: ""
439
+ arguments: "",
440
+ namespace: responsesNamespace(item)
325
441
  };
326
442
  toolCallMap.set(parsed.output_index, created);
327
443
  orderAtoms.push({
@@ -331,11 +447,66 @@ function collapseOpenAISSE(rawBody) {
331
447
  }
332
448
  continue;
333
449
  }
450
+ if (item?.type === "custom_tool_call" && typeof parsed.output_index === "number") {
451
+ if (!toolCallMap.has(parsed.output_index)) {
452
+ const created = {
453
+ kind: "custom",
454
+ id: typeof item.call_id === "string" ? item.call_id : "",
455
+ name: typeof item.name === "string" ? item.name : "",
456
+ input: "",
457
+ namespace: responsesNamespace(item)
458
+ };
459
+ toolCallMap.set(parsed.output_index, created);
460
+ orderAtoms.push({
461
+ kind: "customToolCall",
462
+ ref: created
463
+ });
464
+ }
465
+ continue;
466
+ }
467
+ }
468
+ if (parsed.type === "response.custom_tool_call_input.delta" && typeof parsed.delta === "string" && typeof parsed.output_index === "number") {
469
+ let entry = toolCallMap.get(parsed.output_index);
470
+ if (!entry) {
471
+ entry = {
472
+ kind: "custom",
473
+ id: "",
474
+ name: "",
475
+ input: ""
476
+ };
477
+ toolCallMap.set(parsed.output_index, entry);
478
+ orderAtoms.push({
479
+ kind: "customToolCall",
480
+ ref: entry
481
+ });
482
+ }
483
+ if (entry.kind === "custom") entry.input += parsed.delta;
484
+ continue;
485
+ }
486
+ if (parsed.type === "response.custom_tool_call_input.done" && typeof parsed.output_index === "number") {
487
+ const entry = toolCallMap.get(parsed.output_index);
488
+ if (entry) {
489
+ if (entry.kind === "custom" && entry.input === "" && typeof parsed.input === "string") entry.input = parsed.input;
490
+ } else if (typeof parsed.input === "string") {
491
+ const created = {
492
+ kind: "custom",
493
+ id: "",
494
+ name: "",
495
+ input: parsed.input
496
+ };
497
+ toolCallMap.set(parsed.output_index, created);
498
+ orderAtoms.push({
499
+ kind: "customToolCall",
500
+ ref: created
501
+ });
502
+ }
503
+ continue;
334
504
  }
335
505
  if (parsed.type === "response.function_call_arguments.delta" && typeof parsed.delta === "string" && typeof parsed.output_index === "number") {
336
506
  let entry = toolCallMap.get(parsed.output_index);
337
507
  if (!entry) {
338
508
  entry = {
509
+ kind: "function",
339
510
  id: "",
340
511
  name: "",
341
512
  arguments: ""
@@ -346,15 +517,16 @@ function collapseOpenAISSE(rawBody) {
346
517
  ref: entry
347
518
  });
348
519
  }
349
- entry.arguments += parsed.delta;
520
+ if (entry.kind === "function") entry.arguments += parsed.delta;
350
521
  continue;
351
522
  }
352
523
  if (parsed.type === "response.function_call_arguments.done" && typeof parsed.output_index === "number") {
353
524
  const entry = toolCallMap.get(parsed.output_index);
354
525
  if (entry) {
355
- if (entry.arguments === "" && typeof parsed.arguments === "string") entry.arguments = parsed.arguments;
526
+ if (entry.kind === "function" && entry.arguments === "" && typeof parsed.arguments === "string") entry.arguments = parsed.arguments;
356
527
  } else if (typeof parsed.arguments === "string") {
357
528
  const created = {
529
+ kind: "function",
358
530
  id: "",
359
531
  name: "",
360
532
  arguments: parsed.arguments
@@ -407,6 +579,7 @@ function collapseOpenAISSE(rawBody) {
407
579
  lastToolCallKey = index;
408
580
  if (!toolCallMap.has(index)) {
409
581
  const created = {
582
+ kind: "function",
410
583
  id: rawId ?? "",
411
584
  name: fn?.name ?? "",
412
585
  arguments: ""
@@ -420,11 +593,11 @@ function collapseOpenAISSE(rawBody) {
420
593
  const entry = toolCallMap.get(index);
421
594
  if (fn?.name && typeof fn.name === "string" && !entry.name) entry.name = fn.name;
422
595
  if (tc.id && typeof tc.id === "string" && !entry.id) entry.id = tc.id;
423
- if (fn?.arguments && typeof fn.arguments === "string") entry.arguments += fn.arguments;
596
+ if (entry.kind === "function" && fn?.arguments && typeof fn.arguments === "string") entry.arguments += fn.arguments;
424
597
  }
425
598
  }
426
599
  const harmonyToolCalls = [];
427
- if (toolCallMap.size === 0 && require_harmony.isHarmonyContent(content)) {
600
+ if (!Array.from(toolCallMap.values()).some((tc) => tc.kind === "function") && require_harmony.isHarmonyContent(content)) {
428
601
  const parsed = require_harmony.parseHarmonyContent(content);
429
602
  if (parsed.failed) {
430
603
  harmonyUnparsed = true;
@@ -435,18 +608,22 @@ function collapseOpenAISSE(rawBody) {
435
608
  harmonyToolCalls.push(...parsed.toolCalls);
436
609
  }
437
610
  }
438
- if (toolCallMap.size > 0 || harmonyToolCalls.length > 0) {
611
+ const sortedEntries = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);
612
+ const customEntries = sortedEntries.flatMap(([, tc]) => tc.kind === "custom" ? [tc] : []);
613
+ const functionEntries = sortedEntries.flatMap(([, tc]) => tc.kind === "function" ? [tc] : []);
614
+ let customFields = {};
615
+ if (customEntries.length > 0) {
616
+ const firstCustomAtom = orderAtoms.findIndex((a) => a.kind === "customToolCall");
617
+ const responsesBlocks = orderedBlocksFrom(orderAtoms, orderAtoms.some((a, i) => a.kind === "toolCall" && i > firstCustomAtom));
618
+ customFields = {
619
+ customToolCalls: responsesBlocks ? orderAtoms.flatMap((a) => a.kind === "customToolCall" ? [toCustomToolCall(a.ref)] : []) : customEntries.map(toCustomToolCall),
620
+ ...responsesBlocks ? { responsesBlocks } : {}
621
+ };
622
+ }
623
+ if (functionEntries.length > 0 || harmonyToolCalls.length > 0) {
439
624
  const blocks = buildOrderedBlocks(orderAtoms);
440
- const orderedToolCalls = orderAtoms.filter((a) => a.kind === "toolCall").map((a) => ({
441
- name: a.ref.name,
442
- arguments: normalizeToolArguments(a.ref.arguments),
443
- ...a.ref.id ? { id: a.ref.id } : {}
444
- }));
445
- const indexSortedToolCalls = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b).map(([, tc]) => ({
446
- name: tc.name,
447
- arguments: normalizeToolArguments(tc.arguments),
448
- ...tc.id ? { id: tc.id } : {}
449
- }));
625
+ const orderedToolCalls = orderAtoms.flatMap((a) => a.kind === "toolCall" ? [toFunctionToolCall(a.ref)] : []);
626
+ const indexSortedToolCalls = functionEntries.map(toFunctionToolCall);
450
627
  return {
451
628
  ...transcriptSeen ? { transcription: {
452
629
  text: transcript,
@@ -456,6 +633,7 @@ function collapseOpenAISSE(rawBody) {
456
633
  ...blocks ? { blocks } : {},
457
634
  ...content ? { content } : {},
458
635
  toolCalls: [...blocks ? orderedToolCalls : indexSortedToolCalls, ...harmonyToolCalls],
636
+ ...customFields,
459
637
  ...reasoning ? { reasoning } : {},
460
638
  ...webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {},
461
639
  ...usage ? { usage } : {},
@@ -473,6 +651,7 @@ function collapseOpenAISSE(rawBody) {
473
651
  ...transcriptUsage ? { usage: transcriptUsage } : {}
474
652
  } } : {},
475
653
  content,
654
+ ...customFields,
476
655
  ...reasoning ? { reasoning } : {},
477
656
  ...webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {},
478
657
  ...usage ? { usage } : {},
@@ -1011,6 +1190,16 @@ function collapseBedrockEventStream(rawBody) {
1011
1190
  let parsed;
1012
1191
  try {
1013
1192
  parsed = JSON.parse(frameStr);
1193
+ if (frame.headers[":event-type"] === "chunk" && parsed !== null && typeof parsed === "object" && Object.hasOwn(parsed, "bytes")) try {
1194
+ const bytes = parsed.bytes;
1195
+ if (typeof bytes !== "string" || bytes.length === 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(bytes)) throw new TypeError("bytes must be a nonempty base64 string");
1196
+ const event = JSON.parse(Buffer.from(bytes, "base64").toString("utf8"));
1197
+ if (event === null || typeof event !== "object" || Array.isArray(event) || !("type" in event) || typeof event.type !== "string") throw new TypeError("decoded bytes must contain a Claude event object");
1198
+ parsed = event;
1199
+ } catch (err) {
1200
+ const message = err instanceof Error ? err.message : "unknown";
1201
+ throw new TypeError(`Invalid Invoke PayloadPart: ${message}`);
1202
+ }
1014
1203
  } catch (err) {
1015
1204
  droppedChunks++;
1016
1205
  if (droppedChunks === 1) firstDroppedSample = `parse failed (${err instanceof Error ? err.message : "unknown"}): ${surrogateSafeSlice(frameStr, 200)}`;
@@ -1256,8 +1445,19 @@ function collapseGeminiInteractionsSSE(rawBody) {
1256
1445
  * Collapse a streaming response body into a non-streaming fixture response.
1257
1446
  * Returns null if the content type is not a known streaming format.
1258
1447
  * Falls back to OpenAI SSE parsing for unrecognized provider keys with text/event-stream.
1448
+ *
1449
+ * Public, with the 1.44.0 result (see {@link collapseOpenAISSE}). The recorder
1450
+ * uses {@link collapseStreamingResponseWithResponsesTools}.
1259
1451
  */
1260
1452
  function collapseStreamingResponse(contentType, providerKey, body, logger) {
1453
+ const collapsed = collapseStreamingResponseWithResponsesTools(contentType, providerKey, body, logger);
1454
+ return collapsed && withoutResponsesToolFields(collapsed);
1455
+ }
1456
+ /**
1457
+ * @internal {@link collapseStreamingResponse} keeping an OpenAI Responses
1458
+ * `namespace` and custom tool calls.
1459
+ */
1460
+ function collapseStreamingResponseWithResponsesTools(contentType, providerKey, body, logger) {
1261
1461
  const ct = contentType.toLowerCase();
1262
1462
  if (ct.includes("application/vnd.amazon.eventstream")) return collapseBedrockEventStream(typeof body === "string" ? Buffer.from(body, "binary") : body);
1263
1463
  if (ct.includes("application/x-ndjson")) return collapseOllamaNDJSON(typeof body === "string" ? body : body.toString("utf8"));
@@ -1267,7 +1467,7 @@ function collapseStreamingResponse(contentType, providerKey, body, logger) {
1267
1467
  case "openai":
1268
1468
  case "azure":
1269
1469
  case "openrouter":
1270
- case "byteplus": return collapseOpenAISSE(str);
1470
+ case "byteplus": return collapseOpenAISSEWithResponsesTools(str);
1271
1471
  case "anthropic": return collapseAnthropicSSE(str);
1272
1472
  case "gemini":
1273
1473
  case "vertexai": return collapseGeminiSSE(str);
@@ -1276,7 +1476,7 @@ function collapseStreamingResponse(contentType, providerKey, body, logger) {
1276
1476
  case "bedrock": return collapseAnthropicSSE(str);
1277
1477
  default:
1278
1478
  logger?.warn(`[stream-collapse] unknown SSE provider "${providerKey}", falling back to OpenAI SSE format`);
1279
- return collapseOpenAISSE(str);
1479
+ return collapseOpenAISSEWithResponsesTools(str);
1280
1480
  }
1281
1481
  }
1282
1482
  return null;
@@ -1293,5 +1493,7 @@ exports.collapseGeminiSSE = collapseGeminiSSE;
1293
1493
  exports.collapseOllamaNDJSON = collapseOllamaNDJSON;
1294
1494
  exports.collapseOpenAISSE = collapseOpenAISSE;
1295
1495
  exports.collapseStreamingResponse = collapseStreamingResponse;
1496
+ exports.collapseStreamingResponseWithResponsesTools = collapseStreamingResponseWithResponsesTools;
1296
1497
  exports.setCollapseStringLimitForTests = setCollapseStringLimitForTests;
1498
+ exports.withoutResponsesToolFields = withoutResponsesToolFields;
1297
1499
  //# sourceMappingURL=stream-collapse.cjs.map