@copilotkit/aimock 1.43.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +46 -0
  4. package/README.md +14 -2
  5. package/dist/agui-handler.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +344 -43
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +345 -44
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +9 -5
  25. package/dist/chaos.cjs.map +1 -1
  26. package/dist/chaos.d.cts.map +1 -1
  27. package/dist/chaos.d.ts.map +1 -1
  28. package/dist/chaos.js +10 -7
  29. package/dist/chaos.js.map +1 -1
  30. package/dist/cli.cjs +238 -9
  31. package/dist/cli.cjs.map +1 -1
  32. package/dist/cli.js +242 -13
  33. package/dist/cli.js.map +1 -1
  34. package/dist/cohere.cjs +159 -72
  35. package/dist/cohere.cjs.map +1 -1
  36. package/dist/cohere.d.cts.map +1 -1
  37. package/dist/cohere.d.ts.map +1 -1
  38. package/dist/cohere.js +160 -73
  39. package/dist/cohere.js.map +1 -1
  40. package/dist/config-loader.cjs +63 -5
  41. package/dist/config-loader.cjs.map +1 -1
  42. package/dist/config-loader.d.cts +37 -4
  43. package/dist/config-loader.d.cts.map +1 -1
  44. package/dist/config-loader.d.ts +37 -4
  45. package/dist/config-loader.d.ts.map +1 -1
  46. package/dist/config-loader.js +63 -5
  47. package/dist/config-loader.js.map +1 -1
  48. package/dist/constants.cjs +8 -0
  49. package/dist/constants.cjs.map +1 -1
  50. package/dist/constants.d.cts +6 -2
  51. package/dist/constants.d.ts +6 -2
  52. package/dist/constants.js +8 -1
  53. package/dist/constants.js.map +1 -1
  54. package/dist/echo-text.cjs +65 -0
  55. package/dist/echo-text.cjs.map +1 -0
  56. package/dist/echo-text.d.cts +22 -0
  57. package/dist/echo-text.d.cts.map +1 -0
  58. package/dist/echo-text.d.ts +22 -0
  59. package/dist/echo-text.d.ts.map +1 -0
  60. package/dist/echo-text.js +65 -0
  61. package/dist/echo-text.js.map +1 -0
  62. package/dist/embeddings.cjs +18 -1
  63. package/dist/embeddings.cjs.map +1 -1
  64. package/dist/embeddings.d.cts +1 -1
  65. package/dist/embeddings.d.cts.map +1 -1
  66. package/dist/embeddings.d.ts +1 -1
  67. package/dist/embeddings.d.ts.map +1 -1
  68. package/dist/embeddings.js +18 -1
  69. package/dist/embeddings.js.map +1 -1
  70. package/dist/fakes-plugin.cjs +131 -0
  71. package/dist/fakes-plugin.cjs.map +1 -0
  72. package/dist/fakes-plugin.d.cts +23 -0
  73. package/dist/fakes-plugin.d.cts.map +1 -0
  74. package/dist/fakes-plugin.d.ts +23 -0
  75. package/dist/fakes-plugin.d.ts.map +1 -0
  76. package/dist/fakes-plugin.js +127 -0
  77. package/dist/fakes-plugin.js.map +1 -0
  78. package/dist/files.cjs +9 -11
  79. package/dist/files.cjs.map +1 -1
  80. package/dist/files.d.cts.map +1 -1
  81. package/dist/files.d.ts.map +1 -1
  82. package/dist/files.js +10 -13
  83. package/dist/files.js.map +1 -1
  84. package/dist/fine-tuning.cjs +1 -19
  85. package/dist/fine-tuning.cjs.map +1 -1
  86. package/dist/fine-tuning.d.cts.map +1 -1
  87. package/dist/fine-tuning.d.ts.map +1 -1
  88. package/dist/fine-tuning.js +2 -20
  89. package/dist/fine-tuning.js.map +1 -1
  90. package/dist/fixture-loader-services.cjs +116 -0
  91. package/dist/fixture-loader-services.cjs.map +1 -0
  92. package/dist/fixture-loader-services.d.cts +48 -0
  93. package/dist/fixture-loader-services.d.cts.map +1 -0
  94. package/dist/fixture-loader-services.d.ts +48 -0
  95. package/dist/fixture-loader-services.d.ts.map +1 -0
  96. package/dist/fixture-loader-services.js +114 -0
  97. package/dist/fixture-loader-services.js.map +1 -0
  98. package/dist/fixture-loader.cjs +552 -29
  99. package/dist/fixture-loader.cjs.map +1 -1
  100. package/dist/fixture-loader.d.cts +140 -2
  101. package/dist/fixture-loader.d.cts.map +1 -1
  102. package/dist/fixture-loader.d.ts +140 -2
  103. package/dist/fixture-loader.d.ts.map +1 -1
  104. package/dist/fixture-loader.js +542 -31
  105. package/dist/fixture-loader.js.map +1 -1
  106. package/dist/gemini-embeddings.cjs +42 -2
  107. package/dist/gemini-embeddings.cjs.map +1 -1
  108. package/dist/gemini-embeddings.js +43 -3
  109. package/dist/gemini-embeddings.js.map +1 -1
  110. package/dist/gemini-interactions.cjs +288 -52
  111. package/dist/gemini-interactions.cjs.map +1 -1
  112. package/dist/gemini-interactions.d.cts.map +1 -1
  113. package/dist/gemini-interactions.d.ts.map +1 -1
  114. package/dist/gemini-interactions.js +289 -53
  115. package/dist/gemini-interactions.js.map +1 -1
  116. package/dist/gemini.cjs +234 -38
  117. package/dist/gemini.cjs.map +1 -1
  118. package/dist/gemini.d.cts.map +1 -1
  119. package/dist/gemini.d.ts.map +1 -1
  120. package/dist/gemini.js +235 -39
  121. package/dist/gemini.js.map +1 -1
  122. package/dist/helpers.cjs +1157 -12
  123. package/dist/helpers.cjs.map +1 -1
  124. package/dist/helpers.d.cts +85 -4
  125. package/dist/helpers.d.cts.map +1 -1
  126. package/dist/helpers.d.ts +85 -4
  127. package/dist/helpers.d.ts.map +1 -1
  128. package/dist/helpers.js +1113 -14
  129. package/dist/helpers.js.map +1 -1
  130. package/dist/images.cjs +3 -2
  131. package/dist/images.cjs.map +1 -1
  132. package/dist/images.js +3 -2
  133. package/dist/images.js.map +1 -1
  134. package/dist/index.cjs +39 -1
  135. package/dist/index.d.cts +11 -4
  136. package/dist/index.d.ts +11 -4
  137. package/dist/index.js +11 -4
  138. package/dist/jest.cjs +43 -14
  139. package/dist/jest.cjs.map +1 -1
  140. package/dist/jest.d.cts +47 -5
  141. package/dist/jest.d.cts.map +1 -1
  142. package/dist/jest.d.ts +47 -5
  143. package/dist/jest.d.ts.map +1 -1
  144. package/dist/jest.js +45 -16
  145. package/dist/jest.js.map +1 -1
  146. package/dist/journal.cjs +155 -13
  147. package/dist/journal.cjs.map +1 -1
  148. package/dist/journal.d.cts +54 -4
  149. package/dist/journal.d.cts.map +1 -1
  150. package/dist/journal.d.ts +54 -4
  151. package/dist/journal.d.ts.map +1 -1
  152. package/dist/journal.js +155 -13
  153. package/dist/journal.js.map +1 -1
  154. package/dist/live-sanitize.cjs +4 -32
  155. package/dist/live-sanitize.cjs.map +1 -1
  156. package/dist/live-sanitize.js +4 -32
  157. package/dist/live-sanitize.js.map +1 -1
  158. package/dist/llmock.cjs +204 -39
  159. package/dist/llmock.cjs.map +1 -1
  160. package/dist/llmock.d.cts +51 -1
  161. package/dist/llmock.d.cts.map +1 -1
  162. package/dist/llmock.d.ts +51 -1
  163. package/dist/llmock.d.ts.map +1 -1
  164. package/dist/llmock.js +206 -41
  165. package/dist/llmock.js.map +1 -1
  166. package/dist/mcp-fakes-mount.cjs +217 -0
  167. package/dist/mcp-fakes-mount.cjs.map +1 -0
  168. package/dist/mcp-fakes-mount.js +211 -0
  169. package/dist/mcp-fakes-mount.js.map +1 -0
  170. package/dist/mcp-fakes-report.cjs +111 -0
  171. package/dist/mcp-fakes-report.cjs.map +1 -0
  172. package/dist/mcp-fakes-report.d.cts +40 -0
  173. package/dist/mcp-fakes-report.d.cts.map +1 -0
  174. package/dist/mcp-fakes-report.d.ts +40 -0
  175. package/dist/mcp-fakes-report.d.ts.map +1 -0
  176. package/dist/mcp-fakes-report.js +107 -0
  177. package/dist/mcp-fakes-report.js.map +1 -0
  178. package/dist/mcp-fakes.cjs +1942 -0
  179. package/dist/mcp-fakes.cjs.map +1 -0
  180. package/dist/mcp-fakes.d.cts +504 -0
  181. package/dist/mcp-fakes.d.cts.map +1 -0
  182. package/dist/mcp-fakes.d.ts +504 -0
  183. package/dist/mcp-fakes.d.ts.map +1 -0
  184. package/dist/mcp-fakes.js +1937 -0
  185. package/dist/mcp-fakes.js.map +1 -0
  186. package/dist/mcp-handler.cjs +534 -27
  187. package/dist/mcp-handler.cjs.map +1 -1
  188. package/dist/mcp-handler.d.cts +49 -0
  189. package/dist/mcp-handler.d.cts.map +1 -0
  190. package/dist/mcp-handler.d.ts +49 -0
  191. package/dist/mcp-handler.d.ts.map +1 -0
  192. package/dist/mcp-handler.js +530 -28
  193. package/dist/mcp-handler.js.map +1 -1
  194. package/dist/mcp-mock.cjs +326 -47
  195. package/dist/mcp-mock.cjs.map +1 -1
  196. package/dist/mcp-mock.d.cts +97 -1
  197. package/dist/mcp-mock.d.cts.map +1 -1
  198. package/dist/mcp-mock.d.ts +97 -1
  199. package/dist/mcp-mock.d.ts.map +1 -1
  200. package/dist/mcp-mock.js +327 -48
  201. package/dist/mcp-mock.js.map +1 -1
  202. package/dist/mcp-recorder.cjs +1224 -0
  203. package/dist/mcp-recorder.cjs.map +1 -0
  204. package/dist/mcp-recorder.d.cts +108 -0
  205. package/dist/mcp-recorder.d.cts.map +1 -0
  206. package/dist/mcp-recorder.d.ts +108 -0
  207. package/dist/mcp-recorder.d.ts.map +1 -0
  208. package/dist/mcp-recorder.js +1215 -0
  209. package/dist/mcp-recorder.js.map +1 -0
  210. package/dist/mcp-stub.cjs +5 -1
  211. package/dist/mcp-stub.d.cts +3 -1
  212. package/dist/mcp-stub.d.ts +3 -1
  213. package/dist/mcp-stub.js +3 -1
  214. package/dist/mcp-types.d.cts +6 -0
  215. package/dist/mcp-types.d.ts +6 -0
  216. package/dist/message-text.cjs +192 -0
  217. package/dist/message-text.cjs.map +1 -0
  218. package/dist/message-text.d.cts +31 -0
  219. package/dist/message-text.d.cts.map +1 -0
  220. package/dist/message-text.d.ts +31 -0
  221. package/dist/message-text.d.ts.map +1 -0
  222. package/dist/message-text.js +184 -0
  223. package/dist/message-text.js.map +1 -0
  224. package/dist/messages.cjs +400 -56
  225. package/dist/messages.cjs.map +1 -1
  226. package/dist/messages.d.cts.map +1 -1
  227. package/dist/messages.d.ts.map +1 -1
  228. package/dist/messages.js +401 -58
  229. package/dist/messages.js.map +1 -1
  230. package/dist/metrics.cjs +46 -66
  231. package/dist/metrics.cjs.map +1 -1
  232. package/dist/metrics.d.cts +14 -6
  233. package/dist/metrics.d.cts.map +1 -1
  234. package/dist/metrics.d.ts +14 -6
  235. package/dist/metrics.d.ts.map +1 -1
  236. package/dist/metrics.js +32 -40
  237. package/dist/metrics.js.map +1 -1
  238. package/dist/misbehavior.cjs +1523 -0
  239. package/dist/misbehavior.cjs.map +1 -0
  240. package/dist/misbehavior.d.cts +43 -0
  241. package/dist/misbehavior.d.cts.map +1 -0
  242. package/dist/misbehavior.d.ts +43 -0
  243. package/dist/misbehavior.d.ts.map +1 -0
  244. package/dist/misbehavior.js +1511 -0
  245. package/dist/misbehavior.js.map +1 -0
  246. package/dist/ollama.cjs +315 -113
  247. package/dist/ollama.cjs.map +1 -1
  248. package/dist/ollama.d.cts.map +1 -1
  249. package/dist/ollama.d.ts.map +1 -1
  250. package/dist/ollama.js +316 -114
  251. package/dist/ollama.js.map +1 -1
  252. package/dist/openapi.cjs +3405 -0
  253. package/dist/openapi.cjs.map +1 -0
  254. package/dist/openapi.d.cts +30 -0
  255. package/dist/openapi.d.cts.map +1 -0
  256. package/dist/openapi.d.ts +30 -0
  257. package/dist/openapi.d.ts.map +1 -0
  258. package/dist/openapi.js +3404 -0
  259. package/dist/openapi.js.map +1 -0
  260. package/dist/openrouter-video.cjs +4 -4
  261. package/dist/openrouter-video.cjs.map +1 -1
  262. package/dist/openrouter-video.d.cts.map +1 -1
  263. package/dist/openrouter-video.d.ts.map +1 -1
  264. package/dist/openrouter-video.js +4 -4
  265. package/dist/openrouter-video.js.map +1 -1
  266. package/dist/record-sanitize.cjs +231 -0
  267. package/dist/record-sanitize.cjs.map +1 -0
  268. package/dist/record-sanitize.js +224 -0
  269. package/dist/record-sanitize.js.map +1 -0
  270. package/dist/recorder.cjs +115 -6
  271. package/dist/recorder.cjs.map +1 -1
  272. package/dist/recorder.d.cts +2 -1
  273. package/dist/recorder.d.cts.map +1 -1
  274. package/dist/recorder.d.ts +2 -1
  275. package/dist/recorder.d.ts.map +1 -1
  276. package/dist/recorder.js +116 -8
  277. package/dist/recorder.js.map +1 -1
  278. package/dist/responses.cjs +701 -166
  279. package/dist/responses.cjs.map +1 -1
  280. package/dist/responses.d.cts +5 -13
  281. package/dist/responses.d.cts.map +1 -1
  282. package/dist/responses.d.ts +5 -13
  283. package/dist/responses.d.ts.map +1 -1
  284. package/dist/responses.js +699 -169
  285. package/dist/responses.js.map +1 -1
  286. package/dist/route-registry.cjs +951 -0
  287. package/dist/route-registry.cjs.map +1 -0
  288. package/dist/route-registry.d.cts +33 -0
  289. package/dist/route-registry.d.cts.map +1 -0
  290. package/dist/route-registry.d.ts +33 -0
  291. package/dist/route-registry.d.ts.map +1 -0
  292. package/dist/route-registry.js +866 -0
  293. package/dist/route-registry.js.map +1 -0
  294. package/dist/router.cjs +24 -2
  295. package/dist/router.cjs.map +1 -1
  296. package/dist/router.d.cts.map +1 -1
  297. package/dist/router.d.ts.map +1 -1
  298. package/dist/router.js +25 -4
  299. package/dist/router.js.map +1 -1
  300. package/dist/server.cjs +1159 -264
  301. package/dist/server.cjs.map +1 -1
  302. package/dist/server.d.cts +4 -1
  303. package/dist/server.d.cts.map +1 -1
  304. package/dist/server.d.ts +4 -1
  305. package/dist/server.d.ts.map +1 -1
  306. package/dist/server.js +1067 -172
  307. package/dist/server.js.map +1 -1
  308. package/dist/speech.cjs +4 -2
  309. package/dist/speech.cjs.map +1 -1
  310. package/dist/speech.js +4 -2
  311. package/dist/speech.js.map +1 -1
  312. package/dist/stream-collapse.cjs +236 -34
  313. package/dist/stream-collapse.cjs.map +1 -1
  314. package/dist/stream-collapse.d.cts +39 -4
  315. package/dist/stream-collapse.d.cts.map +1 -1
  316. package/dist/stream-collapse.d.ts +39 -4
  317. package/dist/stream-collapse.d.ts.map +1 -1
  318. package/dist/stream-collapse.js +235 -35
  319. package/dist/stream-collapse.js.map +1 -1
  320. package/dist/suite.cjs +1 -1
  321. package/dist/suite.js +1 -1
  322. package/dist/transcription.cjs +2 -2
  323. package/dist/transcription.cjs.map +1 -1
  324. package/dist/transcription.d.cts.map +1 -1
  325. package/dist/transcription.d.ts.map +1 -1
  326. package/dist/transcription.js +2 -2
  327. package/dist/transcription.js.map +1 -1
  328. package/dist/types.cjs +18 -0
  329. package/dist/types.cjs.map +1 -0
  330. package/dist/types.d.cts +516 -5
  331. package/dist/types.d.cts.map +1 -1
  332. package/dist/types.d.ts +516 -5
  333. package/dist/types.d.ts.map +1 -1
  334. package/dist/types.js +17 -0
  335. package/dist/types.js.map +1 -0
  336. package/dist/validate-cli.cjs +123 -33
  337. package/dist/validate-cli.cjs.map +1 -1
  338. package/dist/validate-cli.js +125 -35
  339. package/dist/validate-cli.js.map +1 -1
  340. package/dist/vector-stores.cjs +1180 -0
  341. package/dist/vector-stores.cjs.map +1 -0
  342. package/dist/vector-stores.d.cts +106 -0
  343. package/dist/vector-stores.d.cts.map +1 -0
  344. package/dist/vector-stores.d.ts +106 -0
  345. package/dist/vector-stores.d.ts.map +1 -0
  346. package/dist/vector-stores.js +1164 -0
  347. package/dist/vector-stores.js.map +1 -0
  348. package/dist/vector-types.d.cts.map +1 -1
  349. package/dist/version.cjs +45 -0
  350. package/dist/version.cjs.map +1 -0
  351. package/dist/version.js +44 -0
  352. package/dist/version.js.map +1 -0
  353. package/dist/video.cjs +19 -0
  354. package/dist/video.cjs.map +1 -1
  355. package/dist/video.d.cts.map +1 -1
  356. package/dist/video.d.ts.map +1 -1
  357. package/dist/video.js +19 -0
  358. package/dist/video.js.map +1 -1
  359. package/dist/vitest.cjs +77 -16
  360. package/dist/vitest.cjs.map +1 -1
  361. package/dist/vitest.d.cts +38 -5
  362. package/dist/vitest.d.cts.map +1 -1
  363. package/dist/vitest.d.ts +38 -5
  364. package/dist/vitest.d.ts.map +1 -1
  365. package/dist/vitest.js +78 -17
  366. package/dist/vitest.js.map +1 -1
  367. package/dist/watcher.cjs +6 -2
  368. package/dist/watcher.cjs.map +1 -1
  369. package/dist/watcher.js +6 -2
  370. package/dist/watcher.js.map +1 -1
  371. package/dist/ws-gemini-live.cjs +210 -101
  372. package/dist/ws-gemini-live.cjs.map +1 -1
  373. package/dist/ws-gemini-live.d.cts +9 -3
  374. package/dist/ws-gemini-live.d.cts.map +1 -1
  375. package/dist/ws-gemini-live.d.ts +9 -3
  376. package/dist/ws-gemini-live.d.ts.map +1 -1
  377. package/dist/ws-gemini-live.js +211 -102
  378. package/dist/ws-gemini-live.js.map +1 -1
  379. package/dist/ws-realtime.cjs +175 -62
  380. package/dist/ws-realtime.cjs.map +1 -1
  381. package/dist/ws-realtime.d.cts +8 -3
  382. package/dist/ws-realtime.d.cts.map +1 -1
  383. package/dist/ws-realtime.d.ts +8 -3
  384. package/dist/ws-realtime.d.ts.map +1 -1
  385. package/dist/ws-realtime.js +176 -63
  386. package/dist/ws-realtime.js.map +1 -1
  387. package/dist/ws-responses.cjs +121 -16
  388. package/dist/ws-responses.cjs.map +1 -1
  389. package/dist/ws-responses.d.cts +8 -12
  390. package/dist/ws-responses.d.cts.map +1 -1
  391. package/dist/ws-responses.d.ts +8 -12
  392. package/dist/ws-responses.d.ts.map +1 -1
  393. package/dist/ws-responses.js +123 -18
  394. package/dist/ws-responses.js.map +1 -1
  395. package/package.json +13 -2
  396. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1,6 +1,7 @@
1
1
  import { DEFAULT_TEST_ID } from "./constants.js";
2
- import { flattenHeaders, formatToMime, generateToolCallId, isAudioResponse, isContentWithToolCallsResponse, isErrorResponse, isTextResponse, isToolCallResponse, resolveFixtureBlocks, resolveResponse, resolveStrictMode, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
2
+ import { fixtureToolCallErrorCode, flattenHeaders, formatToMime, generateToolCallId, googleFixtureToolCallErrorDetails, isAudioResponse, isCombinedFixtureResponse, isErrorResponse, isFixtureToolCallError, isTextResponse, isToolCallResponse, journalFixtureToolCallError, rejectResponsesOnlyToolCalls, requireServedFunctionToolCalls, resolveFixtureBlockOutcome, resolveFixtureBlocks, resolveResponse, resolveStrictMode, runWithToolArgumentsScope, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField, strictToolArgumentsEnabled, toolArgsForWire } from "./helpers.js";
3
3
  import { calculateDelay, delay } from "./sse-writer.js";
4
+ import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
4
5
  import { matchFixtureDiagnostic } from "./router.js";
5
6
  import "./journal.js";
6
7
  import { createInterruptionSignal } from "./interruption.js";
@@ -102,10 +103,94 @@ function convertTools(geminiTools) {
102
103
  function: {
103
104
  name: d.name,
104
105
  description: d.description,
105
- parameters: d.parameters
106
+ parameters: d.parameters ?? d.parametersJsonSchema
106
107
  }
107
108
  }));
108
109
  }
110
+ function liveToolArguments(tc) {
111
+ return servedToolArgs(tc, "object").value;
112
+ }
113
+ const GEMINI_LIVE_WIRE = "Gemini Live";
114
+ /** Prepare native object arguments and IDs once for both output and the journal. */
115
+ function prepareLiveMisbehavior(plan) {
116
+ if (plan.summary.fault === "tool-args-invalid-json" || plan.summary.fault === "empty-response") return {
117
+ ...plan,
118
+ summary: {
119
+ ...plan.summary,
120
+ servedToolCalls: []
121
+ }
122
+ };
123
+ const response = plan.response;
124
+ const combined = isCombinedFixtureResponse(response);
125
+ const outcome = combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : void 0;
126
+ const calls = outcome?.toolCalls ?? (combined || isToolCallResponse(response) ? response.toolCalls ?? [] : []);
127
+ const duplicate = plan.duplicateId;
128
+ const toolCalls = calls.map((call, index) => {
129
+ const args = toolArgsForWire(call);
130
+ return {
131
+ ...call,
132
+ arguments: args.kind === "parsed" ? args.text : args.raw,
133
+ ...index === duplicate?.destinationIndex ? {} : { id: call.id ?? generateToolCallId() }
134
+ };
135
+ });
136
+ if (duplicate) toolCalls[duplicate.destinationIndex].id = toolCalls[duplicate.sourceIndex].id;
137
+ let preparedResponse = { ...response };
138
+ if ("usage" in preparedResponse) delete preparedResponse.usage;
139
+ if (outcome) {
140
+ let index = 0;
141
+ const blocks = outcome.ordered.map((block) => block.type === "text" ? { ...block } : {
142
+ ...block,
143
+ ...toolCalls[index++]
144
+ });
145
+ preparedResponse = {
146
+ ...preparedResponse,
147
+ content: outcome.content,
148
+ toolCalls,
149
+ blocks
150
+ };
151
+ } else if (combined || isToolCallResponse(response)) preparedResponse = {
152
+ ...preparedResponse,
153
+ toolCalls
154
+ };
155
+ return {
156
+ ...plan,
157
+ response: preparedResponse,
158
+ summary: {
159
+ ...plan.summary,
160
+ servedToolCalls: toolCalls.map(({ name, arguments: args, id }) => ({
161
+ name,
162
+ arguments: args,
163
+ id
164
+ }))
165
+ }
166
+ };
167
+ }
168
+ /**
169
+ * Validate the whole selected response before audio, text, or any tool is
170
+ * sent: every entry is validated, custom tool calls are rejected, and every
171
+ * argument string must parse. Returns the calls narrowed to function calls. On
172
+ * failure the journal entry becomes a 500, and the outer message handler sends
173
+ * code 13 with `google.rpc.ErrorInfo` details carrying the aimock code, drops
174
+ * this turn from the history, and leaves the socket open.
175
+ */
176
+ function preflightToolArguments(response, journalEntry) {
177
+ return journalFixtureToolCallError(journalEntry, () => {
178
+ const functionCalls = requireServedFunctionToolCalls(response, GEMINI_LIVE_WIRE);
179
+ if (strictToolArgumentsEnabled()) for (const tc of functionCalls) liveToolArguments(tc);
180
+ return functionCalls;
181
+ });
182
+ }
183
+ /** Resolve ordered blocks (rejecting custom tool calls) and preflight their arguments. */
184
+ function preflightBlocks(response, journalEntry) {
185
+ return journalFixtureToolCallError(journalEntry, () => {
186
+ rejectResponsesOnlyToolCalls(response, GEMINI_LIVE_WIRE);
187
+ const resolved = resolveFixtureBlocks(response.blocks ?? []);
188
+ if (strictToolArgumentsEnabled()) {
189
+ for (const block of resolved) if (block.type === "toolCall") liveToolArguments(block);
190
+ }
191
+ return resolved;
192
+ });
193
+ }
109
194
  function handleWebSocketGeminiLive(ws, fixtures, journal, defaults) {
110
195
  const { logger } = defaults;
111
196
  const session = {
@@ -116,19 +201,31 @@ function handleWebSocketGeminiLive(ws, fixtures, journal, defaults) {
116
201
  };
117
202
  let pending = Promise.resolve();
118
203
  ws.on("message", (raw) => {
119
- pending = pending.then(() => processMessage(raw, ws, fixtures, journal, defaults, session).catch((err) => {
120
- const msg = err instanceof Error ? err.message : "Internal error";
121
- logger.error(`WebSocket Gemini Live error: ${msg}`);
204
+ pending = pending.then(async () => {
205
+ const historyMark = session.conversationHistory.length;
122
206
  try {
123
- ws.send(JSON.stringify({ error: {
124
- code: 13,
125
- message: msg,
126
- status: "INTERNAL"
127
- } }));
128
- } catch (sendErr) {
129
- defaults.logger.debug(`Failed to send error to client: ${sendErr instanceof Error ? sendErr.message : "unknown"}`);
207
+ defaults.beforeProcessMessage?.();
208
+ await runWithToolArgumentsScope({
209
+ strict: defaults.strictToolArguments === true,
210
+ logger
211
+ }, () => processMessage(raw, ws, fixtures, journal, defaults, session));
212
+ } catch (err) {
213
+ const msg = err instanceof Error ? err.message : "Internal error";
214
+ logger.error(`WebSocket Gemini Live error: ${msg}`);
215
+ const fixtureToolCallError = isFixtureToolCallError(err);
216
+ if (fixtureToolCallError) session.conversationHistory.length = historyMark;
217
+ try {
218
+ ws.send(JSON.stringify({ error: {
219
+ code: 13,
220
+ message: msg,
221
+ status: "INTERNAL",
222
+ ...fixtureToolCallError ? { details: googleFixtureToolCallErrorDetails(fixtureToolCallErrorCode(err)) } : {}
223
+ } }));
224
+ } catch (sendErr) {
225
+ defaults.logger.debug(`Failed to send error to client: ${sendErr instanceof Error ? sendErr.message : "unknown"}`);
226
+ }
130
227
  }
131
- }));
228
+ });
132
229
  });
133
230
  }
134
231
  async function processMessage(raw, ws, fixtures, journal, defaults, session) {
@@ -240,12 +337,28 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
240
337
  return;
241
338
  }
242
339
  session.conversationHistory.push(...newMessages);
243
- const response = await resolveResponse(fixture, completionReq);
244
- const latency = fixture.latency ?? defaults.latency;
245
- const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
246
- if (isErrorResponse(response)) {
247
- const status = response.status ?? 500;
248
- journal.add({
340
+ let response = await resolveResponse(fixture, completionReq);
341
+ const plannerDefaults = {
342
+ ...defaults,
343
+ replaySpeed: defaults.replaySpeed ?? 1
344
+ };
345
+ let misbehavior = planMisbehavior({
346
+ wire: "gemini-live",
347
+ emitsToolCallIds: true,
348
+ fixture,
349
+ response,
350
+ request: completionReq,
351
+ stream: true,
352
+ defaults: plannerDefaults,
353
+ rawHeaders: defaults.upgradeHeaders ?? {},
354
+ url: `${path}?testId=${encodeURIComponent(testId)}`
355
+ });
356
+ if (misbehavior.kind === "applied") {
357
+ misbehavior = prepareLiveMisbehavior(misbehavior);
358
+ response = misbehavior.response;
359
+ }
360
+ const addResponseEntry = (status) => {
361
+ const entry = journal.add({
249
362
  method: "WS",
250
363
  path,
251
364
  headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
@@ -255,6 +368,68 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
255
368
  fixture
256
369
  }
257
370
  });
371
+ recordMisbehaviorOutcome({
372
+ entry,
373
+ summary: misbehavior.summary,
374
+ defaults: plannerDefaults,
375
+ testId
376
+ });
377
+ return entry;
378
+ };
379
+ if (misbehavior.kind === "error") {
380
+ addResponseEntry(misbehavior.status);
381
+ if (!misbehavior.summary?.evaluations.length) defaults.logger.error(`[misbehavior] ${misbehavior.message} (testId=${testId})`);
382
+ ws.send(JSON.stringify({ error: {
383
+ code: httpToGrpc(misbehavior.status),
384
+ message: misbehavior.message,
385
+ status: misbehavior.status === 400 ? "INVALID_ARGUMENT" : "UNIMPLEMENTED"
386
+ } }));
387
+ return;
388
+ }
389
+ const latency = fixture.latency ?? defaults.latency;
390
+ if (misbehavior.kind === "applied" && (misbehavior.summary.fault === "tool-args-invalid-json" || misbehavior.summary.fault === "empty-response")) {
391
+ const journalEntry = addResponseEntry(200);
392
+ const interruption = createInterruptionSignal(fixture);
393
+ const markInterrupted = () => {
394
+ journalEntry.response.interrupted = true;
395
+ journalEntry.response.interruptReason = interruption?.reason();
396
+ ws.destroy();
397
+ };
398
+ try {
399
+ if (ws.isClosed) return;
400
+ const chunkDelay = calculateDelay(0, void 0, latency, fixture.recordedTimings, fixture.replaySpeed ?? defaults.replaySpeed);
401
+ if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
402
+ if (interruption?.signal.aborted) {
403
+ markInterrupted();
404
+ return;
405
+ }
406
+ if (ws.isClosed) return;
407
+ const malformed = misbehavior.summary.fault === "tool-args-invalid-json";
408
+ ws.send(JSON.stringify({ serverContent: malformed ? {
409
+ turnComplete: true,
410
+ turnCompleteReason: "MALFORMED_FUNCTION_CALL"
411
+ } : { modelTurn: { parts: [{ text: "" }] } } }));
412
+ interruption?.tick();
413
+ if (interruption?.signal.aborted) {
414
+ markInterrupted();
415
+ return;
416
+ }
417
+ if (!malformed && !ws.isClosed) {
418
+ ws.send(JSON.stringify({ serverContent: { turnComplete: true } }));
419
+ session.conversationHistory.push({
420
+ role: "assistant",
421
+ content: ""
422
+ });
423
+ }
424
+ } finally {
425
+ interruption?.cleanup();
426
+ }
427
+ return;
428
+ }
429
+ const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
430
+ if (isErrorResponse(response)) {
431
+ const status = response.status ?? 500;
432
+ addResponseEntry(status);
258
433
  ws.send(JSON.stringify({ error: {
259
434
  code: httpToGrpc(status),
260
435
  message: response.error.message,
@@ -263,17 +438,9 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
263
438
  return;
264
439
  }
265
440
  if (isAudioResponse(response)) {
266
- journal.add({
267
- method: "WS",
268
- path,
269
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
270
- body: completionReq,
271
- response: {
272
- status: 200,
273
- fixture
274
- }
275
- });
441
+ const journalEntry = addResponseEntry(200);
276
442
  const audioResp = response;
443
+ const audioToolCalls = preflightToolArguments(audioResp, journalEntry);
277
444
  let mimeType;
278
445
  let data;
279
446
  if (typeof audioResp.audio === "string") {
@@ -288,7 +455,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
288
455
  data
289
456
  } }];
290
457
  if (audioResp.content) parts.push({ text: audioResp.content });
291
- const resolvedToolCalls = (audioResp.toolCalls ?? []).map((tc) => ({
458
+ const resolvedToolCalls = audioToolCalls.map((tc) => ({
292
459
  ...tc,
293
460
  resolvedId: tc.id ?? generateToolCallId()
294
461
  }));
@@ -300,13 +467,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
300
467
  ws.send(JSON.stringify({ serverContent: { modelTurn: { parts } } }));
301
468
  if (!ws.isClosed) {
302
469
  const functionCalls = resolvedToolCalls.map((tc) => {
303
- let argsObj;
304
- try {
305
- argsObj = JSON.parse(tc.arguments || "{}");
306
- } catch {
307
- defaults.logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
308
- argsObj = {};
309
- }
470
+ const argsObj = liveToolArguments(tc);
310
471
  return {
311
472
  name: tc.name,
312
473
  args: argsObj,
@@ -331,19 +492,10 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
331
492
  });
332
493
  return;
333
494
  }
334
- if (isContentWithToolCallsResponse(response)) {
335
- const journalEntry = journal.add({
336
- method: "WS",
337
- path,
338
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
339
- body: completionReq,
340
- response: {
341
- status: 200,
342
- fixture
343
- }
344
- });
495
+ if (isCombinedFixtureResponse(response)) {
496
+ const journalEntry = addResponseEntry(200);
345
497
  if (response.blocks && response.blocks.length > 0) {
346
- const resolvedBlocks = resolveFixtureBlocks(response.blocks);
498
+ const resolvedBlocks = preflightBlocks(response, journalEntry);
347
499
  const interruption = createInterruptionSignal(fixture);
348
500
  const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
349
501
  const { recordedTimings } = fixture;
@@ -361,13 +513,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
361
513
  }
362
514
  if (ws.isClosed) break;
363
515
  const resolvedId = block.id ?? generateToolCallId();
364
- let argsObj;
365
- try {
366
- argsObj = JSON.parse(block.arguments || "{}");
367
- } catch {
368
- defaults.logger.warn(`Malformed JSON in fixture tool call arguments for "${block.name}": ${block.arguments}`);
369
- argsObj = {};
370
- }
516
+ const argsObj = liveToolArguments(block);
371
517
  try {
372
518
  ws.send(JSON.stringify({ toolCall: { functionCalls: [{
373
519
  name: block.name,
@@ -435,6 +581,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
435
581
  });
436
582
  return;
437
583
  }
584
+ const functionToolCalls = preflightToolArguments(response, journalEntry);
438
585
  const content = response.content ?? "";
439
586
  const chunkList = [];
440
587
  for (let i = 0; i < content.length; i += chunkSize) chunkList.push(content.slice(i, i + chunkSize));
@@ -472,7 +619,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
472
619
  interruption?.cleanup();
473
620
  return;
474
621
  }
475
- const resolvedToolCalls = (response.toolCalls ?? []).map((tc) => ({
622
+ const resolvedToolCalls = functionToolCalls.map((tc) => ({
476
623
  ...tc,
477
624
  resolvedId: tc.id ?? generateToolCallId()
478
625
  }));
@@ -487,13 +634,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
487
634
  return;
488
635
  }
489
636
  const functionCalls = resolvedToolCalls.map((tc) => {
490
- let argsObj;
491
- try {
492
- argsObj = JSON.parse(tc.arguments || "{}");
493
- } catch {
494
- defaults.logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
495
- argsObj = {};
496
- }
637
+ const argsObj = liveToolArguments(tc);
497
638
  return {
498
639
  name: tc.name,
499
640
  args: argsObj,
@@ -527,16 +668,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
527
668
  return;
528
669
  }
529
670
  if (isTextResponse(response)) {
530
- const journalEntry = journal.add({
531
- method: "WS",
532
- path,
533
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
534
- body: completionReq,
535
- response: {
536
- status: 200,
537
- fixture
538
- }
539
- });
671
+ const journalEntry = addResponseEntry(200);
540
672
  const content = response.content;
541
673
  if (content.length === 0) {
542
674
  if (ws.isClosed) return;
@@ -587,16 +719,8 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
587
719
  return;
588
720
  }
589
721
  if (isToolCallResponse(response)) {
590
- const journalEntry = journal.add({
591
- method: "WS",
592
- path,
593
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
594
- body: completionReq,
595
- response: {
596
- status: 200,
597
- fixture
598
- }
599
- });
722
+ const journalEntry = addResponseEntry(200);
723
+ const functionToolCalls = preflightToolArguments(response, journalEntry);
600
724
  const interruption = createInterruptionSignal(fixture);
601
725
  const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
602
726
  const { recordedTimings } = fixture;
@@ -617,18 +741,12 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
617
741
  interruption?.cleanup();
618
742
  return;
619
743
  }
620
- const resolvedToolCalls = (response.toolCalls ?? []).map((tc) => ({
744
+ const resolvedToolCalls = functionToolCalls.map((tc) => ({
621
745
  ...tc,
622
746
  resolvedId: tc.id ?? generateToolCallId()
623
747
  }));
624
748
  const functionCalls = resolvedToolCalls.map((tc) => {
625
- let argsObj;
626
- try {
627
- argsObj = JSON.parse(tc.arguments || "{}");
628
- } catch {
629
- defaults.logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
630
- argsObj = {};
631
- }
749
+ const argsObj = liveToolArguments(tc);
632
750
  return {
633
751
  name: tc.name,
634
752
  args: argsObj,
@@ -660,16 +778,7 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
660
778
  });
661
779
  return;
662
780
  }
663
- journal.add({
664
- method: "WS",
665
- path,
666
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
667
- body: completionReq,
668
- response: {
669
- status: 500,
670
- fixture
671
- }
672
- });
781
+ addResponseEntry(500);
673
782
  ws.send(JSON.stringify({ error: {
674
783
  code: 13,
675
784
  message: "Fixture response did not match any known type",