@copilotkit/aimock 1.45.0 → 1.46.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +24 -0
  4. package/README.md +7 -1
  5. package/dist/agui-mock.cjs +25 -25
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +25 -25
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-types.d.ts.map +1 -1
  12. package/dist/aimock-cli.cjs +15 -1
  13. package/dist/aimock-cli.cjs.map +1 -1
  14. package/dist/aimock-cli.d.cts.map +1 -1
  15. package/dist/aimock-cli.d.ts.map +1 -1
  16. package/dist/aimock-cli.js +16 -2
  17. package/dist/aimock-cli.js.map +1 -1
  18. package/dist/api-key-auth.cjs +10 -9
  19. package/dist/api-key-auth.cjs.map +1 -1
  20. package/dist/api-key-auth.d.cts.map +1 -1
  21. package/dist/api-key-auth.d.ts.map +1 -1
  22. package/dist/api-key-auth.js +11 -10
  23. package/dist/api-key-auth.js.map +1 -1
  24. package/dist/batches.cjs +2 -4
  25. package/dist/batches.cjs.map +1 -1
  26. package/dist/batches.d.cts.map +1 -1
  27. package/dist/batches.d.ts.map +1 -1
  28. package/dist/batches.js +2 -4
  29. package/dist/batches.js.map +1 -1
  30. package/dist/bedrock-converse.cjs +61 -80
  31. package/dist/bedrock-converse.cjs.map +1 -1
  32. package/dist/bedrock-converse.d.cts.map +1 -1
  33. package/dist/bedrock-converse.d.ts.map +1 -1
  34. package/dist/bedrock-converse.js +58 -77
  35. package/dist/bedrock-converse.js.map +1 -1
  36. package/dist/bedrock.cjs +65 -97
  37. package/dist/bedrock.cjs.map +1 -1
  38. package/dist/bedrock.d.cts.map +1 -1
  39. package/dist/bedrock.d.ts.map +1 -1
  40. package/dist/bedrock.js +62 -94
  41. package/dist/bedrock.js.map +1 -1
  42. package/dist/byteplus-video.cjs +11 -10
  43. package/dist/byteplus-video.cjs.map +1 -1
  44. package/dist/byteplus-video.d.cts.map +1 -1
  45. package/dist/byteplus-video.d.ts.map +1 -1
  46. package/dist/byteplus-video.js +5 -4
  47. package/dist/byteplus-video.js.map +1 -1
  48. package/dist/chaos.cjs +5 -4
  49. package/dist/chaos.cjs.map +1 -1
  50. package/dist/chaos.d.cts.map +1 -1
  51. package/dist/chaos.d.ts.map +1 -1
  52. package/dist/chaos.js +5 -4
  53. package/dist/chaos.js.map +1 -1
  54. package/dist/cli.cjs +15 -0
  55. package/dist/cli.cjs.map +1 -1
  56. package/dist/cli.js +15 -0
  57. package/dist/cli.js.map +1 -1
  58. package/dist/cohere.cjs +49 -74
  59. package/dist/cohere.cjs.map +1 -1
  60. package/dist/cohere.d.cts.map +1 -1
  61. package/dist/cohere.d.ts.map +1 -1
  62. package/dist/cohere.js +47 -72
  63. package/dist/cohere.js.map +1 -1
  64. package/dist/config-loader.cjs +29 -1
  65. package/dist/config-loader.cjs.map +1 -1
  66. package/dist/config-loader.d.cts +7 -1
  67. package/dist/config-loader.d.cts.map +1 -1
  68. package/dist/config-loader.d.ts +7 -1
  69. package/dist/config-loader.d.ts.map +1 -1
  70. package/dist/config-loader.js +29 -2
  71. package/dist/config-loader.js.map +1 -1
  72. package/dist/count-tokens.cjs +146 -0
  73. package/dist/count-tokens.cjs.map +1 -0
  74. package/dist/count-tokens.js +146 -0
  75. package/dist/count-tokens.js.map +1 -0
  76. package/dist/elevenlabs-audio.cjs +36 -34
  77. package/dist/elevenlabs-audio.cjs.map +1 -1
  78. package/dist/elevenlabs-audio.d.cts.map +1 -1
  79. package/dist/elevenlabs-audio.d.ts.map +1 -1
  80. package/dist/elevenlabs-audio.js +33 -31
  81. package/dist/elevenlabs-audio.js.map +1 -1
  82. package/dist/elevenlabs-voice.cjs +38 -37
  83. package/dist/elevenlabs-voice.cjs.map +1 -1
  84. package/dist/elevenlabs-voice.d.cts.map +1 -1
  85. package/dist/elevenlabs-voice.d.ts.map +1 -1
  86. package/dist/elevenlabs-voice.js +33 -32
  87. package/dist/elevenlabs-voice.js.map +1 -1
  88. package/dist/embedding-request.cjs +16 -0
  89. package/dist/embedding-request.cjs.map +1 -0
  90. package/dist/embedding-request.js +14 -0
  91. package/dist/embedding-request.js.map +1 -0
  92. package/dist/embeddings.cjs +30 -20
  93. package/dist/embeddings.cjs.map +1 -1
  94. package/dist/embeddings.d.cts.map +1 -1
  95. package/dist/embeddings.d.ts.map +1 -1
  96. package/dist/embeddings.js +30 -20
  97. package/dist/embeddings.js.map +1 -1
  98. package/dist/fal-audio.cjs +45 -43
  99. package/dist/fal-audio.cjs.map +1 -1
  100. package/dist/fal-audio.d.cts.map +1 -1
  101. package/dist/fal-audio.d.ts.map +1 -1
  102. package/dist/fal-audio.js +42 -40
  103. package/dist/fal-audio.js.map +1 -1
  104. package/dist/fal.cjs +17 -15
  105. package/dist/fal.cjs.map +1 -1
  106. package/dist/fal.js +16 -14
  107. package/dist/fal.js.map +1 -1
  108. package/dist/files.cjs +2 -4
  109. package/dist/files.cjs.map +1 -1
  110. package/dist/files.d.cts.map +1 -1
  111. package/dist/files.d.ts.map +1 -1
  112. package/dist/files.js +2 -4
  113. package/dist/files.js.map +1 -1
  114. package/dist/fine-tuning.cjs +2 -4
  115. package/dist/fine-tuning.cjs.map +1 -1
  116. package/dist/fine-tuning.d.cts.map +1 -1
  117. package/dist/fine-tuning.d.ts.map +1 -1
  118. package/dist/fine-tuning.js +2 -4
  119. package/dist/fine-tuning.js.map +1 -1
  120. package/dist/fixture-loader.cjs +37 -42
  121. package/dist/fixture-loader.cjs.map +1 -1
  122. package/dist/fixture-loader.d.cts.map +1 -1
  123. package/dist/fixture-loader.d.ts.map +1 -1
  124. package/dist/fixture-loader.js +37 -42
  125. package/dist/fixture-loader.js.map +1 -1
  126. package/dist/gemini-embeddings.cjs +26 -24
  127. package/dist/gemini-embeddings.cjs.map +1 -1
  128. package/dist/gemini-embeddings.js +26 -24
  129. package/dist/gemini-embeddings.js.map +1 -1
  130. package/dist/gemini-interactions.cjs +50 -35
  131. package/dist/gemini-interactions.cjs.map +1 -1
  132. package/dist/gemini-interactions.d.cts +0 -1
  133. package/dist/gemini-interactions.d.cts.map +1 -1
  134. package/dist/gemini-interactions.d.ts +0 -1
  135. package/dist/gemini-interactions.d.ts.map +1 -1
  136. package/dist/gemini-interactions.js +49 -34
  137. package/dist/gemini-interactions.js.map +1 -1
  138. package/dist/gemini.cjs +57 -67
  139. package/dist/gemini.cjs.map +1 -1
  140. package/dist/gemini.d.cts.map +1 -1
  141. package/dist/gemini.d.ts.map +1 -1
  142. package/dist/gemini.js +56 -67
  143. package/dist/gemini.js.map +1 -1
  144. package/dist/grok-video.cjs +14 -12
  145. package/dist/grok-video.cjs.map +1 -1
  146. package/dist/grok-video.d.cts.map +1 -1
  147. package/dist/grok-video.d.ts.map +1 -1
  148. package/dist/grok-video.js +8 -6
  149. package/dist/grok-video.js.map +1 -1
  150. package/dist/helpers.cjs +11 -68
  151. package/dist/helpers.cjs.map +1 -1
  152. package/dist/helpers.d.cts.map +1 -1
  153. package/dist/helpers.d.ts.map +1 -1
  154. package/dist/helpers.js +12 -67
  155. package/dist/helpers.js.map +1 -1
  156. package/dist/images.cjs +30 -28
  157. package/dist/images.cjs.map +1 -1
  158. package/dist/images.d.cts.map +1 -1
  159. package/dist/images.d.ts.map +1 -1
  160. package/dist/images.js +27 -25
  161. package/dist/images.js.map +1 -1
  162. package/dist/index.d.cts +2 -2
  163. package/dist/index.d.ts +2 -2
  164. package/dist/journal.cjs +3 -1
  165. package/dist/journal.cjs.map +1 -1
  166. package/dist/journal.d.cts.map +1 -1
  167. package/dist/journal.d.ts.map +1 -1
  168. package/dist/journal.js +2 -1
  169. package/dist/journal.js.map +1 -1
  170. package/dist/llmock.cjs +3 -0
  171. package/dist/llmock.cjs.map +1 -1
  172. package/dist/llmock.d.cts.map +1 -1
  173. package/dist/llmock.d.ts.map +1 -1
  174. package/dist/llmock.js +3 -0
  175. package/dist/llmock.js.map +1 -1
  176. package/dist/mcp-fakes.d.cts.map +1 -1
  177. package/dist/mcp-handler.cjs +14 -4
  178. package/dist/mcp-handler.cjs.map +1 -1
  179. package/dist/mcp-handler.js +14 -4
  180. package/dist/mcp-handler.js.map +1 -1
  181. package/dist/mcp-recorder.cjs +2 -1
  182. package/dist/mcp-recorder.cjs.map +1 -1
  183. package/dist/mcp-recorder.js +3 -2
  184. package/dist/mcp-recorder.js.map +1 -1
  185. package/dist/messages.cjs +111 -96
  186. package/dist/messages.cjs.map +1 -1
  187. package/dist/messages.d.cts.map +1 -1
  188. package/dist/messages.d.ts.map +1 -1
  189. package/dist/messages.js +109 -95
  190. package/dist/messages.js.map +1 -1
  191. package/dist/metrics.cjs +5 -2
  192. package/dist/metrics.cjs.map +1 -1
  193. package/dist/metrics.d.cts.map +1 -1
  194. package/dist/metrics.d.ts.map +1 -1
  195. package/dist/metrics.js +6 -3
  196. package/dist/metrics.js.map +1 -1
  197. package/dist/model-utils.cjs +1 -0
  198. package/dist/model-utils.cjs.map +1 -1
  199. package/dist/model-utils.js +1 -1
  200. package/dist/model-utils.js.map +1 -1
  201. package/dist/moderation.cjs +15 -12
  202. package/dist/moderation.cjs.map +1 -1
  203. package/dist/moderation.js +14 -11
  204. package/dist/moderation.js.map +1 -1
  205. package/dist/ollama.cjs +128 -68
  206. package/dist/ollama.cjs.map +1 -1
  207. package/dist/ollama.d.cts.map +1 -1
  208. package/dist/ollama.d.ts.map +1 -1
  209. package/dist/ollama.js +124 -64
  210. package/dist/ollama.js.map +1 -1
  211. package/dist/openapi.cjs +323 -3
  212. package/dist/openapi.cjs.map +1 -1
  213. package/dist/openapi.d.cts.map +1 -1
  214. package/dist/openapi.d.ts.map +1 -1
  215. package/dist/openapi.js +324 -4
  216. package/dist/openapi.js.map +1 -1
  217. package/dist/openrouter-chat.cjs +11 -155
  218. package/dist/openrouter-chat.cjs.map +1 -1
  219. package/dist/openrouter-chat.js +11 -155
  220. package/dist/openrouter-chat.js.map +1 -1
  221. package/dist/openrouter-video.cjs +76 -71
  222. package/dist/openrouter-video.cjs.map +1 -1
  223. package/dist/openrouter-video.d.cts.map +1 -1
  224. package/dist/openrouter-video.d.ts.map +1 -1
  225. package/dist/openrouter-video.js +63 -58
  226. package/dist/openrouter-video.js.map +1 -1
  227. package/dist/recorder.cjs +176 -95
  228. package/dist/recorder.cjs.map +1 -1
  229. package/dist/recorder.d.cts.map +1 -1
  230. package/dist/recorder.d.ts.map +1 -1
  231. package/dist/recorder.js +176 -95
  232. package/dist/recorder.js.map +1 -1
  233. package/dist/rerank.cjs +13 -11
  234. package/dist/rerank.cjs.map +1 -1
  235. package/dist/rerank.js +12 -10
  236. package/dist/rerank.js.map +1 -1
  237. package/dist/response/catalog/anthropic-page.cjs +39 -0
  238. package/dist/response/catalog/anthropic-page.cjs.map +1 -0
  239. package/dist/response/catalog/anthropic-page.js +38 -0
  240. package/dist/response/catalog/anthropic-page.js.map +1 -0
  241. package/dist/response/catalog/collect.cjs +61 -0
  242. package/dist/response/catalog/collect.cjs.map +1 -0
  243. package/dist/response/catalog/collect.js +59 -0
  244. package/dist/response/catalog/collect.js.map +1 -0
  245. package/dist/response/catalog/gemini-page.cjs +25 -0
  246. package/dist/response/catalog/gemini-page.cjs.map +1 -0
  247. package/dist/response/catalog/gemini-page.js +24 -0
  248. package/dist/response/catalog/gemini-page.js.map +1 -0
  249. package/dist/response/catalog/render.cjs +182 -0
  250. package/dist/response/catalog/render.cjs.map +1 -0
  251. package/dist/response/catalog/render.js +171 -0
  252. package/dist/response/catalog/render.js.map +1 -0
  253. package/dist/response/errors.cjs +225 -0
  254. package/dist/response/errors.cjs.map +1 -0
  255. package/dist/response/errors.js +224 -0
  256. package/dist/response/errors.js.map +1 -0
  257. package/dist/response/finish.cjs +39 -0
  258. package/dist/response/finish.cjs.map +1 -0
  259. package/dist/response/finish.js +35 -0
  260. package/dist/response/finish.js.map +1 -0
  261. package/dist/response/policy.cjs +126 -0
  262. package/dist/response/policy.cjs.map +1 -0
  263. package/dist/response/policy.js +120 -0
  264. package/dist/response/policy.js.map +1 -0
  265. package/dist/response/profiles.cjs +69 -0
  266. package/dist/response/profiles.cjs.map +1 -0
  267. package/dist/response/profiles.js +65 -0
  268. package/dist/response/profiles.js.map +1 -0
  269. package/dist/response/usage/codecs/anthropic.cjs +52 -0
  270. package/dist/response/usage/codecs/anthropic.cjs.map +1 -0
  271. package/dist/response/usage/codecs/anthropic.js +50 -0
  272. package/dist/response/usage/codecs/anthropic.js.map +1 -0
  273. package/dist/response/usage/codecs/cohere.cjs +36 -0
  274. package/dist/response/usage/codecs/cohere.cjs.map +1 -0
  275. package/dist/response/usage/codecs/cohere.js +35 -0
  276. package/dist/response/usage/codecs/cohere.js.map +1 -0
  277. package/dist/response/usage/codecs/converse.cjs +16 -0
  278. package/dist/response/usage/codecs/converse.cjs.map +1 -0
  279. package/dist/response/usage/codecs/converse.js +15 -0
  280. package/dist/response/usage/codecs/converse.js.map +1 -0
  281. package/dist/response/usage/codecs/gemini.cjs +31 -0
  282. package/dist/response/usage/codecs/gemini.cjs.map +1 -0
  283. package/dist/response/usage/codecs/gemini.js +31 -0
  284. package/dist/response/usage/codecs/gemini.js.map +1 -0
  285. package/dist/response/usage/codecs/interactions.cjs +22 -0
  286. package/dist/response/usage/codecs/interactions.cjs.map +1 -0
  287. package/dist/response/usage/codecs/interactions.js +21 -0
  288. package/dist/response/usage/codecs/interactions.js.map +1 -0
  289. package/dist/response/usage/codecs/ollama.cjs +17 -0
  290. package/dist/response/usage/codecs/ollama.cjs.map +1 -0
  291. package/dist/response/usage/codecs/ollama.js +17 -0
  292. package/dist/response/usage/codecs/ollama.js.map +1 -0
  293. package/dist/response/usage/codecs/openai.cjs +52 -0
  294. package/dist/response/usage/codecs/openai.cjs.map +1 -0
  295. package/dist/response/usage/codecs/openai.js +50 -0
  296. package/dist/response/usage/codecs/openai.js.map +1 -0
  297. package/dist/response/usage/codecs/openrouter.cjs +68 -0
  298. package/dist/response/usage/codecs/openrouter.cjs.map +1 -0
  299. package/dist/response/usage/codecs/openrouter.js +67 -0
  300. package/dist/response/usage/codecs/openrouter.js.map +1 -0
  301. package/dist/response/usage/codecs/realtime.cjs +19 -0
  302. package/dist/response/usage/codecs/realtime.cjs.map +1 -0
  303. package/dist/response/usage/codecs/realtime.js +18 -0
  304. package/dist/response/usage/codecs/realtime.js.map +1 -0
  305. package/dist/response/usage/codecs/responses.cjs +21 -0
  306. package/dist/response/usage/codecs/responses.cjs.map +1 -0
  307. package/dist/response/usage/codecs/responses.js +20 -0
  308. package/dist/response/usage/codecs/responses.js.map +1 -0
  309. package/dist/response/usage/estimate.cjs +23 -0
  310. package/dist/response/usage/estimate.cjs.map +1 -0
  311. package/dist/response/usage/estimate.js +21 -0
  312. package/dist/response/usage/estimate.js.map +1 -0
  313. package/dist/response/usage/fields.cjs +72 -0
  314. package/dist/response/usage/fields.cjs.map +1 -0
  315. package/dist/response/usage/fields.js +70 -0
  316. package/dist/response/usage/fields.js.map +1 -0
  317. package/dist/response/usage/recording.cjs +52 -0
  318. package/dist/response/usage/recording.cjs.map +1 -0
  319. package/dist/response/usage/recording.js +52 -0
  320. package/dist/response/usage/recording.js.map +1 -0
  321. package/dist/responses.cjs +45 -58
  322. package/dist/responses.cjs.map +1 -1
  323. package/dist/responses.d.cts.map +1 -1
  324. package/dist/responses.d.ts.map +1 -1
  325. package/dist/responses.js +44 -57
  326. package/dist/responses.js.map +1 -1
  327. package/dist/route-registry.cjs +45 -0
  328. package/dist/route-registry.cjs.map +1 -1
  329. package/dist/route-registry.d.cts.map +1 -1
  330. package/dist/route-registry.d.ts.map +1 -1
  331. package/dist/route-registry.js +41 -1
  332. package/dist/route-registry.js.map +1 -1
  333. package/dist/router.cjs +4 -0
  334. package/dist/router.cjs.map +1 -1
  335. package/dist/router.d.cts.map +1 -1
  336. package/dist/router.d.ts.map +1 -1
  337. package/dist/router.js +3 -0
  338. package/dist/router.js.map +1 -1
  339. package/dist/search.cjs +13 -11
  340. package/dist/search.cjs.map +1 -1
  341. package/dist/search.js +12 -10
  342. package/dist/search.js.map +1 -1
  343. package/dist/server.cjs +222 -146
  344. package/dist/server.cjs.map +1 -1
  345. package/dist/server.d.cts.map +1 -1
  346. package/dist/server.d.ts.map +1 -1
  347. package/dist/server.js +223 -147
  348. package/dist/server.js.map +1 -1
  349. package/dist/speech.cjs +20 -18
  350. package/dist/speech.cjs.map +1 -1
  351. package/dist/speech.d.cts.map +1 -1
  352. package/dist/speech.d.ts.map +1 -1
  353. package/dist/speech.js +19 -17
  354. package/dist/speech.js.map +1 -1
  355. package/dist/sse-writer.cjs +7 -0
  356. package/dist/sse-writer.cjs.map +1 -1
  357. package/dist/sse-writer.d.cts.map +1 -1
  358. package/dist/sse-writer.d.ts.map +1 -1
  359. package/dist/sse-writer.js +7 -1
  360. package/dist/sse-writer.js.map +1 -1
  361. package/dist/stream-collapse.cjs +118 -11
  362. package/dist/stream-collapse.cjs.map +1 -1
  363. package/dist/stream-collapse.d.cts +10 -9
  364. package/dist/stream-collapse.d.cts.map +1 -1
  365. package/dist/stream-collapse.d.ts +10 -9
  366. package/dist/stream-collapse.d.ts.map +1 -1
  367. package/dist/stream-collapse.js +118 -11
  368. package/dist/stream-collapse.js.map +1 -1
  369. package/dist/transcription.cjs +12 -10
  370. package/dist/transcription.cjs.map +1 -1
  371. package/dist/transcription.d.cts.map +1 -1
  372. package/dist/transcription.d.ts.map +1 -1
  373. package/dist/transcription.js +11 -9
  374. package/dist/transcription.js.map +1 -1
  375. package/dist/types.cjs.map +1 -1
  376. package/dist/types.d.cts +62 -3
  377. package/dist/types.d.cts.map +1 -1
  378. package/dist/types.d.ts +62 -3
  379. package/dist/types.d.ts.map +1 -1
  380. package/dist/types.js.map +1 -1
  381. package/dist/vector-mock.cjs +3 -8
  382. package/dist/vector-mock.cjs.map +1 -1
  383. package/dist/vector-mock.d.cts.map +1 -1
  384. package/dist/vector-mock.d.ts.map +1 -1
  385. package/dist/vector-mock.js +3 -8
  386. package/dist/vector-mock.js.map +1 -1
  387. package/dist/vector-stores.cjs +2 -4
  388. package/dist/vector-stores.cjs.map +1 -1
  389. package/dist/vector-stores.d.cts.map +1 -1
  390. package/dist/vector-stores.d.ts.map +1 -1
  391. package/dist/vector-stores.js +2 -4
  392. package/dist/vector-stores.js.map +1 -1
  393. package/dist/veo-video.cjs +16 -14
  394. package/dist/veo-video.cjs.map +1 -1
  395. package/dist/veo-video.js +10 -8
  396. package/dist/veo-video.js.map +1 -1
  397. package/dist/video.cjs +21 -19
  398. package/dist/video.cjs.map +1 -1
  399. package/dist/video.d.cts.map +1 -1
  400. package/dist/video.d.ts.map +1 -1
  401. package/dist/video.js +20 -18
  402. package/dist/video.js.map +1 -1
  403. package/dist/ws-gemini-live.cjs +11 -3
  404. package/dist/ws-gemini-live.cjs.map +1 -1
  405. package/dist/ws-gemini-live.d.cts +0 -1
  406. package/dist/ws-gemini-live.d.cts.map +1 -1
  407. package/dist/ws-gemini-live.d.ts +0 -1
  408. package/dist/ws-gemini-live.d.ts.map +1 -1
  409. package/dist/ws-gemini-live.js +10 -2
  410. package/dist/ws-gemini-live.js.map +1 -1
  411. package/dist/ws-live.cjs +6 -5
  412. package/dist/ws-live.cjs.map +1 -1
  413. package/dist/ws-live.js +5 -4
  414. package/dist/ws-live.js.map +1 -1
  415. package/dist/ws-realtime.cjs +28 -54
  416. package/dist/ws-realtime.cjs.map +1 -1
  417. package/dist/ws-realtime.d.cts.map +1 -1
  418. package/dist/ws-realtime.d.ts.map +1 -1
  419. package/dist/ws-realtime.js +25 -51
  420. package/dist/ws-realtime.js.map +1 -1
  421. package/dist/ws-responses.cjs +8 -6
  422. package/dist/ws-responses.cjs.map +1 -1
  423. package/dist/ws-responses.js +7 -5
  424. package/dist/ws-responses.js.map +1 -1
  425. package/package.json +4 -1
  426. package/skills/write-fixtures/SKILL.md +25 -16
@@ -1 +1 @@
1
- {"version":3,"file":"gemini-interactions.cjs","names":["isJsonObject","generateToolCallId","servedToolArgs","resolveFixtureBlockOutcome","calculateDelay","delay","isCombinedFixtureResponse","isToolCallResponse","prepareOpenAIChatMisbehavior","flattenHeaders","getContext","getTestId","matchFixtureDiagnostic","applyChaosAsync","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","planMisbehavior","resolveOpenAIChatMisbehaviorUsage","isErrorResponse","isTextResponse","extractOverrides","createInterruptionSignal","requireEmittedFunctionToolCalls"],"sources":["../src/gemini-interactions.ts"],"sourcesContent":["/**\n * Google Gemini Interactions API support.\n *\n * Translates incoming Interactions requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back\n * into the Gemini Interactions format — either a single JSON response or\n * an SSE stream with event_type-based framing.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n FixtureBlock,\n HandlerDefaults,\n RecordedTimings,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n requireEmittedFunctionToolCalls,\n isTextResponse,\n isToolCallResponse,\n isCombinedFixtureResponse,\n isErrorResponse,\n extractOverrides,\n generateToolCallId,\n flattenHeaders,\n isJsonObject,\n getTestId,\n getContext,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n resolveFixtureBlockOutcome,\n servedToolArgs,\n prepareOpenAIChatMisbehavior,\n resolveOpenAIChatMisbehaviorUsage,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport {\n planMisbehavior,\n recordMisbehaviorOutcome,\n type MisbehaviorPlan,\n type MisbehaviorSkip,\n} from \"./misbehavior.js\";\n\n// ─── Interactions request types ────────────────────────────────────────────\n\ninterface InteractionsContentBlock {\n type: string;\n text?: string;\n name?: string;\n call_id?: string;\n id?: string;\n arguments?: Record<string, unknown>;\n output?: unknown;\n result?: unknown;\n}\n\ninterface InteractionsTurn {\n role: string;\n content?: InteractionsContentBlock[];\n parts?: InteractionsContentBlock[];\n}\n\n/**\n * Top-level Step envelope accepted by the live Gemini Interactions API.\n * The SDK's TypeScript union does not include Step[], but the wire contract\n * does — clients following the live API send these at the top level of `input`.\n * Discriminated by `type`; no `role` field (distinguishes from Turn[]).\n */\ninterface InteractionsStep {\n type: string;\n content?: InteractionsContentBlock[];\n call_id?: string;\n id?: string;\n name?: string;\n result?: unknown;\n output?: unknown;\n is_error?: boolean;\n signature?: string;\n}\n\n/** Step types whose payload is a tool/agent result keyed by call_id. */\nconst STEP_RESULT_TYPES = new Set<string>([\n \"function_result\",\n \"code_execution_result\",\n \"url_context_result\",\n \"google_search_result\",\n \"google_maps_result\",\n \"mcp_server_tool_result\",\n \"file_search_result\",\n]);\n\n/** All recognized top-level Step types (used as the Step[] discriminator). */\nconst STEP_TYPES = new Set<string>([\"user_input\", \"model_output\", ...STEP_RESULT_TYPES]);\n\ninterface InteractionsFunctionTool {\n type: \"function\";\n name: string;\n description?: string;\n parameters?: object;\n}\n\ninterface InteractionsRequest {\n model?: string;\n input?: string | InteractionsTurn[] | InteractionsStep[] | InteractionsContentBlock[];\n system_instruction?: string;\n tools?: InteractionsFunctionTool[];\n generation_config?: {\n temperature?: number;\n max_output_tokens?: number;\n [key: string]: unknown;\n };\n stream?: boolean;\n previous_interaction_id?: string;\n [key: string]: unknown;\n}\n\n// Check unsupported numeric input and containers consumed by the selected variant.\n// Other values retain their existing normalization, including omitted input.\nfunction validateInteractionsInput(input: unknown): string | null {\n if (typeof input === \"number\") return \"input must not be a number\";\n if (!Array.isArray(input)) return null;\n const first = input[0];\n if (isJsonObject(first) && \"role\" in first) {\n for (const [index, turn] of input.entries()) {\n if (!isJsonObject(turn)) continue;\n const blocks = turn.content ?? turn.parts;\n // Empty strings, falsy values and empty arrays bypass the converter's\n // filters. Preserve that behavior and the content ?? parts selection.\n if (typeof blocks === \"string\" && blocks.length > 0) {\n const field = turn.content != null ? \"content\" : \"parts\";\n return `input[${index}].${field} must be an array`;\n }\n }\n } else if (\n !(isJsonObject(first) && typeof first.type === \"string\" && STEP_TYPES.has(first.type))\n ) {\n const nullIndex = input.findIndex((part) => part === null);\n if (nullIndex !== -1) return `input[${nullIndex}] must be an object`;\n }\n return null;\n}\n\n// Preserve tools that the converter ignores; reject only these unsafe reads.\nfunction validateInteractionsTools(tools: unknown): string | null {\n if (typeof tools === \"string\" && tools.length > 0) return \"tools must be an array\";\n if (Array.isArray(tools)) {\n const nullIndex = tools.findIndex((tool) => tool === null);\n if (nullIndex !== -1) return `tools[${nullIndex}] must be an object`;\n }\n return null;\n}\n\n// ─── Input conversion: Interactions → ChatCompletionRequest ───────────────\n\nexport function geminiInteractionsToCompletionRequest(\n req: InteractionsRequest,\n): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n const model = req.model ?? \"gemini-2.5-flash\";\n\n // system_instruction → system message\n if (req.system_instruction) {\n messages.push({ role: \"system\", content: req.system_instruction });\n }\n\n // Parse input\n if (req.input !== undefined) {\n if (typeof req.input === \"string\") {\n // Simple string input → single user message\n messages.push({ role: \"user\", content: req.input });\n } else if (Array.isArray(req.input)) {\n // Could be Turn[], Step[], or Content[]\n const firstItem = req.input[0] as\n | InteractionsTurn\n | InteractionsStep\n | InteractionsContentBlock\n | undefined;\n const isStepArray =\n !!firstItem &&\n !(\"role\" in firstItem) &&\n typeof firstItem.type === \"string\" &&\n STEP_TYPES.has(firstItem.type);\n\n if (firstItem && \"role\" in firstItem) {\n // Turn[] format\n for (const turn of req.input as InteractionsTurn[]) {\n const role = turn.role === \"model\" ? \"assistant\" : turn.role;\n const blocks = turn.content ?? turn.parts;\n if (!blocks || blocks.length === 0) {\n if (role === \"user\" || role === \"assistant\") {\n messages.push({ role: role as \"user\" | \"assistant\", content: \"\" });\n }\n continue;\n }\n\n // Check for function_call or function_result parts\n const funcCallParts = blocks.filter((p) => p.type === \"function_call\");\n const funcResultParts = blocks.filter((p) => p.type === \"function_result\");\n const textParts = blocks.filter((p) => p.type === \"text\");\n\n if (funcCallParts.length > 0) {\n // Assistant tool call message\n const textContent = textParts.map((p) => p.text ?? \"\").join(\"\");\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: funcCallParts.map((p) => ({\n id: p.id ?? p.call_id ?? generateToolCallId(),\n type: \"function\" as const,\n function: {\n name: p.name ?? \"\",\n arguments: JSON.stringify(p.arguments ?? {}),\n },\n })),\n });\n } else if (funcResultParts.length > 0) {\n // Tool response messages\n for (const part of funcResultParts) {\n const resultValue = part.result ?? part.output;\n messages.push({\n role: \"tool\",\n content:\n typeof resultValue === \"string\" ? resultValue : JSON.stringify(resultValue ?? \"\"),\n tool_call_id: part.call_id ?? part.id ?? \"\",\n });\n }\n // Any text parts alongside → separate user message\n if (textParts.length > 0) {\n const text = textParts.map((p) => p.text ?? \"\").join(\"\");\n if (text) {\n messages.push({ role: \"user\", content: text });\n }\n }\n } else {\n // Text-only turn\n const text = textParts.map((p) => p.text ?? \"\").join(\"\");\n if (role === \"user\" || role === \"assistant\" || role === \"system\") {\n messages.push({\n role: role as \"user\" | \"assistant\" | \"system\",\n content: text,\n });\n }\n }\n }\n } else if (isStepArray) {\n // Step[] format — the wire contract Google's /v1beta/interactions accepts.\n for (const step of req.input as InteractionsStep[]) {\n if (step.type === \"user_input\") {\n const text = (step.content ?? [])\n .filter((p) => p.type === \"text\")\n .map((p) => p.text ?? \"\")\n .join(\"\");\n messages.push({ role: \"user\", content: text });\n } else if (step.type === \"model_output\") {\n const blocks = step.content ?? [];\n const funcCallParts = blocks.filter((p) => p.type === \"function_call\");\n const textParts = blocks.filter((p) => p.type === \"text\");\n const textContent = textParts.map((p) => p.text ?? \"\").join(\"\");\n\n if (funcCallParts.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: funcCallParts.map((p) => ({\n id: p.id ?? p.call_id ?? generateToolCallId(),\n type: \"function\" as const,\n function: {\n name: p.name ?? \"\",\n arguments: JSON.stringify(p.arguments ?? {}),\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent });\n }\n } else if (STEP_RESULT_TYPES.has(step.type)) {\n const resultValue = step.result ?? step.output;\n messages.push({\n role: \"tool\",\n content:\n typeof resultValue === \"string\" ? resultValue : JSON.stringify(resultValue ?? \"\"),\n tool_call_id: step.call_id ?? step.id ?? \"\",\n });\n }\n }\n } else {\n // Content[] format — single user message with content blocks\n const textParts = (req.input as InteractionsContentBlock[]).filter(\n (p) => p.type === \"text\",\n );\n const text = textParts.map((p) => p.text ?? \"\").join(\"\");\n messages.push({ role: \"user\", content: text || \"\" });\n }\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n const funcTools = req.tools.filter((t) => t.type === \"function\");\n if (funcTools.length > 0) {\n tools = funcTools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n },\n }));\n }\n }\n\n return {\n model,\n messages,\n stream: req.stream !== false, // default true\n temperature: req.generation_config?.temperature,\n max_tokens: req.generation_config?.max_output_tokens,\n tools,\n };\n}\n\n// ─── Interaction ID generation ────────────────────────────────────────────\n\nlet interactionCounter = 0;\n\nexport function resetInteractionCounter(): void {\n interactionCounter = 0;\n}\n\nfunction nextInteractionId(): string {\n return `aimock-int-${interactionCounter++}`;\n}\n\n// ─── Usage helpers ────────────────────────────────────────────────────────\n\nfunction interactionsUsage(overrides?: ResponseOverrides): {\n total_input_tokens: number;\n total_output_tokens: number;\n total_tokens: number;\n} {\n if (!overrides?.usage) return { total_input_tokens: 0, total_output_tokens: 0, total_tokens: 0 };\n const input =\n overrides.usage.input_tokens ??\n overrides.usage.prompt_tokens ??\n overrides.usage.promptTokenCount ??\n 0;\n const output =\n overrides.usage.output_tokens ??\n overrides.usage.completion_tokens ??\n overrides.usage.candidatesTokenCount ??\n 0;\n const total = overrides.usage.total_tokens ?? overrides.usage.totalTokenCount ?? input + output;\n return {\n total_input_tokens: input,\n total_output_tokens: output,\n total_tokens: total,\n };\n}\n\n// ─── Response building: fixture → Interactions format ─────────────────────\n\nexport function buildInteractionsTextResponse(\n content: string,\n model: string,\n interactionId: string,\n overrides?: ResponseOverrides,\n): object {\n return {\n id: interactionId,\n status: \"completed\",\n model: overrides?.model ?? model,\n role: \"model\",\n output_text: content,\n steps: [{ type: \"model_output\", content: [{ type: \"text\", text: content }] }],\n usage: interactionsUsage(overrides),\n };\n}\n\n// Build a single SDK 2.x function_call step from a fixture tool call,\n// serving malformed arguments as `{}` (or rejecting them under strictToolArguments).\nfunction buildFunctionCallStep(tc: ToolCall, logger: Logger): object {\n const args = servedToolArgs(tc, \"object\", logger);\n return {\n type: \"function_call\",\n id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: args.value,\n };\n}\n\nexport function buildInteractionsToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n interactionId: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n): object {\n return {\n id: interactionId,\n status: \"requires_action\",\n model: overrides?.model ?? model,\n role: \"model\",\n steps: toolCalls.map((tc) => buildFunctionCallStep(tc, logger)),\n usage: interactionsUsage(overrides),\n };\n}\n\nexport function buildInteractionsContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n interactionId: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): object {\n const steps: object[] = [];\n // Collect output_text in step order so the top-level field mirrors the\n // concatenated text steps regardless of where they appear in `steps`.\n let outputText = \"\";\n\n let hasToolCalls = true;\n if (blocks && blocks.length > 0) {\n // NEW PATH: the non-stream `steps[]` array is index/step-addressed and\n // ordered, so emit one step per block in fixture ARRAY ORDER. A toolCall\n // block placed before a text block therefore yields a function_call step\n // ahead of the model_output step — tool-first, the opposite of the legacy\n // (text-step-always-first) shape below.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const ordered = outcome.ordered;\n hasToolCalls = outcome.hasToolCalls;\n for (const block of ordered) {\n if (block.type === \"text\") {\n steps.push({ type: \"model_output\", content: [{ type: \"text\", text: block.text }] });\n outputText += block.text;\n } else {\n steps.push(\n buildFunctionCallStep(\n { name: block.name, arguments: block.arguments, id: block.id },\n logger,\n ),\n );\n }\n }\n } else {\n // LEGACY PATH: a single text step first, then function_call steps —\n // unchanged from the pre-blocks behavior (text always leads `steps`).\n steps.push({ type: \"model_output\", content: [{ type: \"text\", text: content }] });\n outputText = content;\n for (const tc of toolCalls) {\n steps.push(buildFunctionCallStep(tc, logger));\n }\n }\n\n return {\n id: interactionId,\n status: hasToolCalls ? \"requires_action\" : \"completed\",\n model: overrides?.model ?? model,\n role: \"model\",\n output_text: outputText,\n steps,\n usage: interactionsUsage(overrides),\n };\n}\n\nfunction buildInteractionsErrorResponse(message: string, code?: string): object {\n return {\n error: {\n code: code ?? \"INVALID_ARGUMENT\",\n message,\n },\n };\n}\n\n// ─── SSE event builders ──────────────────────────────────────────────────\n\ninterface InteractionsSSEEvent {\n event_type: string;\n [key: string]: unknown;\n}\n\nlet eventIdCounter = 0;\n\nexport function resetEventIdCounter(): void {\n eventIdCounter = 0;\n}\n\nfunction nextEventId(): string {\n return `evt_${++eventIdCounter}`;\n}\n\nexport function buildInteractionsTextSSEEvents(\n content: string,\n interactionId: string,\n chunkSize: number,\n overrides?: ResponseOverrides,\n): InteractionsSSEEvent[] {\n const events: InteractionsSSEEvent[] = [];\n\n // interaction.created\n events.push({\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n });\n\n // step.start — text step is the model_output\n events.push({\n event_type: \"step.start\",\n index: 0,\n step: { type: \"model_output\" },\n event_id: nextEventId(),\n });\n\n // step.delta(s) — inner delta shape is unchanged ({ type: \"text\", text })\n if (content.length === 0) {\n events.push({\n event_type: \"step.delta\",\n index: 0,\n delta: { type: \"text\", text: \"\" },\n event_id: nextEventId(),\n });\n } else {\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n event_type: \"step.delta\",\n index: 0,\n delta: { type: \"text\", text: slice },\n event_id: nextEventId(),\n });\n }\n }\n\n // step.stop\n events.push({\n event_type: \"step.stop\",\n index: 0,\n event_id: nextEventId(),\n });\n\n // interaction.completed\n events.push({\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: \"completed\",\n usage: interactionsUsage(overrides),\n },\n event_id: nextEventId(),\n });\n\n return events;\n}\n\nexport function buildInteractionsToolCallSSEEvents(\n toolCalls: ToolCall[],\n interactionId: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n): InteractionsSSEEvent[] {\n const events: InteractionsSSEEvent[] = [];\n\n // interaction.created\n events.push({\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n });\n\n // Each tool call gets its own step.start/delta/stop bracket. In SDK 2.x the\n // call identity (id, name) lives on step.start; the arguments stream as a\n // dedicated `arguments_delta` carrying a JSON-string fragment, and step.start\n // carries an empty `arguments: {}` placeholder.\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const args = servedToolArgs(tc, \"string\", logger);\n\n events.push({\n event_type: \"step.start\",\n index: idx,\n step: {\n type: \"function_call\",\n id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: {},\n },\n event_id: nextEventId(),\n });\n\n // arguments_delta.arguments is a string fragment. The real SDK may split\n // the args across several fragments that concatenate into valid JSON; the\n // mock emits the whole serialized object as one fragment (a valid\n // degenerate case the collapser handles identically).\n events.push({\n event_type: \"step.delta\",\n index: idx,\n delta: {\n type: \"arguments_delta\",\n arguments: args.text,\n },\n event_id: nextEventId(),\n });\n\n events.push({\n event_type: \"step.stop\",\n index: idx,\n event_id: nextEventId(),\n });\n }\n\n // interaction.completed\n events.push({\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: \"requires_action\",\n usage: interactionsUsage(overrides),\n },\n event_id: nextEventId(),\n });\n\n return events;\n}\n\n// Emit the step.start/delta(s)/stop bracket for a text (model_output) step at\n// a given step `index`. Inner delta shape ({ type: \"text\", text }) and the\n// empty-content single-empty-delta behavior are unchanged from the legacy path.\nfunction pushTextStepEvents(\n events: InteractionsSSEEvent[],\n index: number,\n content: string,\n chunkSize: number,\n): void {\n events.push({\n event_type: \"step.start\",\n index,\n step: { type: \"model_output\" },\n event_id: nextEventId(),\n });\n\n if (content.length === 0) {\n events.push({\n event_type: \"step.delta\",\n index,\n delta: { type: \"text\", text: \"\" },\n event_id: nextEventId(),\n });\n } else {\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n event_type: \"step.delta\",\n index,\n delta: { type: \"text\", text: slice },\n event_id: nextEventId(),\n });\n }\n }\n\n events.push({\n event_type: \"step.stop\",\n index,\n event_id: nextEventId(),\n });\n}\n\n// Emit the step.start/arguments_delta/stop bracket for a function_call step at\n// a given step `index`. Identity (id, name) lives on step.start with an empty\n// `arguments: {}` placeholder; the arguments stream as a single\n// `arguments_delta` JSON-string fragment — unchanged from the legacy path.\nfunction pushFunctionCallStepEvents(\n events: InteractionsSSEEvent[],\n index: number,\n tc: ToolCall,\n logger: Logger,\n): void {\n const args = servedToolArgs(tc, \"string\", logger);\n\n events.push({\n event_type: \"step.start\",\n index,\n step: {\n type: \"function_call\",\n id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: {},\n },\n event_id: nextEventId(),\n });\n\n events.push({\n event_type: \"step.delta\",\n index,\n delta: {\n type: \"arguments_delta\",\n arguments: args.text,\n },\n event_id: nextEventId(),\n });\n\n events.push({\n event_type: \"step.stop\",\n index,\n event_id: nextEventId(),\n });\n}\n\nexport function buildInteractionsContentWithToolCallsSSEEvents(\n content: string,\n toolCalls: ToolCall[],\n interactionId: string,\n chunkSize: number,\n logger: Logger,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): InteractionsSSEEvent[] {\n const events: InteractionsSSEEvent[] = [];\n\n // interaction.created\n events.push({\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n });\n\n let hasToolCalls = true;\n if (blocks && blocks.length > 0) {\n // NEW PATH: stream one step per block in fixture ARRAY ORDER. The step\n // `index` increments with array position, so a toolCall block before a text\n // block yields a function_call step at a LOWER index than the model_output\n // step — tool-first, the opposite of the legacy (text-at-index-0) shape.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const ordered = outcome.ordered;\n hasToolCalls = outcome.hasToolCalls;\n let idx = 0;\n for (const block of ordered) {\n if (block.type === \"text\") {\n pushTextStepEvents(events, idx, block.text, chunkSize);\n } else {\n pushFunctionCallStepEvents(\n events,\n idx,\n {\n name: block.name,\n arguments: block.arguments,\n id: block.id,\n },\n logger,\n );\n }\n idx += 1;\n }\n } else {\n // LEGACY PATH: text content at index 0 (model_output step), tool calls at\n // index 1+ — byte-for-byte unchanged from the pre-blocks behavior.\n pushTextStepEvents(events, 0, content, chunkSize);\n for (let i = 0; i < toolCalls.length; i++) {\n pushFunctionCallStepEvents(events, i + 1, toolCalls[i], logger);\n }\n }\n\n // interaction.completed\n events.push({\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: hasToolCalls ? \"requires_action\" : \"completed\",\n usage: interactionsUsage(overrides),\n },\n event_id: nextEventId(),\n });\n\n return events;\n}\n\n// ─── SSE writer for Interactions streaming ────────────────────────────────\n\ninterface InteractionsStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nexport async function writeGeminiInteractionsSSEStream(\n res: http.ServerResponse,\n events: InteractionsSSEEvent[],\n optionsOrLatency?: number | InteractionsStreamOptions,\n): Promise<boolean> {\n const opts: InteractionsStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n // Data-only SSE (no event: prefix, no [DONE])\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n // Only count step deltas for truncateAfterChunks — framing events\n // (interaction.created, step.start, step.stop, interaction.completed)\n // should not consume chunk budget or trigger the chunk-sent callback.\n if (event.event_type === \"step.delta\") {\n onChunkSent?.();\n chunkIndex++;\n }\n if (signal?.aborted) return false;\n }\n\n if (!res.writableEnded) {\n res.end();\n }\n return true;\n}\n\n// ─── Request handler ──────────────────────────────────────────────────────\n\nfunction prepareInteractionsMisbehavior(\n plan: MisbehaviorPlan,\n streaming: boolean,\n): MisbehaviorPlan {\n if (!streaming && plan.summary.fault === \"stop-length-mid-tool\") {\n // The object wire cannot represent the selected partial argument string.\n // Earlier completed calls/text survive; omit the cut call before allocating\n // IDs and preparing servedToolCalls/usage.\n const response = plan.response;\n const combined = isCombinedFixtureResponse(response);\n const outcome =\n combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : undefined;\n const calls =\n outcome?.toolCalls ??\n (combined || isToolCallResponse(response) ? (response.toolCalls ?? []) : []);\n const toolCalls = calls.filter((_, index) => index !== plan.target?.index);\n let callIndex = 0;\n const blocks = outcome?.ordered.filter(\n (block) => block.type === \"text\" || callIndex++ !== plan.target?.index,\n );\n plan = { ...plan, response: { ...response, toolCalls, ...(blocks ? { blocks } : {}) } };\n }\n // Both modes always emit IDs. The shared preparation preserves effective\n // block order and allocates each wire/journal identity exactly once.\n return prepareOpenAIChatMisbehavior(plan);\n}\n\nfunction finalizeInteractionsMisbehavior(\n events: InteractionsSSEEvent[],\n plan: MisbehaviorPlan | MisbehaviorSkip,\n): InteractionsSSEEvent[] {\n if (plan.kind !== \"applied\" || plan.summary.fault !== \"stop-length-mid-tool\") return events;\n // Approved modeled K5 contract: keep the cut arguments and step.stop, then\n // terminate incomplete. Native truncated-tool closure remains unverified.\n return events.map((event) =>\n event.event_type === \"interaction.completed\" && isJsonObject(event.interaction)\n ? { ...event, interaction: { ...event.interaction, status: \"incomplete\" } }\n : event,\n );\n}\n\nexport async function handleGeminiInteractions(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const { logger } = defaults;\n setCorsHeaders(res);\n\n const urlPath = req.url ?? \"/v1beta/interactions\";\n\n let interactionsReq: InteractionsRequest;\n try {\n interactionsReq = JSON.parse(raw) as InteractionsRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify(\n buildInteractionsErrorResponse(`Malformed JSON body: ${detail}`, \"INVALID_ARGUMENT\"),\n ),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `interactionsReq.stream` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(interactionsReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify(\n buildInteractionsErrorResponse(\"Request body must be a JSON object\", \"INVALID_ARGUMENT\"),\n ),\n );\n return;\n }\n\n const validationError =\n validateInteractionsInput(interactionsReq.input) ??\n validateInteractionsTools(interactionsReq.tools);\n if (validationError) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify(buildInteractionsErrorResponse(validationError, \"INVALID_ARGUMENT\")),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = geminiInteractionsToCompletionRequest(interactionsReq);\n // Keep \"chat\" rather than \"gemini-interactions\" — the router's endpoint\n // compatibility filter (router.ts) treats \"chat\" as a pass-through that\n // matches any unendpointed fixture. Switching to \"gemini-interactions\"\n // would make the request fall into the multimedia guard branch, preventing\n // generic chat fixtures from matching and breaking existing users. The\n // recorder would also start emitting `endpoint: \"gemini-interactions\"` in\n // recorded fixtures, creating a one-way compatibility break.\n completionReq._endpointType = \"chat\";\n completionReq._context = getContext(req);\n\n const streaming = interactionsReq.stream !== false; // default true\n const model = completionReq.model;\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(strictNoMatchLogLine(req.method ?? \"POST\", urlPath, skippedBySequenceOrTurn));\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify(buildInteractionsErrorResponse(strictMessage, \"UNAVAILABLE\")),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"gemini-interactions\",\n urlPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: res.statusCode ?? 200,\n fixture: null,\n source: \"proxy\",\n },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify(buildInteractionsErrorResponse(\"No fixture matched\", \"NOT_FOUND\")),\n );\n return;\n }\n\n let response = await resolveResponse(fixture, completionReq);\n let misbehavior = planMisbehavior({\n wire: \"gemini-interactions\",\n fixture,\n response,\n request: completionReq,\n stream: streaming,\n emitsToolCallIds: true,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n });\n if (misbehavior.kind === \"error\") {\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: misbehavior.status, fixture },\n });\n recordMisbehaviorOutcome({ entry, summary: misbehavior.summary, defaults, testId });\n if (!misbehavior.summary?.evaluations.some((evaluation) => evaluation.outcome === \"error\")) {\n logger.error(`${req.method ?? \"POST\"} ${urlPath}: ${misbehavior.message}`);\n }\n writeErrorResponse(\n res,\n misbehavior.status,\n JSON.stringify(buildInteractionsErrorResponse(misbehavior.message, misbehavior.code)),\n );\n return;\n }\n if (misbehavior.kind === \"applied\") {\n misbehavior = prepareInteractionsMisbehavior(misbehavior, streaming);\n response = misbehavior.response;\n }\n const appliedUsage =\n misbehavior.kind === \"applied\"\n ? resolveOpenAIChatMisbehaviorUsage(misbehavior, completionReq)\n : undefined;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n writeErrorResponse(\n res,\n status,\n JSON.stringify(\n buildInteractionsErrorResponse(response.error.message, response.error.type ?? \"ERROR\"),\n ),\n { retryAfter: response.retryAfter },\n );\n return;\n }\n\n // The content+tool and tool-call branches draw their interaction id after\n // requireEmittedFunctionToolCalls, so a fixture it rejects (a custom tool\n // call or a malformed toolCalls entry) consumes no id. A rejection raised\n // later, inside a builder, comes after the draw and does consume an id:\n // invalid JSON arguments on the non-streaming path, or a malformed block\n // from resolveFixtureBlockOutcome (the streaming path has also consumed\n // event ids by then).\n\n if (misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"reasoning-only\") {\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n // Reasoning-only output carries no tool call, so it has no tool-call check\n // to pass before drawing its id.\n const interactionId = nextInteractionId();\n const usage = {\n ...interactionsUsage({ usage: appliedUsage }),\n total_output_tokens: 0,\n total_thought_tokens: appliedUsage?.completion_tokens ?? 0,\n };\n if (!streaming) {\n const overrides =\n isTextResponse(response) ||\n isToolCallResponse(response) ||\n isCombinedFixtureResponse(response)\n ? extractOverrides(response)\n : undefined;\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n id: interactionId,\n model: overrides?.model ?? model,\n status: \"incomplete\",\n steps: [\n {\n type: \"thought\",\n signature: \"\",\n summary: [{ type: \"text\", text: misbehavior.reasoning ?? \"\" }],\n },\n ],\n usage,\n }),\n );\n return;\n }\n const events: InteractionsSSEEvent[] = [\n {\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n },\n { event_type: \"step.start\", index: 0, step: { type: \"thought\" }, event_id: nextEventId() },\n {\n event_type: \"step.delta\",\n index: 0,\n delta: {\n type: \"thought_summary\",\n content: { type: \"text\", text: misbehavior.reasoning ?? \"\" },\n },\n event_id: nextEventId(),\n },\n { event_type: \"step.stop\", index: 0, event_id: nextEventId() },\n {\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: \"incomplete\",\n usage,\n },\n event_id: nextEventId(),\n },\n ];\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n return;\n }\n\n // Content + tool calls response\n if (isCombinedFixtureResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Gemini Interactions API — ignoring\",\n );\n }\n const overrides = {\n ...extractOverrides(response),\n ...(appliedUsage ? { usage: appliedUsage } : {}),\n };\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, \"Gemini Interactions\");\n const interactionId = nextInteractionId();\n if (!streaming) {\n const body = buildInteractionsContentWithToolCallsResponse(\n response.content ?? \"\",\n functionToolCalls,\n model,\n interactionId,\n logger,\n overrides,\n response.blocks,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"stop-length-mid-tool\"\n ? { ...body, status: \"incomplete\" }\n : body,\n ),\n );\n } else {\n const events = buildInteractionsContentWithToolCallsSSEEvents(\n response.content ?? \"\",\n functionToolCalls,\n interactionId,\n chunkSize,\n logger,\n overrides,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(\n res,\n finalizeInteractionsMisbehavior(events, misbehavior),\n {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n },\n );\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Gemini Interactions API — ignoring\",\n );\n }\n const overrides = {\n ...extractOverrides(response),\n ...(appliedUsage ? { usage: appliedUsage } : {}),\n };\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const interactionId = nextInteractionId();\n if (!streaming) {\n const body = buildInteractionsTextResponse(response.content, model, interactionId, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"stop-length-mid-tool\"\n ? { ...body, status: \"incomplete\" }\n : body,\n ),\n );\n } else {\n const events = buildInteractionsTextSSEEvents(\n response.content,\n interactionId,\n chunkSize,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(\n res,\n finalizeInteractionsMisbehavior(events, misbehavior),\n {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n },\n );\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Gemini Interactions API — ignoring\",\n );\n }\n const overrides = {\n ...extractOverrides(response),\n ...(appliedUsage ? { usage: appliedUsage } : {}),\n };\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, \"Gemini Interactions\");\n const interactionId = nextInteractionId();\n if (!streaming) {\n const body = buildInteractionsToolCallResponse(\n functionToolCalls,\n model,\n interactionId,\n logger,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"stop-length-mid-tool\"\n ? { ...body, status: \"incomplete\" }\n : body,\n ),\n );\n } else {\n const events = buildInteractionsToolCallSSEEvents(\n functionToolCalls,\n interactionId,\n logger,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(\n res,\n finalizeInteractionsMisbehavior(events, misbehavior),\n {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n },\n );\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Unknown response type\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n recordMisbehaviorOutcome({ entry: journalEntry, summary: misbehavior.summary, defaults, testId });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify(\n buildInteractionsErrorResponse(\"Fixture response did not match any known type\", \"INTERNAL\"),\n ),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gemini-interactions.cjs","names":["isJsonObject","generateToolCallId","renderInteractionsUsage","servedToolArgs","resolveFixtureBlockOutcome","calculateDelay","delay","isCombinedFixtureResponse","isToolCallResponse","prepareOpenAIChatMisbehavior","flattenHeaders","renderError","getContext","getTestId","matchFixtureDiagnostic","applyChaosAsync","resolveRequestDecisions","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","planMisbehavior","resolveOpenAIChatMisbehaviorUsage","isErrorResponse","isTextResponse","extractOverrides","createInterruptionSignal","requireEmittedFunctionToolCalls"],"sources":["../src/gemini-interactions.ts"],"sourcesContent":["/**\n * Google Gemini Interactions API support.\n *\n * Translates incoming Interactions requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back\n * into the Gemini Interactions format — either a single JSON response or\n * an SSE stream with event_type-based framing.\n */\nimport { resolveRequestDecisions, strictOverrideField } from \"./response/policy.js\";\nimport { renderError } from \"./response/errors.js\";\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n FixtureBlock,\n HandlerDefaults,\n RecordedTimings,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n requireEmittedFunctionToolCalls,\n isTextResponse,\n isToolCallResponse,\n isCombinedFixtureResponse,\n isErrorResponse,\n extractOverrides,\n generateToolCallId,\n flattenHeaders,\n isJsonObject,\n getTestId,\n getContext,\n resolveResponse,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n resolveFixtureBlockOutcome,\n servedToolArgs,\n prepareOpenAIChatMisbehavior,\n resolveOpenAIChatMisbehaviorUsage,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { render as renderInteractionsUsage } from \"./response/usage/codecs/interactions.js\";\nimport {\n planMisbehavior,\n recordMisbehaviorOutcome,\n type MisbehaviorPlan,\n type MisbehaviorSkip,\n} from \"./misbehavior.js\";\n\n// ─── Interactions request types ────────────────────────────────────────────\n\ninterface InteractionsContentBlock {\n type: string;\n text?: string;\n name?: string;\n call_id?: string;\n id?: string;\n arguments?: Record<string, unknown>;\n output?: unknown;\n result?: unknown;\n}\n\ninterface InteractionsTurn {\n role: string;\n content?: InteractionsContentBlock[];\n parts?: InteractionsContentBlock[];\n}\n\n/**\n * Top-level Step envelope accepted by the live Gemini Interactions API.\n * The SDK's TypeScript union does not include Step[], but the wire contract\n * does — clients following the live API send these at the top level of `input`.\n * Discriminated by `type`; no `role` field (distinguishes from Turn[]).\n */\ninterface InteractionsStep {\n type: string;\n content?: InteractionsContentBlock[];\n call_id?: string;\n id?: string;\n name?: string;\n result?: unknown;\n output?: unknown;\n is_error?: boolean;\n signature?: string;\n}\n\n/** Step types whose payload is a tool/agent result keyed by call_id. */\nconst STEP_RESULT_TYPES = new Set<string>([\n \"function_result\",\n \"code_execution_result\",\n \"url_context_result\",\n \"google_search_result\",\n \"google_maps_result\",\n \"mcp_server_tool_result\",\n \"file_search_result\",\n]);\n\n/** All recognized top-level Step types (used as the Step[] discriminator). */\nconst STEP_TYPES = new Set<string>([\"user_input\", \"model_output\", ...STEP_RESULT_TYPES]);\n\ninterface InteractionsFunctionTool {\n type: \"function\";\n name: string;\n description?: string;\n parameters?: object;\n}\n\ninterface InteractionsRequest {\n model?: string;\n input?: string | InteractionsTurn[] | InteractionsStep[] | InteractionsContentBlock[];\n system_instruction?: string;\n tools?: InteractionsFunctionTool[];\n generation_config?: {\n temperature?: number;\n max_output_tokens?: number;\n [key: string]: unknown;\n };\n stream?: boolean;\n previous_interaction_id?: string;\n [key: string]: unknown;\n}\n\n// Check unsupported numeric input and containers consumed by the selected variant.\n// Other values retain their existing normalization, including omitted input.\nfunction validateInteractionsInput(input: unknown): string | null {\n if (typeof input === \"number\") return \"input must not be a number\";\n if (!Array.isArray(input)) return null;\n const first = input[0];\n if (isJsonObject(first) && \"role\" in first) {\n for (const [index, turn] of input.entries()) {\n if (!isJsonObject(turn)) continue;\n const blocks = turn.content ?? turn.parts;\n // Empty strings, falsy values and empty arrays bypass the converter's\n // filters. Preserve that behavior and the content ?? parts selection.\n if (typeof blocks === \"string\" && blocks.length > 0) {\n const field = turn.content != null ? \"content\" : \"parts\";\n return `input[${index}].${field} must be an array`;\n }\n }\n } else if (\n !(isJsonObject(first) && typeof first.type === \"string\" && STEP_TYPES.has(first.type))\n ) {\n const nullIndex = input.findIndex((part) => part === null);\n if (nullIndex !== -1) return `input[${nullIndex}] must be an object`;\n }\n return null;\n}\n\n// Preserve tools that the converter ignores; reject only these unsafe reads.\nfunction validateInteractionsTools(tools: unknown): string | null {\n if (typeof tools === \"string\" && tools.length > 0) return \"tools must be an array\";\n if (Array.isArray(tools)) {\n const nullIndex = tools.findIndex((tool) => tool === null);\n if (nullIndex !== -1) return `tools[${nullIndex}] must be an object`;\n }\n return null;\n}\n\n// ─── Input conversion: Interactions → ChatCompletionRequest ───────────────\n\nexport function geminiInteractionsToCompletionRequest(\n req: InteractionsRequest,\n): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n const model = req.model ?? \"gemini-2.5-flash\";\n\n // system_instruction → system message\n if (req.system_instruction) {\n messages.push({ role: \"system\", content: req.system_instruction });\n }\n\n // Parse input\n if (req.input !== undefined) {\n if (typeof req.input === \"string\") {\n // Simple string input → single user message\n messages.push({ role: \"user\", content: req.input });\n } else if (Array.isArray(req.input)) {\n // Could be Turn[], Step[], or Content[]\n const firstItem = req.input[0] as\n | InteractionsTurn\n | InteractionsStep\n | InteractionsContentBlock\n | undefined;\n const isStepArray =\n !!firstItem &&\n !(\"role\" in firstItem) &&\n typeof firstItem.type === \"string\" &&\n STEP_TYPES.has(firstItem.type);\n\n if (firstItem && \"role\" in firstItem) {\n // Turn[] format\n for (const turn of req.input as InteractionsTurn[]) {\n const role = turn.role === \"model\" ? \"assistant\" : turn.role;\n const blocks = turn.content ?? turn.parts;\n if (!blocks || blocks.length === 0) {\n if (role === \"user\" || role === \"assistant\") {\n messages.push({ role: role as \"user\" | \"assistant\", content: \"\" });\n }\n continue;\n }\n\n // Check for function_call or function_result parts\n const funcCallParts = blocks.filter((p) => p.type === \"function_call\");\n const funcResultParts = blocks.filter((p) => p.type === \"function_result\");\n const textParts = blocks.filter((p) => p.type === \"text\");\n\n if (funcCallParts.length > 0) {\n // Assistant tool call message\n const textContent = textParts.map((p) => p.text ?? \"\").join(\"\");\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: funcCallParts.map((p) => ({\n id: p.id ?? p.call_id ?? generateToolCallId(),\n type: \"function\" as const,\n function: {\n name: p.name ?? \"\",\n arguments: JSON.stringify(p.arguments ?? {}),\n },\n })),\n });\n } else if (funcResultParts.length > 0) {\n // Tool response messages\n for (const part of funcResultParts) {\n const resultValue = part.result ?? part.output;\n messages.push({\n role: \"tool\",\n content:\n typeof resultValue === \"string\" ? resultValue : JSON.stringify(resultValue ?? \"\"),\n tool_call_id: part.call_id ?? part.id ?? \"\",\n });\n }\n // Any text parts alongside → separate user message\n if (textParts.length > 0) {\n const text = textParts.map((p) => p.text ?? \"\").join(\"\");\n if (text) {\n messages.push({ role: \"user\", content: text });\n }\n }\n } else {\n // Text-only turn\n const text = textParts.map((p) => p.text ?? \"\").join(\"\");\n if (role === \"user\" || role === \"assistant\" || role === \"system\") {\n messages.push({\n role: role as \"user\" | \"assistant\" | \"system\",\n content: text,\n });\n }\n }\n }\n } else if (isStepArray) {\n // Step[] format — the wire contract Google's /v1beta/interactions accepts.\n for (const step of req.input as InteractionsStep[]) {\n if (step.type === \"user_input\") {\n const text = (step.content ?? [])\n .filter((p) => p.type === \"text\")\n .map((p) => p.text ?? \"\")\n .join(\"\");\n messages.push({ role: \"user\", content: text });\n } else if (step.type === \"model_output\") {\n const blocks = step.content ?? [];\n const funcCallParts = blocks.filter((p) => p.type === \"function_call\");\n const textParts = blocks.filter((p) => p.type === \"text\");\n const textContent = textParts.map((p) => p.text ?? \"\").join(\"\");\n\n if (funcCallParts.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: funcCallParts.map((p) => ({\n id: p.id ?? p.call_id ?? generateToolCallId(),\n type: \"function\" as const,\n function: {\n name: p.name ?? \"\",\n arguments: JSON.stringify(p.arguments ?? {}),\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent });\n }\n } else if (STEP_RESULT_TYPES.has(step.type)) {\n const resultValue = step.result ?? step.output;\n messages.push({\n role: \"tool\",\n content:\n typeof resultValue === \"string\" ? resultValue : JSON.stringify(resultValue ?? \"\"),\n tool_call_id: step.call_id ?? step.id ?? \"\",\n });\n }\n }\n } else {\n // Content[] format — single user message with content blocks\n const textParts = (req.input as InteractionsContentBlock[]).filter(\n (p) => p.type === \"text\",\n );\n const text = textParts.map((p) => p.text ?? \"\").join(\"\");\n messages.push({ role: \"user\", content: text || \"\" });\n }\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n const funcTools = req.tools.filter((t) => t.type === \"function\");\n if (funcTools.length > 0) {\n tools = funcTools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n },\n }));\n }\n }\n\n return {\n model,\n messages,\n stream: req.stream !== false, // default true\n temperature: req.generation_config?.temperature,\n max_tokens: req.generation_config?.max_output_tokens,\n tools,\n };\n}\n\n// ─── Interaction ID generation ────────────────────────────────────────────\n\nlet interactionCounter = 0;\n\nexport function resetInteractionCounter(): void {\n interactionCounter = 0;\n}\n\nfunction nextInteractionId(): string {\n return `aimock-int-${interactionCounter++}`;\n}\n\n// ─── Usage helpers ────────────────────────────────────────────────────────\n\nfunction interactionsUsage(overrides?: ResponseOverrides): {\n total_input_tokens: number;\n total_output_tokens: number;\n total_tokens: number;\n} {\n return renderInteractionsUsage(overrides);\n}\n\n// ─── Response building: fixture → Interactions format ─────────────────────\n\nexport function buildInteractionsTextResponse(\n content: string,\n model: string,\n interactionId: string,\n overrides?: ResponseOverrides,\n): object {\n return {\n id: interactionId,\n status: \"completed\",\n model: overrides?.model ?? model,\n role: \"model\",\n output_text: content,\n steps: [{ type: \"model_output\", content: [{ type: \"text\", text: content }] }],\n usage: interactionsUsage(overrides),\n };\n}\n\n// Build a single SDK 2.x function_call step from a fixture tool call,\n// serving malformed arguments as `{}` (or rejecting them under strictToolArguments).\nfunction buildFunctionCallStep(tc: ToolCall, logger: Logger): object {\n const args = servedToolArgs(tc, \"object\", logger);\n return {\n type: \"function_call\",\n id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: args.value,\n };\n}\n\nexport function buildInteractionsToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n interactionId: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n): object {\n return {\n id: interactionId,\n status: \"requires_action\",\n model: overrides?.model ?? model,\n role: \"model\",\n steps: toolCalls.map((tc) => buildFunctionCallStep(tc, logger)),\n usage: interactionsUsage(overrides),\n };\n}\n\nexport function buildInteractionsContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n interactionId: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): object {\n const steps: object[] = [];\n // Collect output_text in step order so the top-level field mirrors the\n // concatenated text steps regardless of where they appear in `steps`.\n let outputText = \"\";\n\n let hasToolCalls = true;\n if (blocks && blocks.length > 0) {\n // NEW PATH: the non-stream `steps[]` array is index/step-addressed and\n // ordered, so emit one step per block in fixture ARRAY ORDER. A toolCall\n // block placed before a text block therefore yields a function_call step\n // ahead of the model_output step — tool-first, the opposite of the legacy\n // (text-step-always-first) shape below.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const ordered = outcome.ordered;\n hasToolCalls = outcome.hasToolCalls;\n for (const block of ordered) {\n if (block.type === \"text\") {\n steps.push({ type: \"model_output\", content: [{ type: \"text\", text: block.text }] });\n outputText += block.text;\n } else {\n steps.push(\n buildFunctionCallStep(\n { name: block.name, arguments: block.arguments, id: block.id },\n logger,\n ),\n );\n }\n }\n } else {\n // LEGACY PATH: a single text step first, then function_call steps —\n // unchanged from the pre-blocks behavior (text always leads `steps`).\n steps.push({ type: \"model_output\", content: [{ type: \"text\", text: content }] });\n outputText = content;\n for (const tc of toolCalls) {\n steps.push(buildFunctionCallStep(tc, logger));\n }\n }\n\n return {\n id: interactionId,\n status: hasToolCalls ? \"requires_action\" : \"completed\",\n model: overrides?.model ?? model,\n role: \"model\",\n output_text: outputText,\n steps,\n usage: interactionsUsage(overrides),\n };\n}\n\n// ─── SSE event builders ──────────────────────────────────────────────────\n\ninterface InteractionsSSEEvent {\n event_type: string;\n [key: string]: unknown;\n}\n\nlet eventIdCounter = 0;\n\nexport function resetEventIdCounter(): void {\n eventIdCounter = 0;\n}\n\nfunction nextEventId(): string {\n return `evt_${++eventIdCounter}`;\n}\n\nexport function buildInteractionsTextSSEEvents(\n content: string,\n interactionId: string,\n chunkSize: number,\n overrides?: ResponseOverrides,\n): InteractionsSSEEvent[] {\n const events: InteractionsSSEEvent[] = [];\n\n // interaction.created\n events.push({\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n });\n\n // step.start — text step is the model_output\n events.push({\n event_type: \"step.start\",\n index: 0,\n step: { type: \"model_output\" },\n event_id: nextEventId(),\n });\n\n // step.delta(s) — inner delta shape is unchanged ({ type: \"text\", text })\n if (content.length === 0) {\n events.push({\n event_type: \"step.delta\",\n index: 0,\n delta: { type: \"text\", text: \"\" },\n event_id: nextEventId(),\n });\n } else {\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n event_type: \"step.delta\",\n index: 0,\n delta: { type: \"text\", text: slice },\n event_id: nextEventId(),\n });\n }\n }\n\n // step.stop\n events.push({\n event_type: \"step.stop\",\n index: 0,\n event_id: nextEventId(),\n });\n\n // interaction.completed\n events.push({\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: \"completed\",\n usage: interactionsUsage(overrides),\n },\n event_id: nextEventId(),\n });\n\n return events;\n}\n\nexport function buildInteractionsToolCallSSEEvents(\n toolCalls: ToolCall[],\n interactionId: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n): InteractionsSSEEvent[] {\n const events: InteractionsSSEEvent[] = [];\n\n // interaction.created\n events.push({\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n });\n\n // Each tool call gets its own step.start/delta/stop bracket. In SDK 2.x the\n // call identity (id, name) lives on step.start; the arguments stream as a\n // dedicated `arguments_delta` carrying a JSON-string fragment, and step.start\n // carries an empty `arguments: {}` placeholder.\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const args = servedToolArgs(tc, \"string\", logger);\n\n events.push({\n event_type: \"step.start\",\n index: idx,\n step: {\n type: \"function_call\",\n id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: {},\n },\n event_id: nextEventId(),\n });\n\n // arguments_delta.arguments is a string fragment. The real SDK may split\n // the args across several fragments that concatenate into valid JSON; the\n // mock emits the whole serialized object as one fragment (a valid\n // degenerate case the collapser handles identically).\n events.push({\n event_type: \"step.delta\",\n index: idx,\n delta: {\n type: \"arguments_delta\",\n arguments: args.text,\n },\n event_id: nextEventId(),\n });\n\n events.push({\n event_type: \"step.stop\",\n index: idx,\n event_id: nextEventId(),\n });\n }\n\n // interaction.completed\n events.push({\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: \"requires_action\",\n usage: interactionsUsage(overrides),\n },\n event_id: nextEventId(),\n });\n\n return events;\n}\n\n// Emit the step.start/delta(s)/stop bracket for a text (model_output) step at\n// a given step `index`. Inner delta shape ({ type: \"text\", text }) and the\n// empty-content single-empty-delta behavior are unchanged from the legacy path.\nfunction pushTextStepEvents(\n events: InteractionsSSEEvent[],\n index: number,\n content: string,\n chunkSize: number,\n): void {\n events.push({\n event_type: \"step.start\",\n index,\n step: { type: \"model_output\" },\n event_id: nextEventId(),\n });\n\n if (content.length === 0) {\n events.push({\n event_type: \"step.delta\",\n index,\n delta: { type: \"text\", text: \"\" },\n event_id: nextEventId(),\n });\n } else {\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n event_type: \"step.delta\",\n index,\n delta: { type: \"text\", text: slice },\n event_id: nextEventId(),\n });\n }\n }\n\n events.push({\n event_type: \"step.stop\",\n index,\n event_id: nextEventId(),\n });\n}\n\n// Emit the step.start/arguments_delta/stop bracket for a function_call step at\n// a given step `index`. Identity (id, name) lives on step.start with an empty\n// `arguments: {}` placeholder; the arguments stream as a single\n// `arguments_delta` JSON-string fragment — unchanged from the legacy path.\nfunction pushFunctionCallStepEvents(\n events: InteractionsSSEEvent[],\n index: number,\n tc: ToolCall,\n logger: Logger,\n): void {\n const args = servedToolArgs(tc, \"string\", logger);\n\n events.push({\n event_type: \"step.start\",\n index,\n step: {\n type: \"function_call\",\n id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: {},\n },\n event_id: nextEventId(),\n });\n\n events.push({\n event_type: \"step.delta\",\n index,\n delta: {\n type: \"arguments_delta\",\n arguments: args.text,\n },\n event_id: nextEventId(),\n });\n\n events.push({\n event_type: \"step.stop\",\n index,\n event_id: nextEventId(),\n });\n}\n\nexport function buildInteractionsContentWithToolCallsSSEEvents(\n content: string,\n toolCalls: ToolCall[],\n interactionId: string,\n chunkSize: number,\n logger: Logger,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): InteractionsSSEEvent[] {\n const events: InteractionsSSEEvent[] = [];\n\n // interaction.created\n events.push({\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n });\n\n let hasToolCalls = true;\n if (blocks && blocks.length > 0) {\n // NEW PATH: stream one step per block in fixture ARRAY ORDER. The step\n // `index` increments with array position, so a toolCall block before a text\n // block yields a function_call step at a LOWER index than the model_output\n // step — tool-first, the opposite of the legacy (text-at-index-0) shape.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const ordered = outcome.ordered;\n hasToolCalls = outcome.hasToolCalls;\n let idx = 0;\n for (const block of ordered) {\n if (block.type === \"text\") {\n pushTextStepEvents(events, idx, block.text, chunkSize);\n } else {\n pushFunctionCallStepEvents(\n events,\n idx,\n {\n name: block.name,\n arguments: block.arguments,\n id: block.id,\n },\n logger,\n );\n }\n idx += 1;\n }\n } else {\n // LEGACY PATH: text content at index 0 (model_output step), tool calls at\n // index 1+ — byte-for-byte unchanged from the pre-blocks behavior.\n pushTextStepEvents(events, 0, content, chunkSize);\n for (let i = 0; i < toolCalls.length; i++) {\n pushFunctionCallStepEvents(events, i + 1, toolCalls[i], logger);\n }\n }\n\n // interaction.completed\n events.push({\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: hasToolCalls ? \"requires_action\" : \"completed\",\n usage: interactionsUsage(overrides),\n },\n event_id: nextEventId(),\n });\n\n return events;\n}\n\n// ─── SSE writer for Interactions streaming ────────────────────────────────\n\ninterface InteractionsStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nexport async function writeGeminiInteractionsSSEStream(\n res: http.ServerResponse,\n events: InteractionsSSEEvent[],\n optionsOrLatency?: number | InteractionsStreamOptions,\n): Promise<boolean> {\n const opts: InteractionsStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n // Data-only SSE (no event: prefix, no [DONE])\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n // Only count step deltas for truncateAfterChunks — framing events\n // (interaction.created, step.start, step.stop, interaction.completed)\n // should not consume chunk budget or trigger the chunk-sent callback.\n if (event.event_type === \"step.delta\") {\n onChunkSent?.();\n chunkIndex++;\n }\n if (signal?.aborted) return false;\n }\n\n if (!res.writableEnded) {\n res.end();\n }\n return true;\n}\n\n// ─── Request handler ──────────────────────────────────────────────────────\n\nfunction prepareInteractionsMisbehavior(\n plan: MisbehaviorPlan,\n streaming: boolean,\n): MisbehaviorPlan {\n if (!streaming && plan.summary.fault === \"stop-length-mid-tool\") {\n // The object wire cannot represent the selected partial argument string.\n // Earlier completed calls/text survive; omit the cut call before allocating\n // IDs and preparing servedToolCalls/usage.\n const response = plan.response;\n const combined = isCombinedFixtureResponse(response);\n const outcome =\n combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : undefined;\n const calls =\n outcome?.toolCalls ??\n (combined || isToolCallResponse(response) ? (response.toolCalls ?? []) : []);\n const toolCalls = calls.filter((_, index) => index !== plan.target?.index);\n let callIndex = 0;\n const blocks = outcome?.ordered.filter(\n (block) => block.type === \"text\" || callIndex++ !== plan.target?.index,\n );\n plan = { ...plan, response: { ...response, toolCalls, ...(blocks ? { blocks } : {}) } };\n }\n // Both modes always emit IDs. The shared preparation preserves effective\n // block order and allocates each wire/journal identity exactly once.\n return prepareOpenAIChatMisbehavior(plan);\n}\n\nfunction finalizeInteractionsMisbehavior(\n events: InteractionsSSEEvent[],\n plan: MisbehaviorPlan | MisbehaviorSkip,\n): InteractionsSSEEvent[] {\n if (plan.kind !== \"applied\" || plan.summary.fault !== \"stop-length-mid-tool\") return events;\n // Approved modeled K5 contract: keep the cut arguments and step.stop, then\n // terminate incomplete. Native truncated-tool closure remains unverified.\n return events.map((event) =>\n event.event_type === \"interaction.completed\" && isJsonObject(event.interaction)\n ? { ...event, interaction: { ...event.interaction, status: \"incomplete\" } }\n : event,\n );\n}\n\nexport async function handleGeminiInteractions(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const { logger } = defaults;\n setCorsHeaders(res);\n\n const urlPath = req.url ?? \"/v1beta/interactions\";\n\n let interactionsReq: InteractionsRequest;\n try {\n interactionsReq = JSON.parse(raw) as InteractionsRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"interactions\", \"validation\", {\n message: `Malformed JSON body: ${detail}`,\n code: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `interactionsReq.stream` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(interactionsReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"interactions\", \"validation\", {\n message: \"Request body must be a JSON object\",\n code: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n const validationError =\n validateInteractionsInput(interactionsReq.input) ??\n validateInteractionsTools(interactionsReq.tools);\n if (validationError) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"interactions\", \"validation\", {\n message: validationError,\n code: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = geminiInteractionsToCompletionRequest(interactionsReq);\n // Keep \"chat\" rather than \"gemini-interactions\" — the router's endpoint\n // compatibility filter (router.ts) treats \"chat\" as a pass-through that\n // matches any unendpointed fixture. Switching to \"gemini-interactions\"\n // would make the request fall into the multimedia guard branch, preventing\n // generic chat fixtures from matching and breaking existing users. The\n // recorder would also start emitting `endpoint: \"gemini-interactions\"` in\n // recorded fixtures, creating a one-way compatibility break.\n completionReq._endpointType = \"chat\";\n completionReq._context = getContext(req);\n\n const streaming = interactionsReq.stream !== false; // default true\n const model = completionReq.model;\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const decisions = resolveRequestDecisions(defaults.strict, req.headers);\n if (decisions.fixtureMiss) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(strictNoMatchLogLine(req.method ?? \"POST\", urlPath, skippedBySequenceOrTurn));\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n renderError(\"interactions\", \"strict-miss\", {\n message: strictMessage,\n code: \"UNAVAILABLE\",\n }).body,\n );\n return;\n }\n if (decisions.upstream && defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"gemini-interactions\",\n urlPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: res.statusCode ?? 200,\n fixture: null,\n source: \"proxy\",\n },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n renderError(\"interactions\", \"fixture-miss\", {\n message: \"No fixture matched\",\n code: \"NOT_FOUND\",\n }).body,\n );\n return;\n }\n\n let response = await resolveResponse(fixture, completionReq);\n let misbehavior = planMisbehavior({\n wire: \"gemini-interactions\",\n fixture,\n response,\n request: completionReq,\n stream: streaming,\n emitsToolCallIds: true,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n });\n if (misbehavior.kind === \"error\") {\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: misbehavior.status, fixture },\n });\n recordMisbehaviorOutcome({ entry, summary: misbehavior.summary, defaults, testId });\n if (!misbehavior.summary?.evaluations.some((evaluation) => evaluation.outcome === \"error\")) {\n logger.error(`${req.method ?? \"POST\"} ${urlPath}: ${misbehavior.message}`);\n }\n writeErrorResponse(\n res,\n misbehavior.status,\n renderError(\"interactions\", \"misbehavior\", {\n message: misbehavior.message,\n code: misbehavior.code,\n }).body,\n );\n return;\n }\n if (misbehavior.kind === \"applied\") {\n misbehavior = prepareInteractionsMisbehavior(misbehavior, streaming);\n response = misbehavior.response;\n }\n const appliedUsage =\n misbehavior.kind === \"applied\"\n ? resolveOpenAIChatMisbehaviorUsage(misbehavior, completionReq)\n : undefined;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n writeErrorResponse(\n res,\n status,\n renderError(\"interactions\", \"fixture\", {\n message: response.error.message,\n code: response.error.type ?? \"ERROR\",\n }).body,\n { retryAfter: response.retryAfter },\n );\n return;\n }\n\n // The content+tool and tool-call branches draw their interaction id after\n // requireEmittedFunctionToolCalls, so a fixture it rejects (a custom tool\n // call or a malformed toolCalls entry) consumes no id. A rejection raised\n // later, inside a builder, comes after the draw and does consume an id:\n // invalid JSON arguments on the non-streaming path, or a malformed block\n // from resolveFixtureBlockOutcome (the streaming path has also consumed\n // event ids by then).\n\n if (misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"reasoning-only\") {\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n // Reasoning-only output carries no tool call, so it has no tool-call check\n // to pass before drawing its id.\n const interactionId = nextInteractionId();\n const usage = renderInteractionsUsage({ usage: appliedUsage }, \"applied-reasoning-only\");\n if (!streaming) {\n const overrides =\n isTextResponse(response) ||\n isToolCallResponse(response) ||\n isCombinedFixtureResponse(response)\n ? extractOverrides(response)\n : undefined;\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n id: interactionId,\n model: overrides?.model ?? model,\n status: \"incomplete\",\n steps: [\n {\n type: \"thought\",\n signature: \"\",\n summary: [{ type: \"text\", text: misbehavior.reasoning ?? \"\" }],\n },\n ],\n usage,\n }),\n );\n return;\n }\n const events: InteractionsSSEEvent[] = [\n {\n event_type: \"interaction.created\",\n interaction: { id: interactionId, status: \"in_progress\" },\n event_id: nextEventId(),\n },\n { event_type: \"step.start\", index: 0, step: { type: \"thought\" }, event_id: nextEventId() },\n {\n event_type: \"step.delta\",\n index: 0,\n delta: {\n type: \"thought_summary\",\n content: { type: \"text\", text: misbehavior.reasoning ?? \"\" },\n },\n event_id: nextEventId(),\n },\n { event_type: \"step.stop\", index: 0, event_id: nextEventId() },\n {\n event_type: \"interaction.completed\",\n interaction: {\n id: interactionId,\n status: \"incomplete\",\n usage,\n },\n event_id: nextEventId(),\n },\n ];\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n return;\n }\n\n // Content + tool calls response\n if (isCombinedFixtureResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Gemini Interactions API — ignoring\",\n );\n }\n const overrides = {\n ...extractOverrides(response),\n ...(appliedUsage ? { usage: appliedUsage } : {}),\n };\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, \"Gemini Interactions\");\n const interactionId = nextInteractionId();\n if (!streaming) {\n const body = buildInteractionsContentWithToolCallsResponse(\n response.content ?? \"\",\n functionToolCalls,\n model,\n interactionId,\n logger,\n overrides,\n response.blocks,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"stop-length-mid-tool\"\n ? { ...body, status: \"incomplete\" }\n : body,\n ),\n );\n } else {\n const events = buildInteractionsContentWithToolCallsSSEEvents(\n response.content ?? \"\",\n functionToolCalls,\n interactionId,\n chunkSize,\n logger,\n overrides,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(\n res,\n finalizeInteractionsMisbehavior(events, misbehavior),\n {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n },\n );\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Gemini Interactions API — ignoring\",\n );\n }\n const overrides = {\n ...extractOverrides(response),\n ...(appliedUsage ? { usage: appliedUsage } : {}),\n };\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const interactionId = nextInteractionId();\n if (!streaming) {\n const body = buildInteractionsTextResponse(response.content, model, interactionId, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"stop-length-mid-tool\"\n ? { ...body, status: \"incomplete\" }\n : body,\n ),\n );\n } else {\n const events = buildInteractionsTextSSEEvents(\n response.content,\n interactionId,\n chunkSize,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(\n res,\n finalizeInteractionsMisbehavior(events, misbehavior),\n {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n },\n );\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Gemini Interactions API — ignoring\",\n );\n }\n const overrides = {\n ...extractOverrides(response),\n ...(appliedUsage ? { usage: appliedUsage } : {}),\n };\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, \"Gemini Interactions\");\n const interactionId = nextInteractionId();\n if (!streaming) {\n const body = buildInteractionsToolCallResponse(\n functionToolCalls,\n model,\n interactionId,\n logger,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n misbehavior.kind === \"applied\" && misbehavior.summary.fault === \"stop-length-mid-tool\"\n ? { ...body, status: \"incomplete\" }\n : body,\n ),\n );\n } else {\n const events = buildInteractionsToolCallSSEEvents(\n functionToolCalls,\n interactionId,\n logger,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiInteractionsSSEStream(\n res,\n finalizeInteractionsMisbehavior(events, misbehavior),\n {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n },\n );\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Unknown response type\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n recordMisbehaviorOutcome({ entry: journalEntry, summary: misbehavior.summary, defaults, testId });\n writeErrorResponse(\n res,\n 500,\n renderError(\"interactions\", \"unknown-response\", {\n message: \"Fixture response did not match any known type\",\n code: \"INTERNAL\",\n }).body,\n );\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@ import { ChatCompletionRequest, Fixture, HandlerDefaults } from "./types.cjs";
3
3
  import * as http$1 from "node:http";
4
4
 
5
5
  //#region src/gemini-interactions.d.ts
6
-
7
6
  interface InteractionsContentBlock {
8
7
  type: string;
9
8
  text?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"gemini-interactions.d.cts","names":[],"sources":["../src/gemini-interactions.ts"],"sourcesContent":[],"mappings":";;;;;;AAqFoC,UAzB1B,wBAAA,CAiDwB;EAOxB,IAAA,EAAA,MAAA;EAAmB,IAAA,CAAA,EAAA,MAAA;MAEV,CAAA,EAAA,MAAA;SAAqB,CAAA,EAAA,MAAA;KAAqB,EAAA,MAAA;WAEnD,CAAA,EAtDI,MAsDJ,CAAA,MAAA,EAAA,OAAA,CAAA;EAAwB,MAAA,CAAA,EAAA,OAAA;EAiDlB,MAAA,CAAA,EAAA,OAAA;;UAlGN,gBAAA,CAmGH;MACJ,EAAA,MAAA;EAAqB,OAAA,CAAA,EAlGZ,wBAkGY,EAAA;EA6sBF,KAAA,CAAA,EA9yBZ,wBA8yBoC,EAAA;;;;;;;;UAryBpC,gBAAA,CA6yBP;EAAO,IAAA,EAAA,MAAA;YA3yBE;;;;;;;;;UAwBF,wBAAA;;;;;;UAOA,mBAAA;;mBAES,qBAAqB,qBAAqB;;UAEnD;;;;;;;;;;iBAiDM,qCAAA,MACT,sBACJ;iBA6sBmB,wBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
1
+ {"version":3,"file":"gemini-interactions.d.cts","names":[],"sources":["../src/gemini-interactions.ts"],"sourcesContent":[],"mappings":";;;;;UA6DU,wBAAA;EAAA,IAAA,EAAA,MAAA;EAWA,IAAA,CAAA,EAAA,MAAA;EAAgB,IAAA,CAAA,EAAA,MAAA;SAEd,CAAA,EAAA,MAAA;KACF,EAAA,MAAA;EAAwB,SAAA,CAAA,EARpB,MAQoB,CAAA,MAAA,EAAA,OAAA,CAAA;EASxB,MAAA,CAAA,EAAA,OAAA;EA0BA,MAAA,CAAA,EAAA,OAAA;AAAwB;UAtCxB,gBAAA,CA6CmB;MAEV,EAAA,MAAA;SAAqB,CAAA,EA7C5B,wBA6C4B,EAAA;OAAqB,CAAA,EA5CnD,wBA4CmD,EAAA;;;AAmD7D;;;;;AAsrBA,UA5wBU,gBAAA,CA4wBY;EAAwB,IAAA,EAAA,MAAA;SACvC,CAAA,EA3wBK,wBA2wBA,EAAA;SACL,CAAA,EAAK,MAAA;KAEA,EAAA,MAAA;MACD,CAAA,EAAA,MAAA;QACC,CAAA,EAAA,OAAA;QACY,CAAA,EAAA,OAAK;UAC1B,CAAA,EAAA,OAAA;EAAO,SAAA,CAAA,EAAA,MAAA;;UA1vBA,wBAAA;;;;;;UAOA,mBAAA;;mBAES,qBAAqB,qBAAqB;;UAEnD;;;;;;;;;;iBAiDM,qCAAA,MACT,sBACJ;iBAorBmB,wBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
@@ -3,7 +3,6 @@ import { ChatCompletionRequest, Fixture, HandlerDefaults } from "./types.js";
3
3
  import * as http$1 from "node:http";
4
4
 
5
5
  //#region src/gemini-interactions.d.ts
6
-
7
6
  interface InteractionsContentBlock {
8
7
  type: string;
9
8
  text?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"gemini-interactions.d.ts","names":[],"sources":["../src/gemini-interactions.ts"],"sourcesContent":[],"mappings":";;;;;;AAqFoC,UAzB1B,wBAAA,CAiDwB;EAOxB,IAAA,EAAA,MAAA;EAAmB,IAAA,CAAA,EAAA,MAAA;MAEV,CAAA,EAAA,MAAA;SAAqB,CAAA,EAAA,MAAA;KAAqB,EAAA,MAAA;WAEnD,CAAA,EAtDI,MAsDJ,CAAA,MAAA,EAAA,OAAA,CAAA;EAAwB,MAAA,CAAA,EAAA,OAAA;EAiDlB,MAAA,CAAA,EAAA,OAAA;;UAlGN,gBAAA,CAmGH;MACJ,EAAA,MAAA;EAAqB,OAAA,CAAA,EAlGZ,wBAkGY,EAAA;EA6sBF,KAAA,CAAA,EA9yBZ,wBA8yBoC,EAAA;;;;;;;;UAryBpC,gBAAA,CA6yBP;EAAO,IAAA,EAAA,MAAA;YA3yBE;;;;;;;;;UAwBF,wBAAA;;;;;;UAOA,mBAAA;;mBAES,qBAAqB,qBAAqB;;UAEnD;;;;;;;;;;iBAiDM,qCAAA,MACT,sBACJ;iBA6sBmB,wBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
1
+ {"version":3,"file":"gemini-interactions.d.ts","names":[],"sources":["../src/gemini-interactions.ts"],"sourcesContent":[],"mappings":";;;;;UA6DU,wBAAA;EAAA,IAAA,EAAA,MAAA;EAWA,IAAA,CAAA,EAAA,MAAA;EAAgB,IAAA,CAAA,EAAA,MAAA;SAEd,CAAA,EAAA,MAAA;KACF,EAAA,MAAA;EAAwB,SAAA,CAAA,EARpB,MAQoB,CAAA,MAAA,EAAA,OAAA,CAAA;EASxB,MAAA,CAAA,EAAA,OAAA;EA0BA,MAAA,CAAA,EAAA,OAAA;AAAwB;UAtCxB,gBAAA,CA6CmB;MAEV,EAAA,MAAA;SAAqB,CAAA,EA7C5B,wBA6C4B,EAAA;OAAqB,CAAA,EA5CnD,wBA4CmD,EAAA;;;AAmD7D;;;;;AAsrBA,UA5wBU,gBAAA,CA4wBY;EAAwB,IAAA,EAAA,MAAA;SACvC,CAAA,EA3wBK,wBA2wBA,EAAA;SACL,CAAA,EAAK,MAAA;KAEA,EAAA,MAAA;MACD,CAAA,EAAA,MAAA;QACC,CAAA,EAAA,OAAA;QACY,CAAA,EAAA,OAAK;UAC1B,CAAA,EAAA,OAAA;EAAO,SAAA,CAAA,EAAA,MAAA;;UA1vBA,wBAAA;;;;;;UAOA,mBAAA;;mBAES,qBAAqB,qBAAqB;;UAEnD;;;;;;;;;;iBAiDM,qCAAA,MACT,sBACJ;iBAorBmB,wBAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
@@ -1,12 +1,23 @@
1
- import { extractOverrides, flattenHeaders, generateToolCallId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, prepareOpenAIChatMisbehavior, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveOpenAIChatMisbehaviorUsage, resolveResponse, resolveStrictMode, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
1
+ import { renderError } from "./response/errors.js";
2
+ import { resolveRequestDecisions, strictOverrideField } from "./response/policy.js";
3
+ import { extractOverrides, flattenHeaders, generateToolCallId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, prepareOpenAIChatMisbehavior, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveOpenAIChatMisbehaviorUsage, resolveResponse, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage } from "./helpers.js";
2
4
  import { calculateDelay, delay, writeErrorResponse } from "./sse-writer.js";
3
5
  import { applyChaosAsync } from "./chaos.js";
4
6
  import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
5
7
  import { matchFixtureDiagnostic } from "./router.js";
6
8
  import { proxyAndRecord } from "./recorder.js";
7
9
  import { createInterruptionSignal } from "./interruption.js";
10
+ import { render } from "./response/usage/codecs/interactions.js";
8
11
 
9
12
  //#region src/gemini-interactions.ts
13
+ /**
14
+ * Google Gemini Interactions API support.
15
+ *
16
+ * Translates incoming Interactions requests into the ChatCompletionRequest
17
+ * format used by the fixture router, and converts fixture responses back
18
+ * into the Gemini Interactions format — either a single JSON response or
19
+ * an SSE stream with event_type-based framing.
20
+ */
10
21
  /** Step types whose payload is a tool/agent result keyed by call_id. */
11
22
  const STEP_RESULT_TYPES = new Set([
12
23
  "function_result",
@@ -185,18 +196,7 @@ function nextInteractionId() {
185
196
  return `aimock-int-${interactionCounter++}`;
186
197
  }
187
198
  function interactionsUsage(overrides) {
188
- if (!overrides?.usage) return {
189
- total_input_tokens: 0,
190
- total_output_tokens: 0,
191
- total_tokens: 0
192
- };
193
- const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? overrides.usage.promptTokenCount ?? 0;
194
- const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? overrides.usage.candidatesTokenCount ?? 0;
195
- return {
196
- total_input_tokens: input,
197
- total_output_tokens: output,
198
- total_tokens: overrides.usage.total_tokens ?? overrides.usage.totalTokenCount ?? input + output
199
- };
199
+ return render(overrides);
200
200
  }
201
201
  function buildInteractionsTextResponse(content, model, interactionId, overrides) {
202
202
  return {
@@ -277,12 +277,6 @@ function buildInteractionsContentWithToolCallsResponse(content, toolCalls, model
277
277
  usage: interactionsUsage(overrides)
278
278
  };
279
279
  }
280
- function buildInteractionsErrorResponse(message, code) {
281
- return { error: {
282
- code: code ?? "INVALID_ARGUMENT",
283
- message
284
- } };
285
- }
286
280
  let eventIdCounter = 0;
287
281
  function resetEventIdCounter() {
288
282
  eventIdCounter = 0;
@@ -570,7 +564,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
570
564
  fixture: null
571
565
  }
572
566
  });
573
- writeErrorResponse(res, 400, JSON.stringify(buildInteractionsErrorResponse(`Malformed JSON body: ${detail}`, "INVALID_ARGUMENT")));
567
+ writeErrorResponse(res, 400, renderError("interactions", "validation", {
568
+ message: `Malformed JSON body: ${detail}`,
569
+ code: "INVALID_ARGUMENT"
570
+ }).body);
574
571
  return;
575
572
  }
576
573
  if (!isJsonObject(interactionsReq)) {
@@ -584,7 +581,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
584
581
  fixture: null
585
582
  }
586
583
  });
587
- writeErrorResponse(res, 400, JSON.stringify(buildInteractionsErrorResponse("Request body must be a JSON object", "INVALID_ARGUMENT")));
584
+ writeErrorResponse(res, 400, renderError("interactions", "validation", {
585
+ message: "Request body must be a JSON object",
586
+ code: "INVALID_ARGUMENT"
587
+ }).body);
588
588
  return;
589
589
  }
590
590
  const validationError = validateInteractionsInput(interactionsReq.input) ?? validateInteractionsTools(interactionsReq.tools);
@@ -599,7 +599,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
599
599
  fixture: null
600
600
  }
601
601
  });
602
- writeErrorResponse(res, 400, JSON.stringify(buildInteractionsErrorResponse(validationError, "INVALID_ARGUMENT")));
602
+ writeErrorResponse(res, 400, renderError("interactions", "validation", {
603
+ message: validationError,
604
+ code: "INVALID_ARGUMENT"
605
+ }).body);
603
606
  return;
604
607
  }
605
608
  const completionReq = geminiInteractionsToCompletionRequest(interactionsReq);
@@ -617,7 +620,8 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
617
620
  body: completionReq
618
621
  }, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
619
622
  if (!fixture) {
620
- if (resolveStrictMode(defaults.strict, req.headers)) {
623
+ const decisions = resolveRequestDecisions(defaults.strict, req.headers);
624
+ if (decisions.fixtureMiss) {
621
625
  const strictStatus = 503;
622
626
  const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);
623
627
  logger.error(strictNoMatchLogLine(req.method ?? "POST", urlPath, skippedBySequenceOrTurn));
@@ -632,10 +636,13 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
632
636
  ...strictOverrideField(defaults.strict, req.headers)
633
637
  }
634
638
  });
635
- writeErrorResponse(res, strictStatus, JSON.stringify(buildInteractionsErrorResponse(strictMessage, "UNAVAILABLE")));
639
+ writeErrorResponse(res, strictStatus, renderError("interactions", "strict-miss", {
640
+ message: strictMessage,
641
+ code: "UNAVAILABLE"
642
+ }).body);
636
643
  return;
637
644
  }
638
- if (defaults.record) {
645
+ if (decisions.upstream && defaults.record) {
639
646
  const outcome = await proxyAndRecord(req, res, completionReq, "gemini-interactions", urlPath, fixtures, defaults, raw);
640
647
  if (outcome === "handled_by_hook") return;
641
648
  if (outcome !== "not_configured") {
@@ -664,7 +671,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
664
671
  ...strictOverrideField(defaults.strict, req.headers)
665
672
  }
666
673
  });
667
- writeErrorResponse(res, 404, JSON.stringify(buildInteractionsErrorResponse("No fixture matched", "NOT_FOUND")));
674
+ writeErrorResponse(res, 404, renderError("interactions", "fixture-miss", {
675
+ message: "No fixture matched",
676
+ code: "NOT_FOUND"
677
+ }).body);
668
678
  return;
669
679
  }
670
680
  let response = await resolveResponse(fixture, completionReq);
@@ -696,7 +706,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
696
706
  testId
697
707
  });
698
708
  if (!misbehavior.summary?.evaluations.some((evaluation) => evaluation.outcome === "error")) logger.error(`${req.method ?? "POST"} ${urlPath}: ${misbehavior.message}`);
699
- writeErrorResponse(res, misbehavior.status, JSON.stringify(buildInteractionsErrorResponse(misbehavior.message, misbehavior.code)));
709
+ writeErrorResponse(res, misbehavior.status, renderError("interactions", "misbehavior", {
710
+ message: misbehavior.message,
711
+ code: misbehavior.code
712
+ }).body);
700
713
  return;
701
714
  }
702
715
  if (misbehavior.kind === "applied") {
@@ -724,7 +737,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
724
737
  defaults,
725
738
  testId
726
739
  });
727
- writeErrorResponse(res, status, JSON.stringify(buildInteractionsErrorResponse(response.error.message, response.error.type ?? "ERROR")), { retryAfter: response.retryAfter });
740
+ writeErrorResponse(res, status, renderError("interactions", "fixture", {
741
+ message: response.error.message,
742
+ code: response.error.type ?? "ERROR"
743
+ }).body, { retryAfter: response.retryAfter });
728
744
  return;
729
745
  }
730
746
  if (misbehavior.kind === "applied" && misbehavior.summary.fault === "reasoning-only") {
@@ -745,11 +761,7 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
745
761
  testId
746
762
  });
747
763
  const interactionId = nextInteractionId();
748
- const usage = {
749
- ...interactionsUsage({ usage: appliedUsage }),
750
- total_output_tokens: 0,
751
- total_thought_tokens: appliedUsage?.completion_tokens ?? 0
752
- };
764
+ const usage = render({ usage: appliedUsage }, "applied-reasoning-only");
753
765
  if (!streaming) {
754
766
  const overrides = isTextResponse(response) || isToolCallResponse(response) || isCombinedFixtureResponse(response) ? extractOverrides(response) : void 0;
755
767
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -991,7 +1003,10 @@ async function handleGeminiInteractions(req, res, raw, fixtures, journal, defaul
991
1003
  defaults,
992
1004
  testId
993
1005
  });
994
- writeErrorResponse(res, 500, JSON.stringify(buildInteractionsErrorResponse("Fixture response did not match any known type", "INTERNAL")));
1006
+ writeErrorResponse(res, 500, renderError("interactions", "unknown-response", {
1007
+ message: "Fixture response did not match any known type",
1008
+ code: "INTERNAL"
1009
+ }).body);
995
1010
  }
996
1011
 
997
1012
  //#endregion