@copilotkit/aimock 1.43.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 (396) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +46 -0
  4. package/README.md +14 -2
  5. package/dist/agui-handler.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 +344 -43
  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 +345 -44
  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 +9 -5
  25. package/dist/chaos.cjs.map +1 -1
  26. package/dist/chaos.d.cts.map +1 -1
  27. package/dist/chaos.d.ts.map +1 -1
  28. package/dist/chaos.js +10 -7
  29. package/dist/chaos.js.map +1 -1
  30. package/dist/cli.cjs +238 -9
  31. package/dist/cli.cjs.map +1 -1
  32. package/dist/cli.js +242 -13
  33. package/dist/cli.js.map +1 -1
  34. package/dist/cohere.cjs +159 -72
  35. package/dist/cohere.cjs.map +1 -1
  36. package/dist/cohere.d.cts.map +1 -1
  37. package/dist/cohere.d.ts.map +1 -1
  38. package/dist/cohere.js +160 -73
  39. package/dist/cohere.js.map +1 -1
  40. package/dist/config-loader.cjs +63 -5
  41. package/dist/config-loader.cjs.map +1 -1
  42. package/dist/config-loader.d.cts +37 -4
  43. package/dist/config-loader.d.cts.map +1 -1
  44. package/dist/config-loader.d.ts +37 -4
  45. package/dist/config-loader.d.ts.map +1 -1
  46. package/dist/config-loader.js +63 -5
  47. package/dist/config-loader.js.map +1 -1
  48. package/dist/constants.cjs +8 -0
  49. package/dist/constants.cjs.map +1 -1
  50. package/dist/constants.d.cts +6 -2
  51. package/dist/constants.d.ts +6 -2
  52. package/dist/constants.js +8 -1
  53. package/dist/constants.js.map +1 -1
  54. package/dist/echo-text.cjs +65 -0
  55. package/dist/echo-text.cjs.map +1 -0
  56. package/dist/echo-text.d.cts +22 -0
  57. package/dist/echo-text.d.cts.map +1 -0
  58. package/dist/echo-text.d.ts +22 -0
  59. package/dist/echo-text.d.ts.map +1 -0
  60. package/dist/echo-text.js +65 -0
  61. package/dist/echo-text.js.map +1 -0
  62. package/dist/embeddings.cjs +18 -1
  63. package/dist/embeddings.cjs.map +1 -1
  64. package/dist/embeddings.d.cts +1 -1
  65. package/dist/embeddings.d.cts.map +1 -1
  66. package/dist/embeddings.d.ts +1 -1
  67. package/dist/embeddings.d.ts.map +1 -1
  68. package/dist/embeddings.js +18 -1
  69. package/dist/embeddings.js.map +1 -1
  70. package/dist/fakes-plugin.cjs +131 -0
  71. package/dist/fakes-plugin.cjs.map +1 -0
  72. package/dist/fakes-plugin.d.cts +23 -0
  73. package/dist/fakes-plugin.d.cts.map +1 -0
  74. package/dist/fakes-plugin.d.ts +23 -0
  75. package/dist/fakes-plugin.d.ts.map +1 -0
  76. package/dist/fakes-plugin.js +127 -0
  77. package/dist/fakes-plugin.js.map +1 -0
  78. package/dist/files.cjs +9 -11
  79. package/dist/files.cjs.map +1 -1
  80. package/dist/files.d.cts.map +1 -1
  81. package/dist/files.d.ts.map +1 -1
  82. package/dist/files.js +10 -13
  83. package/dist/files.js.map +1 -1
  84. package/dist/fine-tuning.cjs +1 -19
  85. package/dist/fine-tuning.cjs.map +1 -1
  86. package/dist/fine-tuning.d.cts.map +1 -1
  87. package/dist/fine-tuning.d.ts.map +1 -1
  88. package/dist/fine-tuning.js +2 -20
  89. package/dist/fine-tuning.js.map +1 -1
  90. package/dist/fixture-loader-services.cjs +116 -0
  91. package/dist/fixture-loader-services.cjs.map +1 -0
  92. package/dist/fixture-loader-services.d.cts +48 -0
  93. package/dist/fixture-loader-services.d.cts.map +1 -0
  94. package/dist/fixture-loader-services.d.ts +48 -0
  95. package/dist/fixture-loader-services.d.ts.map +1 -0
  96. package/dist/fixture-loader-services.js +114 -0
  97. package/dist/fixture-loader-services.js.map +1 -0
  98. package/dist/fixture-loader.cjs +552 -29
  99. package/dist/fixture-loader.cjs.map +1 -1
  100. package/dist/fixture-loader.d.cts +140 -2
  101. package/dist/fixture-loader.d.cts.map +1 -1
  102. package/dist/fixture-loader.d.ts +140 -2
  103. package/dist/fixture-loader.d.ts.map +1 -1
  104. package/dist/fixture-loader.js +542 -31
  105. package/dist/fixture-loader.js.map +1 -1
  106. package/dist/gemini-embeddings.cjs +42 -2
  107. package/dist/gemini-embeddings.cjs.map +1 -1
  108. package/dist/gemini-embeddings.js +43 -3
  109. package/dist/gemini-embeddings.js.map +1 -1
  110. package/dist/gemini-interactions.cjs +288 -52
  111. package/dist/gemini-interactions.cjs.map +1 -1
  112. package/dist/gemini-interactions.d.cts.map +1 -1
  113. package/dist/gemini-interactions.d.ts.map +1 -1
  114. package/dist/gemini-interactions.js +289 -53
  115. package/dist/gemini-interactions.js.map +1 -1
  116. package/dist/gemini.cjs +234 -38
  117. package/dist/gemini.cjs.map +1 -1
  118. package/dist/gemini.d.cts.map +1 -1
  119. package/dist/gemini.d.ts.map +1 -1
  120. package/dist/gemini.js +235 -39
  121. package/dist/gemini.js.map +1 -1
  122. package/dist/helpers.cjs +1157 -12
  123. package/dist/helpers.cjs.map +1 -1
  124. package/dist/helpers.d.cts +85 -4
  125. package/dist/helpers.d.cts.map +1 -1
  126. package/dist/helpers.d.ts +85 -4
  127. package/dist/helpers.d.ts.map +1 -1
  128. package/dist/helpers.js +1113 -14
  129. package/dist/helpers.js.map +1 -1
  130. package/dist/images.cjs +3 -2
  131. package/dist/images.cjs.map +1 -1
  132. package/dist/images.js +3 -2
  133. package/dist/images.js.map +1 -1
  134. package/dist/index.cjs +39 -1
  135. package/dist/index.d.cts +11 -4
  136. package/dist/index.d.ts +11 -4
  137. package/dist/index.js +11 -4
  138. package/dist/jest.cjs +43 -14
  139. package/dist/jest.cjs.map +1 -1
  140. package/dist/jest.d.cts +47 -5
  141. package/dist/jest.d.cts.map +1 -1
  142. package/dist/jest.d.ts +47 -5
  143. package/dist/jest.d.ts.map +1 -1
  144. package/dist/jest.js +45 -16
  145. package/dist/jest.js.map +1 -1
  146. package/dist/journal.cjs +155 -13
  147. package/dist/journal.cjs.map +1 -1
  148. package/dist/journal.d.cts +54 -4
  149. package/dist/journal.d.cts.map +1 -1
  150. package/dist/journal.d.ts +54 -4
  151. package/dist/journal.d.ts.map +1 -1
  152. package/dist/journal.js +155 -13
  153. package/dist/journal.js.map +1 -1
  154. package/dist/live-sanitize.cjs +4 -32
  155. package/dist/live-sanitize.cjs.map +1 -1
  156. package/dist/live-sanitize.js +4 -32
  157. package/dist/live-sanitize.js.map +1 -1
  158. package/dist/llmock.cjs +204 -39
  159. package/dist/llmock.cjs.map +1 -1
  160. package/dist/llmock.d.cts +51 -1
  161. package/dist/llmock.d.cts.map +1 -1
  162. package/dist/llmock.d.ts +51 -1
  163. package/dist/llmock.d.ts.map +1 -1
  164. package/dist/llmock.js +206 -41
  165. package/dist/llmock.js.map +1 -1
  166. package/dist/mcp-fakes-mount.cjs +217 -0
  167. package/dist/mcp-fakes-mount.cjs.map +1 -0
  168. package/dist/mcp-fakes-mount.js +211 -0
  169. package/dist/mcp-fakes-mount.js.map +1 -0
  170. package/dist/mcp-fakes-report.cjs +111 -0
  171. package/dist/mcp-fakes-report.cjs.map +1 -0
  172. package/dist/mcp-fakes-report.d.cts +40 -0
  173. package/dist/mcp-fakes-report.d.cts.map +1 -0
  174. package/dist/mcp-fakes-report.d.ts +40 -0
  175. package/dist/mcp-fakes-report.d.ts.map +1 -0
  176. package/dist/mcp-fakes-report.js +107 -0
  177. package/dist/mcp-fakes-report.js.map +1 -0
  178. package/dist/mcp-fakes.cjs +1942 -0
  179. package/dist/mcp-fakes.cjs.map +1 -0
  180. package/dist/mcp-fakes.d.cts +504 -0
  181. package/dist/mcp-fakes.d.cts.map +1 -0
  182. package/dist/mcp-fakes.d.ts +504 -0
  183. package/dist/mcp-fakes.d.ts.map +1 -0
  184. package/dist/mcp-fakes.js +1937 -0
  185. package/dist/mcp-fakes.js.map +1 -0
  186. package/dist/mcp-handler.cjs +534 -27
  187. package/dist/mcp-handler.cjs.map +1 -1
  188. package/dist/mcp-handler.d.cts +49 -0
  189. package/dist/mcp-handler.d.cts.map +1 -0
  190. package/dist/mcp-handler.d.ts +49 -0
  191. package/dist/mcp-handler.d.ts.map +1 -0
  192. package/dist/mcp-handler.js +530 -28
  193. package/dist/mcp-handler.js.map +1 -1
  194. package/dist/mcp-mock.cjs +326 -47
  195. package/dist/mcp-mock.cjs.map +1 -1
  196. package/dist/mcp-mock.d.cts +97 -1
  197. package/dist/mcp-mock.d.cts.map +1 -1
  198. package/dist/mcp-mock.d.ts +97 -1
  199. package/dist/mcp-mock.d.ts.map +1 -1
  200. package/dist/mcp-mock.js +327 -48
  201. package/dist/mcp-mock.js.map +1 -1
  202. package/dist/mcp-recorder.cjs +1224 -0
  203. package/dist/mcp-recorder.cjs.map +1 -0
  204. package/dist/mcp-recorder.d.cts +108 -0
  205. package/dist/mcp-recorder.d.cts.map +1 -0
  206. package/dist/mcp-recorder.d.ts +108 -0
  207. package/dist/mcp-recorder.d.ts.map +1 -0
  208. package/dist/mcp-recorder.js +1215 -0
  209. package/dist/mcp-recorder.js.map +1 -0
  210. package/dist/mcp-stub.cjs +5 -1
  211. package/dist/mcp-stub.d.cts +3 -1
  212. package/dist/mcp-stub.d.ts +3 -1
  213. package/dist/mcp-stub.js +3 -1
  214. package/dist/mcp-types.d.cts +6 -0
  215. package/dist/mcp-types.d.ts +6 -0
  216. package/dist/message-text.cjs +192 -0
  217. package/dist/message-text.cjs.map +1 -0
  218. package/dist/message-text.d.cts +31 -0
  219. package/dist/message-text.d.cts.map +1 -0
  220. package/dist/message-text.d.ts +31 -0
  221. package/dist/message-text.d.ts.map +1 -0
  222. package/dist/message-text.js +184 -0
  223. package/dist/message-text.js.map +1 -0
  224. package/dist/messages.cjs +400 -56
  225. package/dist/messages.cjs.map +1 -1
  226. package/dist/messages.d.cts.map +1 -1
  227. package/dist/messages.d.ts.map +1 -1
  228. package/dist/messages.js +401 -58
  229. package/dist/messages.js.map +1 -1
  230. package/dist/metrics.cjs +46 -66
  231. package/dist/metrics.cjs.map +1 -1
  232. package/dist/metrics.d.cts +14 -6
  233. package/dist/metrics.d.cts.map +1 -1
  234. package/dist/metrics.d.ts +14 -6
  235. package/dist/metrics.d.ts.map +1 -1
  236. package/dist/metrics.js +32 -40
  237. package/dist/metrics.js.map +1 -1
  238. package/dist/misbehavior.cjs +1523 -0
  239. package/dist/misbehavior.cjs.map +1 -0
  240. package/dist/misbehavior.d.cts +43 -0
  241. package/dist/misbehavior.d.cts.map +1 -0
  242. package/dist/misbehavior.d.ts +43 -0
  243. package/dist/misbehavior.d.ts.map +1 -0
  244. package/dist/misbehavior.js +1511 -0
  245. package/dist/misbehavior.js.map +1 -0
  246. package/dist/ollama.cjs +315 -113
  247. package/dist/ollama.cjs.map +1 -1
  248. package/dist/ollama.d.cts.map +1 -1
  249. package/dist/ollama.d.ts.map +1 -1
  250. package/dist/ollama.js +316 -114
  251. package/dist/ollama.js.map +1 -1
  252. package/dist/openapi.cjs +3405 -0
  253. package/dist/openapi.cjs.map +1 -0
  254. package/dist/openapi.d.cts +30 -0
  255. package/dist/openapi.d.cts.map +1 -0
  256. package/dist/openapi.d.ts +30 -0
  257. package/dist/openapi.d.ts.map +1 -0
  258. package/dist/openapi.js +3404 -0
  259. package/dist/openapi.js.map +1 -0
  260. package/dist/openrouter-video.cjs +4 -4
  261. package/dist/openrouter-video.cjs.map +1 -1
  262. package/dist/openrouter-video.d.cts.map +1 -1
  263. package/dist/openrouter-video.d.ts.map +1 -1
  264. package/dist/openrouter-video.js +4 -4
  265. package/dist/openrouter-video.js.map +1 -1
  266. package/dist/record-sanitize.cjs +231 -0
  267. package/dist/record-sanitize.cjs.map +1 -0
  268. package/dist/record-sanitize.js +224 -0
  269. package/dist/record-sanitize.js.map +1 -0
  270. package/dist/recorder.cjs +115 -6
  271. package/dist/recorder.cjs.map +1 -1
  272. package/dist/recorder.d.cts +2 -1
  273. package/dist/recorder.d.cts.map +1 -1
  274. package/dist/recorder.d.ts +2 -1
  275. package/dist/recorder.d.ts.map +1 -1
  276. package/dist/recorder.js +116 -8
  277. package/dist/recorder.js.map +1 -1
  278. package/dist/responses.cjs +701 -166
  279. package/dist/responses.cjs.map +1 -1
  280. package/dist/responses.d.cts +5 -13
  281. package/dist/responses.d.cts.map +1 -1
  282. package/dist/responses.d.ts +5 -13
  283. package/dist/responses.d.ts.map +1 -1
  284. package/dist/responses.js +699 -169
  285. package/dist/responses.js.map +1 -1
  286. package/dist/route-registry.cjs +951 -0
  287. package/dist/route-registry.cjs.map +1 -0
  288. package/dist/route-registry.d.cts +33 -0
  289. package/dist/route-registry.d.cts.map +1 -0
  290. package/dist/route-registry.d.ts +33 -0
  291. package/dist/route-registry.d.ts.map +1 -0
  292. package/dist/route-registry.js +866 -0
  293. package/dist/route-registry.js.map +1 -0
  294. package/dist/router.cjs +24 -2
  295. package/dist/router.cjs.map +1 -1
  296. package/dist/router.d.cts.map +1 -1
  297. package/dist/router.d.ts.map +1 -1
  298. package/dist/router.js +25 -4
  299. package/dist/router.js.map +1 -1
  300. package/dist/server.cjs +1159 -264
  301. package/dist/server.cjs.map +1 -1
  302. package/dist/server.d.cts +4 -1
  303. package/dist/server.d.cts.map +1 -1
  304. package/dist/server.d.ts +4 -1
  305. package/dist/server.d.ts.map +1 -1
  306. package/dist/server.js +1067 -172
  307. package/dist/server.js.map +1 -1
  308. package/dist/speech.cjs +4 -2
  309. package/dist/speech.cjs.map +1 -1
  310. package/dist/speech.js +4 -2
  311. package/dist/speech.js.map +1 -1
  312. package/dist/stream-collapse.cjs +236 -34
  313. package/dist/stream-collapse.cjs.map +1 -1
  314. package/dist/stream-collapse.d.cts +39 -4
  315. package/dist/stream-collapse.d.cts.map +1 -1
  316. package/dist/stream-collapse.d.ts +39 -4
  317. package/dist/stream-collapse.d.ts.map +1 -1
  318. package/dist/stream-collapse.js +235 -35
  319. package/dist/stream-collapse.js.map +1 -1
  320. package/dist/suite.cjs +1 -1
  321. package/dist/suite.js +1 -1
  322. package/dist/transcription.cjs +2 -2
  323. package/dist/transcription.cjs.map +1 -1
  324. package/dist/transcription.d.cts.map +1 -1
  325. package/dist/transcription.d.ts.map +1 -1
  326. package/dist/transcription.js +2 -2
  327. package/dist/transcription.js.map +1 -1
  328. package/dist/types.cjs +18 -0
  329. package/dist/types.cjs.map +1 -0
  330. package/dist/types.d.cts +516 -5
  331. package/dist/types.d.cts.map +1 -1
  332. package/dist/types.d.ts +516 -5
  333. package/dist/types.d.ts.map +1 -1
  334. package/dist/types.js +17 -0
  335. package/dist/types.js.map +1 -0
  336. package/dist/validate-cli.cjs +123 -33
  337. package/dist/validate-cli.cjs.map +1 -1
  338. package/dist/validate-cli.js +125 -35
  339. package/dist/validate-cli.js.map +1 -1
  340. package/dist/vector-stores.cjs +1180 -0
  341. package/dist/vector-stores.cjs.map +1 -0
  342. package/dist/vector-stores.d.cts +106 -0
  343. package/dist/vector-stores.d.cts.map +1 -0
  344. package/dist/vector-stores.d.ts +106 -0
  345. package/dist/vector-stores.d.ts.map +1 -0
  346. package/dist/vector-stores.js +1164 -0
  347. package/dist/vector-stores.js.map +1 -0
  348. package/dist/vector-types.d.cts.map +1 -1
  349. package/dist/version.cjs +45 -0
  350. package/dist/version.cjs.map +1 -0
  351. package/dist/version.js +44 -0
  352. package/dist/version.js.map +1 -0
  353. package/dist/video.cjs +19 -0
  354. package/dist/video.cjs.map +1 -1
  355. package/dist/video.d.cts.map +1 -1
  356. package/dist/video.d.ts.map +1 -1
  357. package/dist/video.js +19 -0
  358. package/dist/video.js.map +1 -1
  359. package/dist/vitest.cjs +77 -16
  360. package/dist/vitest.cjs.map +1 -1
  361. package/dist/vitest.d.cts +38 -5
  362. package/dist/vitest.d.cts.map +1 -1
  363. package/dist/vitest.d.ts +38 -5
  364. package/dist/vitest.d.ts.map +1 -1
  365. package/dist/vitest.js +78 -17
  366. package/dist/vitest.js.map +1 -1
  367. package/dist/watcher.cjs +6 -2
  368. package/dist/watcher.cjs.map +1 -1
  369. package/dist/watcher.js +6 -2
  370. package/dist/watcher.js.map +1 -1
  371. package/dist/ws-gemini-live.cjs +210 -101
  372. package/dist/ws-gemini-live.cjs.map +1 -1
  373. package/dist/ws-gemini-live.d.cts +9 -3
  374. package/dist/ws-gemini-live.d.cts.map +1 -1
  375. package/dist/ws-gemini-live.d.ts +9 -3
  376. package/dist/ws-gemini-live.d.ts.map +1 -1
  377. package/dist/ws-gemini-live.js +211 -102
  378. package/dist/ws-gemini-live.js.map +1 -1
  379. package/dist/ws-realtime.cjs +175 -62
  380. package/dist/ws-realtime.cjs.map +1 -1
  381. package/dist/ws-realtime.d.cts +8 -3
  382. package/dist/ws-realtime.d.cts.map +1 -1
  383. package/dist/ws-realtime.d.ts +8 -3
  384. package/dist/ws-realtime.d.ts.map +1 -1
  385. package/dist/ws-realtime.js +176 -63
  386. package/dist/ws-realtime.js.map +1 -1
  387. package/dist/ws-responses.cjs +121 -16
  388. package/dist/ws-responses.cjs.map +1 -1
  389. package/dist/ws-responses.d.cts +8 -12
  390. package/dist/ws-responses.d.cts.map +1 -1
  391. package/dist/ws-responses.d.ts +8 -12
  392. package/dist/ws-responses.d.ts.map +1 -1
  393. package/dist/ws-responses.js +123 -18
  394. package/dist/ws-responses.js.map +1 -1
  395. package/package.json +13 -2
  396. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1,10 +1,13 @@
1
+ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
1
2
  const require_model_utils = require('./model-utils.cjs');
2
3
  const require_helpers = require('./helpers.cjs');
3
4
  const require_sse_writer = require('./sse-writer.cjs');
4
5
  const require_chaos = require('./chaos.cjs');
6
+ const require_misbehavior = require('./misbehavior.cjs');
5
7
  const require_router = require('./router.cjs');
6
8
  const require_recorder = require('./recorder.cjs');
7
9
  const require_interruption = require('./interruption.cjs');
10
+ let node_crypto = require("node:crypto");
8
11
 
9
12
  //#region src/responses.ts
10
13
  function extractTextContent(content) {
@@ -12,7 +15,36 @@ function extractTextContent(content) {
12
15
  if (typeof content === "string") return content;
13
16
  return content.filter((p) => p.type === "input_text" || p.type === "output_text").map((p) => p.text ?? "").join("");
14
17
  }
15
- function responsesInputToMessages(req) {
18
+ /**
19
+ * A `custom_tool_call_output.output` is a string or a list of content parts
20
+ * (`input_text` / `input_image` / `input_file`). Flatten a list to its
21
+ * concatenated `input_text` text so text matchers such as
22
+ * `toolResultContains` see it.
23
+ *
24
+ * The value comes straight from the request body, so it is read as `unknown`.
25
+ * Like `function_call_output`, a malformed output never fails the request:
26
+ * any other value (null, an object, a number) yields empty text, and list
27
+ * entries that are not `input_text` parts with string text are skipped.
28
+ */
29
+ function customToolOutputText(output) {
30
+ if (typeof output === "string") return output;
31
+ if (!Array.isArray(output)) return "";
32
+ return output.map((p) => {
33
+ if (p === null || typeof p !== "object") return "";
34
+ const part = p;
35
+ return part.type === "input_text" && typeof part.text === "string" ? part.text : "";
36
+ }).join("");
37
+ }
38
+ /**
39
+ * Convert Responses input items into chat messages for fixture matching. The
40
+ * default is the conversion of earlier releases: `custom_tool_call` and
41
+ * `custom_tool_call_output` items are skipped, and history namespaces are not
42
+ * kept. With `extended`, a custom tool call becomes an assistant message with
43
+ * `custom_tool_calls` (so turn counting sees it), its output becomes a `tool`
44
+ * message (so `hasToolResult` and `toolCallId` see it), and a `function_call`
45
+ * keeps its `namespace`.
46
+ */
47
+ function responsesInputToMessages(req, extended = false) {
16
48
  const messages = [];
17
49
  const itemReferencePlaceholders = /* @__PURE__ */ new WeakSet();
18
50
  if (req.instructions) messages.push({
@@ -26,6 +58,25 @@ function responsesInputToMessages(req) {
26
58
  });
27
59
  return messages;
28
60
  }
61
+ /** A synthesized call for an output item that has no matching call. */
62
+ const attachSynthesizedCall = (target, item) => {
63
+ const id = item.call_id ?? require_helpers.generateToolCallId();
64
+ if (item.type === "custom_tool_call_output") (target.custom_tool_calls ??= []).push({
65
+ id,
66
+ type: "custom",
67
+ name: "",
68
+ input: ""
69
+ });
70
+ else (target.tool_calls ??= []).push({
71
+ id,
72
+ type: "function",
73
+ function: {
74
+ name: "",
75
+ arguments: ""
76
+ }
77
+ });
78
+ };
79
+ const hasCalls = (m) => m.tool_calls !== void 0 || m.custom_tool_calls !== void 0;
29
80
  for (const item of req.input) if (item.role === "system" || item.role === "developer") messages.push({
30
81
  role: "system",
31
82
  content: extractTextContent(item.content)
@@ -44,61 +95,55 @@ function responsesInputToMessages(req) {
44
95
  tool_calls: [{
45
96
  id: item.call_id ?? require_helpers.generateToolCallId(),
46
97
  type: "function",
98
+ ...extended && typeof item.namespace === "string" ? { namespace: item.namespace } : {},
47
99
  function: {
48
100
  name: item.name ?? "",
49
101
  arguments: item.arguments ?? ""
50
102
  }
51
103
  }]
52
104
  });
53
- else if (item.type === "function_call_output") {
54
- if (!messages.some((m) => m.role === "assistant" && m.tool_calls?.some((tc) => tc.id === item.call_id))) {
105
+ else if (extended && item.type === "custom_tool_call") messages.push({
106
+ role: "assistant",
107
+ content: null,
108
+ custom_tool_calls: [{
109
+ id: item.call_id ?? require_helpers.generateToolCallId(),
110
+ type: "custom",
111
+ name: item.name ?? "",
112
+ input: typeof item.input === "string" ? item.input : "",
113
+ ...typeof item.namespace === "string" ? { namespace: item.namespace } : {}
114
+ }]
115
+ });
116
+ else if (item.type === "function_call_output" || extended && item.type === "custom_tool_call_output") {
117
+ if (!messages.some((m) => m.role === "assistant" && (m.tool_calls?.some((tc) => tc.id === item.call_id) || m.custom_tool_calls?.some((tc) => tc.id === item.call_id)))) {
55
118
  const lastMsg = messages[messages.length - 1];
56
- if (lastMsg && lastMsg.role === "assistant" && itemReferencePlaceholders.has(lastMsg) && !lastMsg.tool_calls) {
119
+ if (lastMsg && lastMsg.role === "assistant" && itemReferencePlaceholders.has(lastMsg) && !hasCalls(lastMsg)) {
57
120
  lastMsg.content = null;
58
- lastMsg.tool_calls = [{
59
- id: item.call_id ?? require_helpers.generateToolCallId(),
60
- type: "function",
61
- function: {
62
- name: "",
63
- arguments: ""
64
- }
65
- }];
121
+ attachSynthesizedCall(lastMsg, item);
66
122
  itemReferencePlaceholders.delete(lastMsg);
67
123
  } else {
68
124
  let appended = false;
69
125
  for (let k = messages.length - 1; k >= 0; k--) {
70
126
  const m = messages[k];
71
- if (m.role === "assistant" && m.tool_calls) {
72
- m.tool_calls.push({
73
- id: item.call_id ?? require_helpers.generateToolCallId(),
74
- type: "function",
75
- function: {
76
- name: "",
77
- arguments: ""
78
- }
79
- });
127
+ if (m.role === "assistant" && hasCalls(m)) {
128
+ attachSynthesizedCall(m, item);
80
129
  appended = true;
81
130
  break;
82
131
  }
83
132
  if (m.role === "user") break;
84
133
  }
85
- if (!appended) messages.push({
86
- role: "assistant",
87
- content: null,
88
- tool_calls: [{
89
- id: item.call_id ?? require_helpers.generateToolCallId(),
90
- type: "function",
91
- function: {
92
- name: "",
93
- arguments: ""
94
- }
95
- }]
96
- });
134
+ if (!appended) {
135
+ const synthesized = {
136
+ role: "assistant",
137
+ content: null
138
+ };
139
+ attachSynthesizedCall(synthesized, item);
140
+ messages.push(synthesized);
141
+ }
97
142
  }
98
143
  }
99
144
  messages.push({
100
145
  role: "tool",
101
- content: item.output ?? "",
146
+ content: item.type === "custom_tool_call_output" ? customToolOutputText(item.output) : item.output ?? "",
102
147
  tool_call_id: item.call_id
103
148
  });
104
149
  } else if (item.type === "item_reference") {
@@ -111,6 +156,7 @@ function responsesInputToMessages(req) {
111
156
  }
112
157
  return messages;
113
158
  }
159
+ /** The request tools of earlier releases: top-level `function` tools only. */
114
160
  function responsesToolsToCompletionsTools(tools) {
115
161
  if (!tools || tools.length === 0) return void 0;
116
162
  return tools.filter((t) => t.type === "function").map((t) => ({
@@ -122,17 +168,146 @@ function responsesToolsToCompletionsTools(tools) {
122
168
  }
123
169
  }));
124
170
  }
125
- function responsesToCompletionRequest(req) {
171
+ /** One Responses `function` or `custom` tool in aimock's normalized form. */
172
+ function normalizeResponsesTool(tool, namespace) {
173
+ if (tool === null || typeof tool !== "object") return void 0;
174
+ const t = tool;
175
+ const ns = namespace !== void 0 ? { namespace } : {};
176
+ if (t.type === "function") {
177
+ const fn = t;
178
+ return {
179
+ type: "function",
180
+ ...ns,
181
+ function: {
182
+ name: fn.name,
183
+ description: fn.description,
184
+ parameters: fn.parameters
185
+ }
186
+ };
187
+ }
188
+ if (t.type === "custom") {
189
+ const custom = t;
190
+ return {
191
+ type: "custom",
192
+ name: custom.name,
193
+ ...custom.description !== void 0 ? { description: custom.description } : {},
194
+ ...ns,
195
+ ...custom.format !== void 0 ? { format: custom.format } : {}
196
+ };
197
+ }
198
+ }
199
+ /**
200
+ * Input items whose `tools` add to the request's tools:
201
+ * `additional_tools` (Codex responses-lite) and `tool_search_output` (tools
202
+ * loaded by tool search, e.g. Codex's deferred MCP namespaces). Both carry the
203
+ * same function / custom / namespace tool shapes as `req.tools`.
204
+ */
205
+ function isToolCarryingItemType(type) {
206
+ return type === "additional_tools" || type === "tool_search_output";
207
+ }
208
+ /**
209
+ * Why a `namespace` tool cannot be flattened, or undefined when it can: its
210
+ * name is not a non-empty string (OpenAI's `NamespaceToolParam` requires
211
+ * `name` with `minLength: 1`), or its `tools` is not an array.
212
+ */
213
+ function namespaceToolProblem(tool) {
214
+ if (typeof tool.name !== "string" || tool.name === "") return "name is not a non-empty string";
215
+ if (!Array.isArray(tool.tools)) return "tools is not an array";
216
+ }
217
+ /**
218
+ * Flatten every Responses tool a request offers, for extended matching and for
219
+ * `toolNamespace`. Sources, in order: `req.tools`, then the `tools` of every
220
+ * `additional_tools` or `tool_search_output` input item, in input order.
221
+ * `namespace` tools contribute one entry per inner function/custom tool, each
222
+ * carrying the namespace; other tool types are ignored.
223
+ *
224
+ * Malformed items never fail the request (earlier releases ignored them): a
225
+ * `namespace` tool without a non-empty string name or with a non-array
226
+ * `tools`, a `null` entry, and a tool-carrying item whose `tools` is not an
227
+ * array are dropped, with a warning when `warn` is given.
228
+ */
229
+ function flattenResponsesTools(req, warn) {
230
+ const tools = [];
231
+ const customTools = [];
232
+ const add = (normalized) => {
233
+ if (!normalized) return;
234
+ if (normalized.type === "custom") customTools.push(normalized);
235
+ else tools.push(normalized);
236
+ };
237
+ const sources = [];
238
+ if (Array.isArray(req.tools)) req.tools.forEach((tool, i) => sources.push({
239
+ tool,
240
+ path: `tools[${i}]`
241
+ }));
242
+ if (Array.isArray(req.input)) req.input.forEach((item, i) => {
243
+ if (!isToolCarryingItemType(item?.type) || item?.tools === void 0) return;
244
+ if (!Array.isArray(item.tools)) {
245
+ warn?.(`Ignoring input[${i}].tools: not an array`);
246
+ return;
247
+ }
248
+ item.tools.forEach((tool, j) => sources.push({
249
+ tool,
250
+ path: `input[${i}].tools[${j}]`
251
+ }));
252
+ });
253
+ for (const { tool, path } of sources) {
254
+ const t = tool;
255
+ if (t === null) {
256
+ warn?.(`Ignoring ${path}: null tool`);
257
+ continue;
258
+ }
259
+ if (t?.type === "namespace") {
260
+ const problem = namespaceToolProblem(t);
261
+ if (problem) {
262
+ warn?.(`Ignoring namespace tool ${path}: ${problem}`);
263
+ continue;
264
+ }
265
+ t.tools.forEach((inner, k) => {
266
+ if (inner === null) warn?.(`Ignoring ${path}.tools[${k}]: null tool`);
267
+ else add(normalizeResponsesTool(inner, t.name));
268
+ });
269
+ continue;
270
+ }
271
+ add(normalizeResponsesTool(tool));
272
+ }
126
273
  return {
274
+ tools,
275
+ customTools,
276
+ sourceCount: sources.length
277
+ };
278
+ }
279
+ function responsesToCompletionRequest(req, options = {}) {
280
+ const extended = options.extended === true;
281
+ const all = flattenResponsesTools(req, extended && options.logger ? (message) => options.logger?.warn(`Responses request: ${message}`) : void 0);
282
+ const completionReq = {
127
283
  model: req.model,
128
- messages: responsesInputToMessages(req),
284
+ messages: responsesInputToMessages(req, extended),
129
285
  stream: req.stream,
130
286
  temperature: req.temperature,
131
287
  max_tokens: req.max_output_tokens,
132
- tools: responsesToolsToCompletionsTools(req.tools),
288
+ tools: extended ? all.sourceCount > 0 ? all.tools : void 0 : responsesToolsToCompletionsTools(req.tools),
289
+ ...extended && all.customTools.length > 0 ? { customTools: all.customTools } : {},
133
290
  tool_choice: req.tool_choice,
134
291
  response_format: req.response_format
135
292
  };
293
+ require_router.setResponsesOfferedTools(completionReq, {
294
+ tools: all.tools,
295
+ customTools: all.customTools
296
+ });
297
+ return completionReq;
298
+ }
299
+ /**
300
+ * The HTTP request check of earlier releases for `tools`: keep the
301
+ * converter's empty/falsy bypass, and reject only a collection the legacy
302
+ * converter would throw on (not an array, or a `null` entry). Malformed
303
+ * nested tools (inside a `namespace` tool or a tool-carrying input item) are
304
+ * dropped by the conversion instead.
305
+ */
306
+ function validateResponsesTools(tools) {
307
+ if (tools && tools.length !== 0) {
308
+ if (!Array.isArray(tools)) return "tools must be an array";
309
+ if (tools.some((tool) => tool === null)) return "tools entries must not be null";
310
+ }
136
311
  }
137
312
  function responsesStatus(finishReason, defaultStatus) {
138
313
  if (!finishReason) return defaultStatus;
@@ -180,56 +355,105 @@ function buildTextStreamEvents(content, model, chunkSize, reasoning, webSearches
180
355
  });
181
356
  return events;
182
357
  }
358
+ function requireFixtureToolArguments(value) {
359
+ if (typeof value !== "string") throw new Error("Invalid fixture tool call: \"arguments\" must be a string after normalization");
360
+ return value;
361
+ }
362
+ function requireFixtureToolInput(value) {
363
+ if (typeof value !== "string") throw new Error("Invalid fixture tool call: \"input\" must be a string for a custom tool call");
364
+ return value;
365
+ }
366
+ function isCustomEmittable(call) {
367
+ if (call === null || typeof call !== "object") return false;
368
+ return call.type === "custom" || call.type === "customToolCall";
369
+ }
370
+ /**
371
+ * A Responses `function_call` item. `namespace` is added only when the fixture
372
+ * sets it, so a call without one keeps the keys and key order it had before
373
+ * namespaces existed (existing fixtures stay byte-identical on the wire).
374
+ */
375
+ function functionCallItem(call, fcId, callId, args, status) {
376
+ return {
377
+ type: "function_call",
378
+ id: fcId,
379
+ call_id: callId,
380
+ ...call.namespace !== void 0 ? { namespace: call.namespace } : {},
381
+ name: call.name,
382
+ arguments: args,
383
+ status
384
+ };
385
+ }
386
+ /**
387
+ * `ctc_…` item id, the prefix the OpenAI guide and Codex's item-id map use for
388
+ * custom tool calls. The underscore separator is deliberate: it matches the
389
+ * real id format, so this does not use `generateId` (which would give
390
+ * `ctc-…`, like aimock's own `fc-…` ids).
391
+ */
392
+ function customToolCallItemId() {
393
+ return `ctc_${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
394
+ }
395
+ /** A Responses `custom_tool_call` item; `namespace` is added only when set. */
396
+ function customToolCallItem(call, ctcId, callId, input, status) {
397
+ return {
398
+ type: "custom_tool_call",
399
+ id: ctcId,
400
+ call_id: callId,
401
+ ...call.namespace !== void 0 ? { namespace: call.namespace } : {},
402
+ name: call.name,
403
+ input,
404
+ status
405
+ };
406
+ }
407
+ /**
408
+ * A `toolCalls` entry as earlier releases served it: a function call whose
409
+ * `type`, `input` and `namespace` are ignored. The exported builders take
410
+ * fixtures in that form; the handler passes `namespace` (extended mode) and
411
+ * custom calls to the internal builders instead.
412
+ */
413
+ function legacyFunctionCall(call) {
414
+ if (call === null || typeof call !== "object") return call;
415
+ const { name, arguments: args, id } = call;
416
+ return id !== void 0 ? {
417
+ name,
418
+ arguments: args,
419
+ id
420
+ } : {
421
+ name,
422
+ arguments: args
423
+ };
424
+ }
425
+ /**
426
+ * The exported builders' `toolCalls` as legacy function calls. It walks
427
+ * `toolCalls` by index up to `toolCalls.length`, as earlier releases did, so an
428
+ * untyped caller's non-array value gives the same calls: none for an object
429
+ * without `length`, and entries by index for a string or array-like.
430
+ */
431
+ function legacyFunctionCalls(toolCalls) {
432
+ const calls = [];
433
+ for (let idx = 0; idx < toolCalls.length; idx++) calls.push(legacyFunctionCall(toolCalls[idx]));
434
+ return calls;
435
+ }
436
+ /** Resolve exported-builder `blocks` as earlier releases did (no namespace emitted). */
437
+ function legacyOrderedBlocks(blocks) {
438
+ if (!blocks || blocks.length === 0) return void 0;
439
+ return require_helpers.resolveFixtureBlocks(blocks).map((block) => {
440
+ if (block.type === "text" || block.namespace === void 0) return block;
441
+ const copy = { ...block };
442
+ delete copy.namespace;
443
+ return copy;
444
+ });
445
+ }
183
446
  function buildToolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
447
+ return toolCallStreamEvents(legacyFunctionCalls(toolCalls), model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
448
+ }
449
+ function toolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
450
+ require_helpers.assertResponsesToolCalls(toolCalls);
184
451
  const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
185
452
  const fcOutputItems = [];
186
453
  for (let idx = 0; idx < toolCalls.length; idx++) {
187
- const tc = toolCalls[idx];
188
- const callId = tc.id || require_helpers.generateToolCallId();
189
- const fcId = require_helpers.generateId("fc");
190
- const outputIndex = nextOutputIndex + idx;
191
- events.push({
192
- type: "response.output_item.added",
193
- output_index: outputIndex,
194
- item: {
195
- type: "function_call",
196
- id: fcId,
197
- call_id: callId,
198
- name: tc.name,
199
- arguments: "",
200
- status: "in_progress"
201
- }
202
- });
203
- const args = tc.arguments;
204
- for (let i = 0; i < args.length; i += chunkSize) {
205
- const slice = args.slice(i, i + chunkSize);
206
- events.push({
207
- type: "response.function_call_arguments.delta",
208
- item_id: fcId,
209
- output_index: outputIndex,
210
- delta: slice
211
- });
212
- }
213
- events.push({
214
- type: "response.function_call_arguments.done",
215
- item_id: fcId,
216
- output_index: outputIndex,
217
- arguments: args
218
- });
219
- const doneItem = {
220
- type: "function_call",
221
- id: fcId,
222
- call_id: callId,
223
- name: tc.name,
224
- arguments: args,
225
- status: "completed"
226
- };
227
- events.push({
228
- type: "response.output_item.done",
229
- output_index: outputIndex,
230
- item: doneItem
231
- });
232
- fcOutputItems.push(doneItem);
454
+ const { events: callEvents, item } = buildToolCallOutputEvents(toolCalls[idx], chunkSize, nextOutputIndex + idx);
455
+ events.push(...callEvents);
456
+ fcOutputItems.push(item);
233
457
  }
234
458
  events.push({
235
459
  type: "response.completed",
@@ -460,7 +684,7 @@ function buildWebSearchStreamEvents(queries, startOutputIndex) {
460
684
  }
461
685
  return events;
462
686
  }
463
- function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
687
+ function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false, forceReasoning = false) {
464
688
  const respId = overrides?.id ?? responseId();
465
689
  const created = overrides?.created ?? Math.floor(Date.now() / 1e3);
466
690
  const effectiveModel = overrides?.model ?? model;
@@ -489,7 +713,7 @@ function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrid
489
713
  output: []
490
714
  }
491
715
  });
492
- if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) {
716
+ if (reasoning || forceReasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) {
493
717
  const reasoningEvents = buildReasoningStreamEvents(reasoning, chunkSize, emitEncryptedReasoning);
494
718
  events.push(...reasoningEvents);
495
719
  const doneEvent = reasoningEvents.find((e) => e.type === "response.output_item.done" && e.item?.type === "reasoning");
@@ -585,27 +809,20 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
585
809
  /**
586
810
  * Emit the output_item.added → arguments deltas → arguments.done →
587
811
  * output_item.done events for a single function_call at `outputIndex`,
588
- * returning the completed item for the final `output` array. Behavior is
589
- * identical to the inline per-tool-call loop in the legacy path; both the
590
- * legacy branch and the ordered-blocks branch share this so wire output stays
591
- * byte-identical for a given (tool, outputIndex).
812
+ * returning the completed item for the final `output` array. Every Responses
813
+ * streaming builder (tool-only, legacy content+toolCalls and ordered blocks)
814
+ * reaches this through {@link buildToolCallOutputEvents}, so a given
815
+ * (tool, outputIndex) has the same wire output on every path.
592
816
  */
593
817
  function buildFunctionCallOutputEvents(toolCall, chunkSize, outputIndex) {
594
818
  const callId = toolCall.id || require_helpers.generateToolCallId();
595
819
  const fcId = require_helpers.generateId("fc");
596
- const args = toolCall.arguments;
820
+ const args = requireFixtureToolArguments(toolCall.arguments);
597
821
  const events = [];
598
822
  events.push({
599
823
  type: "response.output_item.added",
600
824
  output_index: outputIndex,
601
- item: {
602
- type: "function_call",
603
- id: fcId,
604
- call_id: callId,
605
- name: toolCall.name,
606
- arguments: "",
607
- status: "in_progress"
608
- }
825
+ item: functionCallItem(toolCall, fcId, callId, "", "in_progress")
609
826
  });
610
827
  for (let i = 0; i < args.length; i += chunkSize) events.push({
611
828
  type: "response.function_call_arguments.delta",
@@ -619,24 +836,78 @@ function buildFunctionCallOutputEvents(toolCall, chunkSize, outputIndex) {
619
836
  output_index: outputIndex,
620
837
  arguments: args
621
838
  });
622
- const fcItem = {
623
- type: "function_call",
624
- id: fcId,
625
- call_id: callId,
626
- name: toolCall.name,
627
- arguments: args,
628
- status: "completed"
839
+ const item = functionCallItem(toolCall, fcId, callId, args, "completed");
840
+ events.push({
841
+ type: "response.output_item.done",
842
+ output_index: outputIndex,
843
+ item
844
+ });
845
+ return {
846
+ events,
847
+ item
629
848
  };
849
+ }
850
+ /**
851
+ * `text` cut into slices of at most `chunkSize` UTF-16 units, never between
852
+ * the two halves of a surrogate pair: a cut that would land inside a pair
853
+ * moves back before it, or, when that would leave the slice empty
854
+ * (`chunkSize` 1), forward past it. The slices rejoin to `text` exactly.
855
+ */
856
+ function surrogateSafeChunks(text, chunkSize) {
857
+ const chunks = [];
858
+ for (let i = 0; i < text.length;) {
859
+ let end = Math.min(i + chunkSize, text.length);
860
+ const high = text.charCodeAt(end - 1);
861
+ const low = text.charCodeAt(end);
862
+ if (high >= 55296 && high <= 56319 && low >= 56320 && low <= 57343) end = end - 1 > i ? end - 1 : end + 1;
863
+ chunks.push(text.slice(i, end));
864
+ i = end;
865
+ }
866
+ return chunks;
867
+ }
868
+ /**
869
+ * Emit output_item.added → custom_tool_call_input.delta×N →
870
+ * custom_tool_call_input.done → output_item.done for one `custom_tool_call` at
871
+ * `outputIndex`, returning the completed item. An empty `input`
872
+ * yields no delta event.
873
+ */
874
+ function buildCustomToolCallOutputEvents(call, chunkSize, outputIndex) {
875
+ const callId = call.id || require_helpers.generateToolCallId();
876
+ const ctcId = customToolCallItemId();
877
+ const input = requireFixtureToolInput(call.input);
878
+ const events = [];
879
+ events.push({
880
+ type: "response.output_item.added",
881
+ output_index: outputIndex,
882
+ item: customToolCallItem(call, ctcId, callId, "", "in_progress")
883
+ });
884
+ for (const delta of surrogateSafeChunks(input, chunkSize)) events.push({
885
+ type: "response.custom_tool_call_input.delta",
886
+ item_id: ctcId,
887
+ output_index: outputIndex,
888
+ delta
889
+ });
890
+ events.push({
891
+ type: "response.custom_tool_call_input.done",
892
+ item_id: ctcId,
893
+ output_index: outputIndex,
894
+ input
895
+ });
896
+ const item = customToolCallItem(call, ctcId, callId, input, "completed");
630
897
  events.push({
631
898
  type: "response.output_item.done",
632
899
  output_index: outputIndex,
633
- item: fcItem
900
+ item
634
901
  });
635
902
  return {
636
903
  events,
637
- fcItem
904
+ item
638
905
  };
639
906
  }
907
+ /** Streaming dispatcher: one function or custom tool call at `outputIndex`. */
908
+ function buildToolCallOutputEvents(call, chunkSize, outputIndex) {
909
+ return isCustomEmittable(call) ? buildCustomToolCallOutputEvents(call, chunkSize, outputIndex) : buildFunctionCallOutputEvents(call, chunkSize, outputIndex);
910
+ }
640
911
  function buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
641
912
  const output = [];
642
913
  if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(require_helpers.generateId("rs"), {
@@ -680,6 +951,7 @@ function buildTextResponse(content, model, reasoning, webSearches, overrides, em
680
951
  return buildResponseEnvelope(model, buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning), overrides);
681
952
  }
682
953
  function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
954
+ require_helpers.assertResponsesToolCalls(toolCalls);
683
955
  const output = [];
684
956
  if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(require_helpers.generateId("rs"), {
685
957
  summaryText: reasoning,
@@ -694,21 +966,22 @@ function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrid
694
966
  query
695
967
  }
696
968
  });
697
- for (const tc of toolCalls) output.push({
698
- type: "function_call",
699
- id: require_helpers.generateId("fc"),
700
- call_id: tc.id || require_helpers.generateToolCallId(),
701
- name: tc.name,
702
- arguments: tc.arguments,
703
- status: "completed"
704
- });
969
+ for (const tc of toolCalls) output.push(buildToolCallOutputItem(tc));
705
970
  return buildResponseEnvelope(model, output, overrides);
706
971
  }
707
972
  function buildContentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize, reasoning, webSearches, overrides, blocks, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
973
+ const ordered = legacyOrderedBlocks(blocks);
974
+ return contentWithToolCallsStreamEvents(content, ordered && ordered.length > 0 ? [] : legacyFunctionCalls(toolCalls), model, chunkSize, reasoning, webSearches, overrides, ordered, emitEncryptedReasoning, synthesizeSummarylessReasoning);
975
+ }
976
+ /**
977
+ * Internal content+tool-calls builder. `ordered` is already resolved (see
978
+ * {@link resolveServedBlockOutcome}); when non-empty it is streamed in array
979
+ * order, otherwise the legacy message-first path runs over `toolCalls`.
980
+ */
981
+ function contentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize, reasoning, webSearches, overrides, ordered, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
708
982
  const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
709
983
  const orderedOutputItems = [];
710
- if (blocks && blocks.length > 0) {
711
- const ordered = require_helpers.resolveFixtureBlocks(blocks);
984
+ if (ordered && ordered.length > 0) {
712
985
  let outputIndex = nextOutputIndex;
713
986
  for (const block of ordered) {
714
987
  if (block.type === "text") {
@@ -716,25 +989,21 @@ function buildContentWithToolCallsStreamEvents(content, toolCalls, model, chunkS
716
989
  events.push(...msgEvents);
717
990
  orderedOutputItems.push(msgItem);
718
991
  } else {
719
- const { events: fcEvents, fcItem } = buildFunctionCallOutputEvents({
720
- name: block.name,
721
- arguments: block.arguments,
722
- id: block.id
723
- }, chunkSize, outputIndex);
724
- events.push(...fcEvents);
725
- orderedOutputItems.push(fcItem);
992
+ const { events: callEvents, item } = buildToolCallOutputEvents(block, chunkSize, outputIndex);
993
+ events.push(...callEvents);
994
+ orderedOutputItems.push(item);
726
995
  }
727
996
  outputIndex += 1;
728
997
  }
729
998
  } else {
999
+ require_helpers.assertResponsesToolCalls(toolCalls);
730
1000
  const { events: msgEvents, msgItem } = buildMessageOutputEvents(content, chunkSize, nextOutputIndex);
731
1001
  events.push(...msgEvents);
732
1002
  orderedOutputItems.push(msgItem);
733
1003
  for (let idx = 0; idx < toolCalls.length; idx++) {
734
- const fcOutputIndex = nextOutputIndex + 1 + idx;
735
- const { events: fcEvents, fcItem } = buildFunctionCallOutputEvents(toolCalls[idx], chunkSize, fcOutputIndex);
736
- events.push(...fcEvents);
737
- orderedOutputItems.push(fcItem);
1004
+ const { events: callEvents, item } = buildToolCallOutputEvents(toolCalls[idx], chunkSize, nextOutputIndex + 1 + idx);
1005
+ events.push(...callEvents);
1006
+ orderedOutputItems.push(item);
738
1007
  }
739
1008
  }
740
1009
  events.push({
@@ -751,15 +1020,10 @@ function buildContentWithToolCallsStreamEvents(content, toolCalls, model, chunkS
751
1020
  });
752
1021
  return events;
753
1022
  }
754
- function buildFunctionCallOutputItem(tc) {
755
- return {
756
- type: "function_call",
757
- id: require_helpers.generateId("fc"),
758
- call_id: tc.id || require_helpers.generateToolCallId(),
759
- name: tc.name,
760
- arguments: tc.arguments,
761
- status: "completed"
762
- };
1023
+ /** Non-streaming dispatcher: the completed function or custom tool call item. */
1024
+ function buildToolCallOutputItem(tc) {
1025
+ if (isCustomEmittable(tc)) return customToolCallItem(tc, customToolCallItemId(), tc.id || require_helpers.generateToolCallId(), requireFixtureToolInput(tc.input), "completed");
1026
+ return functionCallItem(tc, require_helpers.generateId("fc"), tc.id || require_helpers.generateToolCallId(), requireFixtureToolArguments(tc.arguments), "completed");
763
1027
  }
764
1028
  function buildMessageOutputItem(content) {
765
1029
  return {
@@ -774,9 +1038,8 @@ function buildMessageOutputItem(content) {
774
1038
  }]
775
1039
  };
776
1040
  }
777
- function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning, webSearches, overrides, blocks, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
778
- if (blocks && blocks.length > 0) {
779
- const ordered = require_helpers.resolveFixtureBlocks(blocks);
1041
+ function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning, webSearches, overrides, ordered, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
1042
+ if (ordered && ordered.length > 0) {
780
1043
  const output = [];
781
1044
  if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(require_helpers.generateId("rs"), {
782
1045
  summaryText: reasoning,
@@ -792,15 +1055,12 @@ function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning,
792
1055
  }
793
1056
  });
794
1057
  for (const block of ordered) if (block.type === "text") output.push(buildMessageOutputItem(block.text));
795
- else output.push(buildFunctionCallOutputItem({
796
- name: block.name,
797
- arguments: block.arguments,
798
- id: block.id
799
- }));
1058
+ else output.push(buildToolCallOutputItem(block));
800
1059
  return buildResponseEnvelope(model, output, overrides);
801
1060
  }
1061
+ require_helpers.assertResponsesToolCalls(toolCalls);
802
1062
  const output = buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning);
803
- for (const tc of toolCalls) output.push(buildFunctionCallOutputItem(tc));
1063
+ for (const tc of toolCalls) output.push(buildToolCallOutputItem(tc));
804
1064
  return buildResponseEnvelope(model, output, overrides);
805
1065
  }
806
1066
  async function writeResponsesSSEStream(res, events, optionsOrLatency) {
@@ -869,7 +1129,41 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
869
1129
  } }));
870
1130
  return;
871
1131
  }
872
- const completionReq = responsesToCompletionRequest(responsesReq);
1132
+ let inputError;
1133
+ if (typeof responsesReq.input !== "string" && !Array.isArray(responsesReq.input)) inputError = "input must be a string or an array";
1134
+ else if (Array.isArray(responsesReq.input)) for (const [index, item] of responsesReq.input.entries()) {
1135
+ if (item === null) {
1136
+ inputError = `input[${index}] must not be null`;
1137
+ break;
1138
+ }
1139
+ if ((item.role === "system" || item.role === "developer" || item.role === "user" || item.role === "assistant") && item.content && typeof item.content !== "string" && !Array.isArray(item.content)) {
1140
+ inputError = `input[${index}].content must be a string or an array`;
1141
+ break;
1142
+ }
1143
+ }
1144
+ const validationError = inputError ?? validateResponsesTools(responsesReq.tools);
1145
+ if (validationError) {
1146
+ journal.add({
1147
+ method: req.method ?? "POST",
1148
+ path: req.url ?? "/v1/responses",
1149
+ headers: require_helpers.flattenHeaders(req.headers),
1150
+ body: responsesReq,
1151
+ response: {
1152
+ status: 400,
1153
+ fixture: null
1154
+ }
1155
+ });
1156
+ require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
1157
+ message: validationError,
1158
+ type: "invalid_request_error"
1159
+ } }));
1160
+ return;
1161
+ }
1162
+ const extendedTools = defaults.responsesTools === "extended";
1163
+ const completionReq = responsesToCompletionRequest(responsesReq, {
1164
+ extended: extendedTools,
1165
+ logger: defaults.logger
1166
+ });
873
1167
  completionReq._endpointType = "chat";
874
1168
  completionReq._context = require_helpers.getContext(req);
875
1169
  const emitEncryptedReasoning = requestWantsEncryptedReasoning(responsesReq);
@@ -945,27 +1239,116 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
945
1239
  } }));
946
1240
  return;
947
1241
  }
948
- const response = await require_helpers.resolveResponse(fixture, completionReq);
1242
+ const resolvedResponse = await require_helpers.resolveResponse(fixture, completionReq);
1243
+ const response = extendedTools ? resolvedResponse : require_helpers.withoutLegacyNamespaces(resolvedResponse);
1244
+ const misbehavior = require_misbehavior.planMisbehavior({
1245
+ wire: "openai-responses",
1246
+ fixture,
1247
+ response,
1248
+ request: completionReq,
1249
+ stream: responsesReq.stream === true,
1250
+ emitsToolCallIds: true,
1251
+ defaults,
1252
+ rawHeaders: req.headers,
1253
+ url: req.url
1254
+ });
1255
+ if (misbehavior.kind === "error") {
1256
+ require_misbehavior.recordMisbehaviorOutcome({
1257
+ entry: journal.add({
1258
+ method: req.method ?? "POST",
1259
+ path: req.url ?? "/v1/responses",
1260
+ headers: require_helpers.flattenHeaders(req.headers),
1261
+ body: completionReq,
1262
+ response: {
1263
+ status: misbehavior.status,
1264
+ fixture
1265
+ }
1266
+ }),
1267
+ summary: misbehavior.summary,
1268
+ defaults,
1269
+ testId
1270
+ });
1271
+ if (!misbehavior.summary?.evaluations.some((evaluation) => evaluation.outcome === "error")) defaults.logger.error(misbehavior.message);
1272
+ require_sse_writer.writeErrorResponse(res, misbehavior.status, JSON.stringify({ error: {
1273
+ message: misbehavior.message,
1274
+ type: "invalid_request_error",
1275
+ code: misbehavior.code
1276
+ } }));
1277
+ return;
1278
+ }
949
1279
  const latency = fixture.latency ?? defaults.latency;
950
1280
  const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
951
1281
  const fixtureTimings = fixture.recordedTimings;
952
1282
  const effectiveReplaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
953
- if (require_helpers.isErrorResponse(response)) {
954
- const status = response.status ?? 500;
955
- journal.add({
1283
+ if (misbehavior.kind === "applied") {
1284
+ const prepared = prepareResponsesMisbehavior(misbehavior);
1285
+ const output = buildResponsesMisbehavior(prepared, completionReq, chunkSize, emitEncryptedReasoning);
1286
+ const entry = journal.add({
956
1287
  method: req.method ?? "POST",
957
1288
  path: req.url ?? "/v1/responses",
958
1289
  headers: require_helpers.flattenHeaders(req.headers),
959
1290
  body: completionReq,
960
1291
  response: {
961
- status,
1292
+ status: 200,
962
1293
  fixture
963
1294
  }
964
1295
  });
1296
+ require_misbehavior.recordMisbehaviorOutcome({
1297
+ entry,
1298
+ summary: prepared.summary,
1299
+ defaults,
1300
+ testId
1301
+ });
1302
+ if (responsesReq.stream !== true) {
1303
+ res.writeHead(200, { "Content-Type": "application/json" });
1304
+ res.end(JSON.stringify(output.response));
1305
+ } else {
1306
+ const appliedTimings = prepared.duplicateId && fixtureTimings ? {
1307
+ ...fixtureTimings,
1308
+ interChunkDelaysMs: [...fixtureTimings.interChunkDelaysMs]
1309
+ } : fixtureTimings;
1310
+ if (prepared.duplicateId && appliedTimings) {
1311
+ const lastGap = appliedTimings.interChunkDelaysMs.at(-1) ?? 0;
1312
+ while (appliedTimings.interChunkDelaysMs.length < output.events.length - 1) appliedTimings.interChunkDelaysMs.push(lastGap);
1313
+ }
1314
+ const interruption = require_interruption.createInterruptionSignal(fixture);
1315
+ if (!await writeResponsesSSEStream(res, output.events, {
1316
+ latency,
1317
+ streamingProfile: fixture.streamingProfile,
1318
+ recordedTimings: appliedTimings,
1319
+ replaySpeed: effectiveReplaySpeed,
1320
+ signal: interruption?.signal,
1321
+ onChunkSent: interruption?.tick
1322
+ })) {
1323
+ if (!res.writableEnded) res.destroy();
1324
+ entry.response.interrupted = true;
1325
+ entry.response.interruptReason = interruption?.reason();
1326
+ }
1327
+ interruption?.cleanup();
1328
+ }
1329
+ return;
1330
+ }
1331
+ if (require_helpers.isErrorResponse(response)) {
1332
+ const status = response.status ?? 500;
1333
+ require_misbehavior.recordMisbehaviorOutcome({
1334
+ entry: journal.add({
1335
+ method: req.method ?? "POST",
1336
+ path: req.url ?? "/v1/responses",
1337
+ headers: require_helpers.flattenHeaders(req.headers),
1338
+ body: completionReq,
1339
+ response: {
1340
+ status,
1341
+ fixture
1342
+ }
1343
+ }),
1344
+ summary: misbehavior.summary,
1345
+ defaults,
1346
+ testId
1347
+ });
965
1348
  require_sse_writer.writeErrorResponse(res, status, require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
966
1349
  return;
967
1350
  }
968
- if (require_helpers.isContentWithToolCallsResponse(response)) {
1351
+ if (require_helpers.isCombinedFixtureResponse(response)) {
969
1352
  const overrides = require_helpers.extractOverrides(response);
970
1353
  const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
971
1354
  const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, defaults.logger);
@@ -979,12 +1362,21 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
979
1362
  fixture
980
1363
  }
981
1364
  });
1365
+ require_misbehavior.recordMisbehaviorOutcome({
1366
+ entry: journalEntry,
1367
+ summary: misbehavior.summary,
1368
+ defaults,
1369
+ testId
1370
+ });
1371
+ const ordered = require_helpers.resolveServedBlockOutcome(response)?.ordered;
1372
+ if (!ordered) require_helpers.assertCustomToolCalls(response);
1373
+ const toolCalls = require_helpers.servedToolCalls(response);
982
1374
  if (responsesReq.stream !== true) {
983
- const body = buildContentWithToolCallsResponse(response.content ?? "", response.toolCalls ?? [], completionReq.model, effReasoning, response.webSearches, overrides, response.blocks, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1375
+ const body = buildContentWithToolCallsResponse(response.content ?? "", toolCalls, completionReq.model, effReasoning, response.webSearches, overrides, ordered, emitEncryptedReasoning, synthesizeSummarylessReasoning);
984
1376
  res.writeHead(200, { "Content-Type": "application/json" });
985
1377
  res.end(JSON.stringify(body));
986
1378
  } else {
987
- const events = buildContentWithToolCallsStreamEvents(response.content ?? "", response.toolCalls ?? [], completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, response.blocks, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1379
+ const events = contentWithToolCallsStreamEvents(response.content ?? "", toolCalls, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, ordered, emitEncryptedReasoning, synthesizeSummarylessReasoning);
988
1380
  const interruption = require_interruption.createInterruptionSignal(fixture);
989
1381
  if (!await writeResponsesSSEStream(res, events, {
990
1382
  latency,
@@ -1016,6 +1408,12 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
1016
1408
  fixture
1017
1409
  }
1018
1410
  });
1411
+ require_misbehavior.recordMisbehaviorOutcome({
1412
+ entry: journalEntry,
1413
+ summary: misbehavior.summary,
1414
+ defaults,
1415
+ testId
1416
+ });
1019
1417
  if (responsesReq.stream !== true) {
1020
1418
  const body = buildTextResponse(response.content, completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1021
1419
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -1053,12 +1451,19 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
1053
1451
  fixture
1054
1452
  }
1055
1453
  });
1454
+ require_misbehavior.recordMisbehaviorOutcome({
1455
+ entry: journalEntry,
1456
+ summary: misbehavior.summary,
1457
+ defaults,
1458
+ testId
1459
+ });
1460
+ require_helpers.assertCustomToolCalls(response);
1056
1461
  if (responsesReq.stream !== true) {
1057
- const body = buildToolCallResponse(response.toolCalls, completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1462
+ const body = buildToolCallResponse(require_helpers.servedToolCalls(response), completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1058
1463
  res.writeHead(200, { "Content-Type": "application/json" });
1059
1464
  res.end(JSON.stringify(body));
1060
1465
  } else {
1061
- const events = buildToolCallStreamEvents(response.toolCalls, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1466
+ const events = toolCallStreamEvents(require_helpers.servedToolCalls(response), completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
1062
1467
  const interruption = require_interruption.createInterruptionSignal(fixture);
1063
1468
  if (!await writeResponsesSSEStream(res, events, {
1064
1469
  latency,
@@ -1076,29 +1481,159 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
1076
1481
  }
1077
1482
  return;
1078
1483
  }
1079
- journal.add({
1080
- method: req.method ?? "POST",
1081
- path: req.url ?? "/v1/responses",
1082
- headers: require_helpers.flattenHeaders(req.headers),
1083
- body: completionReq,
1084
- response: {
1085
- status: 500,
1086
- fixture
1087
- }
1484
+ require_misbehavior.recordMisbehaviorOutcome({
1485
+ entry: journal.add({
1486
+ method: req.method ?? "POST",
1487
+ path: req.url ?? "/v1/responses",
1488
+ headers: require_helpers.flattenHeaders(req.headers),
1489
+ body: completionReq,
1490
+ response: {
1491
+ status: 500,
1492
+ fixture
1493
+ }
1494
+ }),
1495
+ summary: misbehavior.summary,
1496
+ defaults,
1497
+ testId
1088
1498
  });
1089
1499
  require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
1090
1500
  message: "Fixture response did not match any known type",
1091
1501
  type: "server_error"
1092
1502
  } }));
1093
1503
  }
1504
+ /** Prepare call IDs once, retaining the engine's effective blocks and exact served-call metadata. */
1505
+ function prepareResponsesMisbehavior(plan) {
1506
+ return require_helpers.prepareOpenAIChatMisbehavior(plan);
1507
+ }
1508
+ /** Build one faulted payload/event sequence for both HTTP and Responses WebSocket consumers. */
1509
+ function buildResponsesMisbehavior(plan, request, chunkSize, emitEncryptedReasoning = false) {
1510
+ const response = plan.response;
1511
+ if (!(require_helpers.isCombinedFixtureResponse(response) || require_helpers.isTextResponse(response) || require_helpers.isToolCallResponse(response))) throw new Error("Responses misbehavior requires a prepared chat response");
1512
+ const overrides = require_helpers.extractOverrides(response);
1513
+ const reasoning = plan.reasoning ?? ("reasoning" in response ? response.reasoning : void 0);
1514
+ const webSearches = "webSearches" in response ? response.webSearches : void 0;
1515
+ const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(request.model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, false, plan.reasoning !== void 0);
1516
+ const output = [...prefixOutputItems];
1517
+ let outputIndex = nextOutputIndex;
1518
+ const incomplete = plan.stop === "length" || plan.stop === "content_filter";
1519
+ if (plan.refusal !== void 0) {
1520
+ const id = itemId();
1521
+ const part = {
1522
+ type: "refusal",
1523
+ refusal: plan.refusal
1524
+ };
1525
+ const item = {
1526
+ id,
1527
+ type: "message",
1528
+ role: "assistant",
1529
+ status: "completed",
1530
+ content: [part]
1531
+ };
1532
+ const position = {
1533
+ item_id: id,
1534
+ output_index: outputIndex,
1535
+ content_index: 0
1536
+ };
1537
+ events.push({
1538
+ type: "response.output_item.added",
1539
+ output_index: outputIndex,
1540
+ item: {
1541
+ ...item,
1542
+ status: "in_progress",
1543
+ content: []
1544
+ }
1545
+ }, {
1546
+ type: "response.content_part.added",
1547
+ ...position,
1548
+ part: {
1549
+ type: "refusal",
1550
+ refusal: ""
1551
+ }
1552
+ });
1553
+ for (let i = 0; i < plan.refusal.length; i += chunkSize) events.push({
1554
+ type: "response.refusal.delta",
1555
+ ...position,
1556
+ delta: plan.refusal.slice(i, i + chunkSize)
1557
+ });
1558
+ events.push({
1559
+ type: "response.refusal.done",
1560
+ ...position,
1561
+ refusal: plan.refusal
1562
+ }, {
1563
+ type: "response.content_part.done",
1564
+ ...position,
1565
+ part
1566
+ }, {
1567
+ type: "response.output_item.done",
1568
+ output_index: outputIndex,
1569
+ item
1570
+ });
1571
+ output.push(item);
1572
+ } else if (plan.summary.fault !== "empty-response" && plan.stop !== "content_filter" && plan.reasoning === void 0) {
1573
+ const combined = require_helpers.isCombinedFixtureResponse(response);
1574
+ const blocks = (combined ? require_helpers.resolveServedBlockOutcome(response) : void 0)?.ordered ?? [..."content" in response && typeof response.content === "string" ? [{
1575
+ type: "text",
1576
+ text: response.content
1577
+ }] : [], ...combined || require_helpers.isToolCallResponse(response) ? require_helpers.servedToolCalls(response).map(require_helpers.toolCallFixtureBlock) : []];
1578
+ let callIndex = 0;
1579
+ for (const block of blocks) {
1580
+ if (block.type === "text") {
1581
+ const message = buildMessageOutputEvents(block.text, chunkSize, outputIndex);
1582
+ events.push(...message.events);
1583
+ output.push(message.msgItem);
1584
+ } else {
1585
+ const call = block.type === "customToolCall" ? buildCustomToolCallOutputEvents(block, chunkSize, outputIndex) : buildFunctionCallOutputEvents(block, chunkSize, outputIndex);
1586
+ const cut = plan.summary.fault === "stop-length-mid-tool" && callIndex === plan.target?.index;
1587
+ const item = cut ? {
1588
+ ...call.item,
1589
+ status: "incomplete"
1590
+ } : call.item;
1591
+ events.push(...call.events.map((event) => cut && event.type === "response.output_item.done" ? {
1592
+ ...event,
1593
+ item
1594
+ } : event));
1595
+ output.push(item);
1596
+ callIndex++;
1597
+ }
1598
+ outputIndex++;
1599
+ }
1600
+ }
1601
+ const usage = require_helpers.resolveOpenAIChatMisbehaviorUsage(plan, request);
1602
+ const body = {
1603
+ id: respId,
1604
+ object: "response",
1605
+ created_at: created,
1606
+ model: overrides?.model ?? request.model,
1607
+ status: incomplete ? "incomplete" : responsesStatus(overrides?.finishReason, "completed"),
1608
+ ...incomplete ? { incomplete_details: { reason: plan.stop === "content_filter" ? "content_filter" : "max_output_tokens" } } : {},
1609
+ output,
1610
+ usage: {
1611
+ input_tokens: usage.prompt_tokens,
1612
+ output_tokens: usage.completion_tokens,
1613
+ total_tokens: usage.total_tokens
1614
+ }
1615
+ };
1616
+ events.push({
1617
+ type: incomplete ? "response.incomplete" : "response.completed",
1618
+ response: body
1619
+ });
1620
+ return {
1621
+ response: body,
1622
+ events
1623
+ };
1624
+ }
1094
1625
 
1095
1626
  //#endregion
1096
1627
  exports.buildContentWithToolCallsStreamEvents = buildContentWithToolCallsStreamEvents;
1628
+ exports.buildResponsesMisbehavior = buildResponsesMisbehavior;
1097
1629
  exports.buildTextResponse = buildTextResponse;
1098
1630
  exports.buildTextStreamEvents = buildTextStreamEvents;
1099
1631
  exports.buildToolCallStreamEvents = buildToolCallStreamEvents;
1632
+ exports.contentWithToolCallsStreamEvents = contentWithToolCallsStreamEvents;
1100
1633
  exports.handleResponses = handleResponses;
1634
+ exports.prepareResponsesMisbehavior = prepareResponsesMisbehavior;
1101
1635
  exports.requestIncludesEncryptedReasoning = requestIncludesEncryptedReasoning;
1102
1636
  exports.requestWantsEncryptedReasoning = requestWantsEncryptedReasoning;
1103
1637
  exports.responsesToCompletionRequest = responsesToCompletionRequest;
1638
+ exports.toolCallStreamEvents = toolCallStreamEvents;
1104
1639
  //# sourceMappingURL=responses.cjs.map